13 #define XRD_TRACE m_trace->
15 #include "INIReader.h"
24 #if defined(__linux__)
27 unsigned XrdThrottleManager::GetTimerListHash() {
28 int cpu = sched_getcpu();
32 return cpu % m_timer_list_size;
37 unsigned XrdThrottleManager::GetTimerListHash() {
44 XrdThrottleManager::TraceID =
"ThrottleManager";
49 m_interval_length_seconds(1.0),
50 m_bytes_per_second(-1),
52 m_concurrency_limit(-1),
53 m_last_round_allocation(100*1024),
56 m_loadshed_frequency(0)
59 std::fill(m_wake_order_0.begin(), m_wake_order_0.end(), -1);
60 std::fill(m_wake_order_1.begin(), m_wake_order_1.end(), -1);
84 if (!loadshed_host.empty() && loadshed_port > 0 && loadshed_freq > 0)
87 SetLoadShed(loadshed_host, loadshed_port, loadshed_freq);
92 if (!user_config_file.empty())
94 m_user_config_file = user_config_file;
97 m_log->
Emsg(
"ThrottleManager",
"Failed to load per-user configuration file", user_config_file.c_str());
105 TRACE(
DEBUG,
"Initializing the throttle manager.");
107 m_primary_bytes_shares.resize(m_max_users);
108 m_secondary_bytes_shares.resize(m_max_users);
109 m_primary_ops_shares.resize(m_max_users);
110 m_secondary_ops_shares.resize(m_max_users);
111 for (
auto & waiter : m_waiter_info) {
112 waiter.m_manager =
this;
116 for (
int i=0; i<m_max_users; i++)
118 m_primary_bytes_shares[i] = m_last_round_allocation;
119 m_secondary_bytes_shares[i] = 0;
120 m_primary_ops_shares[i] = 10;
121 m_secondary_ops_shares[i] = 0;
126 if ((rc =
XrdSysThread::Run(&tid, XrdThrottleManager::RecomputeBootstrap,
static_cast<void *
>(
this), 0,
"Buffer Manager throttle")))
127 m_log->
Emsg(
"ThrottleManager", rc,
"create throttle thread");
131 std::tuple<std::string, uint16_t>
135 return std::make_tuple(
"nobody", GetUid(
"nobody"));
142 if (client->
eaAPI && client->
eaAPI->
Get(
"token.subject", user)) {
143 if (client->
vorg) user = std::string(client->
vorg) +
":" + user;
144 }
else if (client->
eaAPI) {
145 std::string request_name;
146 if (client->
eaAPI->
Get(
"request.name", request_name) && !request_name.empty()) user = request_name;
148 if (user.empty()) {user = client->
name ? client->
name :
"nobody";}
149 uint16_t uid = GetUid(user.c_str());
150 return std::make_tuple(user, uid);
158 XrdThrottleManager::GetShares(
int &shares,
int &request)
164 request -= (remaining < request) ? remaining : request;
173 XrdThrottleManager::StealShares(
int uid,
int &reqsize,
int &reqops)
175 if (!reqsize && !reqops)
return;
176 TRACE(BANDWIDTH,
"Stealing shares to fill request of " << reqsize <<
" bytes");
177 TRACE(IOPS,
"Stealing shares to fill request of " << reqops <<
" ops.");
179 for (
int i=uid+1; i % m_max_users == uid; i++)
181 if (reqsize) GetShares(m_secondary_bytes_shares[i % m_max_users], reqsize);
182 if (reqops) GetShares(m_secondary_ops_shares[ i % m_max_users], reqops);
185 TRACE(BANDWIDTH,
"After stealing shares, " << reqsize <<
" of request bytes remain.");
186 TRACE(IOPS,
"After stealing shares, " << reqops <<
" of request ops remain.");
199 unsigned long effective_max_conn = user_max_conn < m_max_conns ? user_max_conn : m_max_conns;
201 if (m_max_open == 0 && effective_max_conn == 0)
return true;
203 const std::lock_guard<std::mutex> lock(m_file_mutex);
204 auto iter = m_file_counters.find(entity);
205 unsigned long cur_open_files = 0, cur_open_conns;
207 if (iter == m_file_counters.end()) {
208 m_file_counters[entity] = 1;
209 TRACE(FILES,
"User " << entity <<
" has opened their first file");
211 }
else if (iter->second < m_max_open) {
213 cur_open_files = iter->second;
215 std::stringstream ss;
216 ss <<
"User " << entity <<
" has hit the limit of " << m_max_open <<
" open files";
217 TRACE(FILES, ss.str());
218 error_message = ss.str();
223 if (effective_max_conn > 0) {
225 auto conn_iter = m_active_conns.find(entity);
226 auto conn_count_iter = m_conn_counters.find(entity);
227 if ((conn_count_iter != m_conn_counters.end()) && (conn_count_iter->second == effective_max_conn) &&
228 (conn_iter == m_active_conns.end() || ((*(conn_iter->second))[pid] == 0)))
231 if (m_max_open) iter->second--;
232 std::stringstream ss;
233 ss <<
"User " << entity <<
" has hit the limit of " << effective_max_conn <<
235 if (user_max_conn > 0) {
236 ss <<
" (per-user limit)";
238 TRACE(CONNS, ss.str());
239 error_message = ss.str();
242 if (conn_iter == m_active_conns.end()) {
243 std::unique_ptr<std::unordered_map<pid_t, unsigned long>> conn_map(
244 new std::unordered_map<pid_t, unsigned long>());
245 (*conn_map)[pid] = 1;
246 m_active_conns[entity] = std::move(conn_map);
247 if (conn_count_iter == m_conn_counters.end()) {
248 m_conn_counters[entity] = 1;
251 m_conn_counters[entity] ++;
252 cur_open_conns = m_conn_counters[entity];
255 auto pid_iter = conn_iter->second->find(pid);
256 if (pid_iter == conn_iter->second->end() || pid_iter->second == 0) {
257 (*(conn_iter->second))[pid] = 1;
258 conn_count_iter->second++;
259 cur_open_conns = conn_count_iter->second;
261 (*(conn_iter->second))[pid] ++;
262 cur_open_conns = conn_count_iter->second;
265 TRACE(CONNS,
"User " << entity <<
" has " << cur_open_conns <<
" open connections (limit: " << effective_max_conn <<
")");
267 if (m_max_open)
TRACE(FILES,
"User " << entity <<
" has " << cur_open_files <<
" open files");
281 if (m_max_open == 0 && m_max_conns == 0)
return true;
284 const std::lock_guard<std::mutex> lock(m_file_mutex);
286 auto iter = m_file_counters.find(entity);
287 if (iter == m_file_counters.end()) {
288 TRACE(FILES,
"WARNING: User " << entity <<
" closed a file but throttle plugin never saw an open file");
290 }
else if (iter->second == 0) {
291 TRACE(FILES,
"WARNING: User " << entity <<
" closed a file but throttle plugin thinks all files were already closed");
296 if (result)
TRACE(FILES,
"User " << entity <<
" closed a file; " << iter->second <<
302 auto conn_iter = m_active_conns.find(entity);
303 auto conn_count_iter = m_conn_counters.find(entity);
304 if (conn_iter == m_active_conns.end() || !(conn_iter->second)) {
305 TRACE(CONNS,
"WARNING: User " << entity <<
" closed a file on a connection we are not"
309 auto pid_iter = conn_iter->second->find(pid);
310 if (pid_iter == conn_iter->second->end()) {
311 TRACE(CONNS,
"WARNING: User " << entity <<
" closed a file on a connection we are not"
315 if (pid_iter->second == 0) {
316 TRACE(CONNS,
"WARNING: User " << entity <<
" closed a file on connection the throttle"
317 " plugin thinks was idle");
321 if (conn_count_iter == m_conn_counters.end()) {
322 TRACE(CONNS,
"WARNING: User " << entity <<
" closed a file but the throttle plugin never"
323 " observed an open file");
324 }
else if (pid_iter->second == 0) {
325 if (conn_count_iter->second == 0) {
326 TRACE(CONNS,
"WARNING: User " << entity <<
" had a connection go idle but the "
327 " throttle plugin already thought all connections were idle");
329 conn_count_iter->second--;
330 TRACE(CONNS,
"User " << entity <<
" had connection on thread " << pid <<
" go idle; "
331 << conn_count_iter->second <<
" active connections remain");
347 if (m_bytes_per_second < 0)
349 if (m_ops_per_second < 0)
351 while (reqsize || reqops)
355 GetShares(m_primary_bytes_shares[uid], reqsize);
358 TRACE(BANDWIDTH,
"Using secondary shares; request has " << reqsize <<
" bytes left.");
359 GetShares(m_secondary_bytes_shares[uid], reqsize);
360 TRACE(BANDWIDTH,
"Finished with secondary shares; request has " << reqsize <<
" bytes left.");
364 TRACE(BANDWIDTH,
"Filled byte shares out of primary; " << m_primary_bytes_shares[uid] <<
" left.");
366 GetShares(m_primary_ops_shares[uid], reqops);
369 GetShares(m_secondary_ops_shares[uid], reqops);
371 StealShares(uid, reqsize, reqops);
374 if (reqsize || reqops)
376 if (reqsize)
TRACE(BANDWIDTH,
"Sleeping to wait for throttle fairshare.");
377 if (reqops)
TRACE(IOPS,
"Sleeping to wait for throttle fairshare.");
378 m_compute_var.
Wait();
379 m_loadshed_limit_hit++;
386 XrdThrottleManager::UserIOAccounting()
388 std::chrono::steady_clock::duration::rep total_active_time = 0;
389 for (
size_t idx = 0; idx < m_timer_list.size(); idx++) {
390 auto &timerList = m_timer_list[idx];
391 std::unique_lock<std::mutex> lock(timerList.m_mutex);
392 auto timer = timerList.m_first;
394 auto next = timer->m_next;
395 auto uid = timer->m_owner;
396 auto &waiter = m_waiter_info[uid];
397 auto recent_duration = timer->Reset();
398 waiter.m_io_time += recent_duration.count();
400 total_active_time += recent_duration.count();
404 m_io_active_time += total_active_time;
408 XrdThrottleManager::ComputeWaiterOrder()
415 auto now = std::chrono::steady_clock::now();
416 auto elapsed = now - m_last_waiter_recompute_time;
417 m_last_waiter_recompute_time = now;
418 std::chrono::duration<double> elapsed_secs = elapsed;
425 auto alpha = 1 - std::exp(-1 * elapsed_secs.count() / 10.0);
427 std::vector<double> share;
428 share.resize(m_max_users);
429 size_t users_with_waiters = 0;
432 for (
int i = 0; i < m_max_users; i++)
434 auto &waiter = m_waiter_info[i];
435 auto io_duration_rep = waiter.m_io_time.exchange(std::chrono::steady_clock::duration(0).count());
436 std::chrono::steady_clock::duration io_duration = std::chrono::steady_clock::duration(io_duration_rep);
437 std::chrono::duration<double> io_duration_secs = io_duration;
438 auto prev_concurrency = io_duration_secs.count() / elapsed_secs.count();
439 float new_concurrency = waiter.m_concurrency;
441 new_concurrency = (1 - alpha) * new_concurrency + alpha * prev_concurrency;
442 waiter.m_concurrency = new_concurrency;
443 if (new_concurrency > 0) {
444 TRACE(
DEBUG,
"User " << i <<
" has concurrency of " << new_concurrency);
448 std::lock_guard<std::mutex> lock(waiter.m_mutex);
449 waiting = waiter.m_waiting;
453 share[i] = new_concurrency;
454 TRACE(
DEBUG,
"User " << i <<
" has concurrency of " << share[i] <<
" and is waiting for " << waiting);
460 users_with_waiters++;
467 auto fair_share =
static_cast<double>(m_concurrency_limit) /
static_cast<double>(users_with_waiters);
468 std::vector<uint16_t> waiter_order;
469 waiter_order.resize(m_max_users);
474 double shares_sum = 0;
475 for (
int idx = 0; idx < m_max_users; idx++)
478 shares_sum += fair_share / share[idx];
486 auto scale_factor = (
static_cast<double>(m_max_users) -
static_cast<double>(users_with_waiters)) / shares_sum;
488 for (
int uid = 0; uid < m_max_users; uid++) {
489 if (share[uid] > 0) {
490 auto shares =
static_cast<unsigned>(scale_factor * fair_share / share[uid]) + 1;
491 TRACE(
DEBUG,
"User " << uid <<
" has " << shares <<
" shares");
492 for (
unsigned idx = 0; idx < shares; idx++)
494 waiter_order[offset % m_max_users] = uid;
499 if (offset < m_max_users) {
500 for (
size_t idx = offset; idx < m_max_users; idx++) {
501 waiter_order[idx] = -1;
505 std::shuffle(waiter_order.begin(), waiter_order.end(), std::default_random_engine());
509 auto &waiter_order_to_modify = (m_wake_order_active == 0) ? m_wake_order_1 : m_wake_order_0;
510 std::copy(waiter_order.begin(), waiter_order.end(), waiter_order_to_modify.begin());
514 m_wake_order_active = (m_wake_order_active + 1) % 2;
521 if (users_with_waiters) {
522 m_waiting_users = users_with_waiters;
523 auto io_active = m_io_active.load(std::memory_order_acquire);
524 for (
size_t idx = io_active; idx < static_cast<size_t>(m_concurrency_limit); idx++) {
531 XrdThrottleManager::RecomputeBootstrap(
void *instance)
534 manager->Recompute();
539 XrdThrottleManager::Recompute()
546 if (m_max_open || m_max_conns) {
547 const std::lock_guard<std::mutex> lock(m_file_mutex);
548 for (
auto iter = m_active_conns.begin(); iter != m_active_conns.end();)
550 auto & conn_count = *iter;
551 if (!conn_count.second) {
552 iter = m_active_conns.erase(iter);
555 for (
auto iter2 = conn_count.second->begin(); iter2 != conn_count.second->end();) {
556 if (iter2->second == 0) {
557 iter2 = conn_count.second->erase(iter2);
562 if (!conn_count.second->size()) {
563 iter = m_active_conns.erase(iter);
568 for (
auto iter = m_conn_counters.begin(); iter != m_conn_counters.end();) {
570 iter = m_conn_counters.erase(iter);
575 for (
auto iter = m_file_counters.begin(); iter != m_file_counters.end();) {
577 iter = m_file_counters.erase(iter);
584 TRACE(
DEBUG,
"Recomputing fairshares for throttle.");
586 ComputeWaiterOrder();
587 TRACE(
DEBUG,
"Finished recomputing fairshares for throttle; sleeping for " << m_interval_length_seconds <<
" seconds.");
610 XrdThrottleManager::RecomputeInternal()
613 float intervals_per_second = 1.0/m_interval_length_seconds;
614 float total_bytes_shares = m_bytes_per_second / intervals_per_second;
615 float total_ops_shares = m_ops_per_second / intervals_per_second;
620 float active_users = 0;
622 for (
int i=0; i<m_max_users; i++)
624 int primary =
AtomicFAZ(m_primary_bytes_shares[i]);
625 if (primary != m_last_round_allocation)
629 m_secondary_bytes_shares[i] = primary;
630 primary =
AtomicFAZ(m_primary_ops_shares[i]);
632 m_secondary_ops_shares[i] = primary;
633 bytes_used += (primary < 0) ? m_last_round_allocation : (m_last_round_allocation-primary);
637 if (active_users == 0)
645 m_last_round_allocation =
static_cast<int>(total_bytes_shares / active_users);
646 int ops_shares =
static_cast<int>(total_ops_shares / active_users);
647 TRACE(BANDWIDTH,
"Round byte allocation " << m_last_round_allocation <<
" ; last round used " << bytes_used <<
".");
648 TRACE(IOPS,
"Round ops allocation " << ops_shares);
649 for (
int i=0; i<m_max_users; i++)
651 m_primary_bytes_shares[i] = m_last_round_allocation;
652 m_primary_ops_shares[i] = ops_shares;
658 int limit_hit = m_loadshed_limit_hit.
exchange(0);
659 TRACE(
DEBUG,
"Throttle limit hit " << limit_hit <<
" times during last interval.");
662 m_compute_var.
Lock();
663 m_stable_io_active = m_io_active.load(std::memory_order_acquire);
664 auto io_active = m_stable_io_active;
665 m_stable_io_total = m_io_total;
666 auto io_total = m_stable_io_total;
667 auto io_wait_rep = m_io_active_time.
exchange(std::chrono::steady_clock::duration(0).count());
668 m_stable_io_wait += std::chrono::steady_clock::duration(io_wait_rep);
672 auto io_wait_ms = std::chrono::duration_cast<std::chrono::milliseconds>(m_stable_io_wait).count();
673 TRACE(IOLOAD,
"Current IO counter is " << io_active <<
"; total IO active time is " << io_wait_ms <<
"ms.");
677 auto len = snprintf(buf, 128,
678 R
"({"event":"throttle_update","io_wait":%.4f,"io_active":%d,"io_total":%llu})",
679 static_cast<double>(io_wait_ms) / 1000.0, io_active,
static_cast<long long unsigned>(io_total));
680 auto suc = (len < 128) ? m_gstream->
Insert(buf, len + 1) :
false;
683 TRACE(IOLOAD,
"Failed g-stream insertion of throttle_update record (len=" << len <<
"): " << buf);
693 XrdThrottleManager::GetUid(
const std::string &username)
695 std::hash<std::string> hash_fn;
696 auto hash = hash_fn(username);
697 auto uid =
static_cast<uint16_t
>(hash % m_max_users);
698 TRACE(
DEBUG,
"Mapping user " << username <<
" to UID " << uid);
706 XrdThrottleManager::NotifyOne()
708 auto &wake_order = (m_wake_order_active == 0) ? m_wake_order_0 : m_wake_order_1;
710 for (
size_t idx = 0; idx < m_max_users; ++idx)
712 auto offset = m_waiter_offset.fetch_add(1, std::memory_order_acq_rel);
713 int16_t uid = wake_order[offset % m_max_users];
718 auto &waiter_info = m_waiter_info[uid];
719 std::unique_lock<std::mutex> lock(waiter_info.m_mutex);
720 if (waiter_info.m_waiting) {
721 waiter_info.NotifyOne(std::move(lock));
733 int cur_counter = m_io_active.fetch_add(1, std::memory_order_acq_rel);
736 while (m_concurrency_limit >= 0 && cur_counter >= m_concurrency_limit)
741 if (m_waiter_info[uid].m_concurrency < 1)
745 m_loadshed_limit_hit++;
746 m_io_active.fetch_sub(1, std::memory_order_acq_rel);
747 TRACE(
DEBUG,
"ThrottleManager (user=" << uid <<
"): IO concurrency limit hit; waiting for other IOs to finish.");
748 ok = m_waiter_info[uid].Wait();
750 TRACE(
DEBUG,
"ThrottleManager (user=" << uid <<
"): timed out waiting for other IOs to finish.");
753 cur_counter = m_io_active.fetch_add(1, std::memory_order_acq_rel);
766 m_io_active_time += event_duration.count();
767 auto old_active = m_io_active.fetch_sub(1, std::memory_order_acq_rel);
768 m_waiter_info[uid].m_io_time += event_duration.count();
769 if (old_active ==
static_cast<unsigned>(m_concurrency_limit))
774 unsigned waiting_users = m_waiting_users;
775 if (waiting_users == 0) waiting_users = 1;
776 if (m_waiter_info[uid].m_concurrency < m_concurrency_limit / waiting_users)
778 std::unique_lock<std::mutex> lock(m_waiter_info[uid].m_mutex);
779 if (m_waiter_info[uid].m_waiting > 0)
781 m_waiter_info[uid].NotifyOne(std::move(lock));
799 if (m_loadshed_port == 0)
803 if (m_loadshed_limit_hit == 0)
807 if (
static_cast<unsigned>(rand()) % 100 > m_loadshed_frequency)
821 if (m_loadshed_port == 0)
825 if (opaque && opaque[0])
829 if (env.
Get(
"throttle.shed") != 0)
834 lsOpaque +=
"&throttle.shed=1";
838 lsOpaque =
"throttle.shed=1";
845 host = m_loadshed_host;
848 port = m_loadshed_port;
852 XrdThrottleManager::Waiter::Wait()
854 auto timeout = std::chrono::steady_clock::now() + m_manager->m_max_wait_time;
856 std::unique_lock<std::mutex> lock(m_mutex);
858 m_cv.wait_until(lock, timeout,
859 [&] {
return m_manager->m_io_active.load(std::memory_order_acquire) <
static_cast<unsigned>(m_manager->m_concurrency_limit) || std::chrono::steady_clock::now() >= timeout; });
862 if (std::chrono::steady_clock::now() > timeout) {
886 INIReader reader(config_file);
887 if (reader.ParseError() < 0)
889 m_log->
Emsg(
"ThrottleManager", errno,
"Unable to open per-user configuration file", config_file.c_str());
892 else if (reader.ParseError() > 0)
894 std::stringstream ss;
895 ss <<
"Parse error on line " << reader.ParseError() <<
" of file " << config_file;
896 m_log->
Emsg(
"ThrottleManager", ss.str().c_str());
900 std::unordered_map<std::string, UserLimit> new_limits;
903 for (
const auto §ion : reader.Sections())
906 std::string name = reader.Get(section,
"name",
"");
909 m_log->
Say(
"ThrottleManager",
"Section", section.c_str(),
"missing 'name' parameter; skipping");
913 long max_conn = reader.GetInteger(section,
"maxconn", 0);
916 m_log->
Say(
"ThrottleManager",
"Section", section.c_str(),
"has invalid or missing 'maxconn' parameter; skipping");
921 limit.max_conn =
static_cast<unsigned long>(max_conn);
923 limit.is_wildcard = (name.find(
'*') != std::string::npos);
924 new_limits[name] = limit;
928 size_t num_entries = new_limits.size();
930 std::unique_lock<std::shared_mutex> lock(m_user_limits_mutex);
931 m_user_limits = std::move(new_limits);
934 m_log->
Say(
"ThrottleManager",
"Loaded", std::to_string(num_entries).c_str(),
"per-user limit entries from", config_file.c_str());
944 if (m_user_config_file.empty())
946 m_log->
Emsg(
"ThrottleManager",
"No per-user configuration file specified");
962 std::shared_lock lock(m_user_limits_mutex);
965 auto exact_iter = m_user_limits.find(username);
966 if (exact_iter != m_user_limits.end() && !exact_iter->second.is_wildcard)
968 return exact_iter->second.max_conn;
972 unsigned long best_match = 0;
973 size_t best_prefix_len = 0;
974 unsigned long catch_all_match = 0;
976 for (
const auto &entry : m_user_limits)
978 if (!entry.second.is_wildcard)
continue;
980 const std::string &pattern = entry.first;
985 catch_all_match = entry.second.max_conn;
989 size_t wildcard_pos = pattern.find(
'*');
990 if (wildcard_pos == std::string::npos)
continue;
993 std::string prefix = pattern.substr(0, wildcard_pos);
994 if (username.length() >= prefix.length() &&
995 username.substr(0, prefix.length()) == prefix)
998 if (prefix.length() > best_prefix_len)
1000 best_prefix_len = prefix.length();
1001 best_match = entry.second.max_conn;
1007 if (best_match > 0)
return best_match;
1011 return catch_all_match;
#define AtomicFSub(w, x, y)
char * Get(const char *varname)
XrdSecAttr * Get(const void *sigkey)
char * vorg
Entity's virtual organization(s)
XrdSecEntityAttr * eaAPI
non-const API to attributes
char * name
Entity's name.
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
void Say(const char *text1, const char *text2=0, const char *txt3=0, const char *text4=0, const char *text5=0, const char *txt6=0)
static int Run(pthread_t *, void *(*proc)(void *), void *arg, int opts=0, const char *desc=0)
static unsigned long Num(void)
static void Wait(int milliseconds)
T exchange(T v, std::memory_order mo=std::memory_order_relaxed) noexcept
void StopIOTimer(std::chrono::steady_clock::duration &event_duration, uint16_t uid)
void SetThrottles(float reqbyterate, float reqoprate, int concurrency, float interval_length)
void SetMaxOpen(unsigned long max_open)
void FromConfig(XrdThrottle::Configuration &config)
void Apply(int reqsize, int reqops, int uid)
std::tuple< std::string, uint16_t > GetUserInfo(const XrdSecEntity *client)
XrdThrottleTimer StartIOTimer(uint16_t uid, bool &ok)
void SetLoadShed(std::string &hostname, unsigned port, unsigned frequency)
friend class XrdThrottleTimer
void PrepLoadShed(const char *opaque, std::string &lsOpaque)
bool CheckLoadShed(const std::string &opaque)
int LoadUserLimits(const std::string &config_file)
void SetMaxWait(unsigned long max_wait)
unsigned long GetUserMaxConn(const std::string &username)
void SetMaxConns(unsigned long max_conns)
XrdThrottleManager(XrdSysError *lP, XrdOucTrace *tP)
void PerformLoadShed(const std::string &opaque, std::string &host, unsigned &port)
bool CloseFile(const std::string &entity)
bool OpenFile(const std::string &entity, std::string &open_error_message)
long long GetLoadshedPort() const
long long GetThrottleDataRate() const
long long GetMaxWait() const
long long GetMaxConn() const
long long GetThrottleConcurrency() const
long long GetMaxOpen() const
const std::string & GetLoadshedHost() const
long long GetLoadshedFreq() const
long long GetThrottleIOPSRate() const
long long GetThrottleRecomputeIntervalMS() const
int GetTraceLevels() const
const std::string & GetUserConfigFile() const
bool Insert(const char *data, int dlen)