00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "libts.h"
00031 #include "I_Net.h"
00032 #include "CongestionDB.h"
00033 #include "Congestion.h"
00034 #include "ControlMatcher.h"
00035 #include "ProxyConfig.h"
00036
00037 RecRawStatBlock *congest_rsb;
00038
00039 InkRand CongestionRand(123);
00040
00041 static const char *congestPrefix = "[CongestionControl]";
00042
00043 static const matcher_tags congest_dest_tags = {
00044 "dest_host",
00045 "dest_domain",
00046 "dest_ip",
00047 NULL,
00048 NULL,
00049 "host_regex",
00050 true
00051 };
00052
00053
00054
00055 char *DEFAULT_error_page = NULL;
00056 int DEFAULT_max_connection_failures = 5;
00057 int DEFAULT_fail_window = 120;
00058 int DEFAULT_proxy_retry_interval = 10;
00059 int DEFAULT_client_wait_interval = 300;
00060 int DEFAULT_wait_interval_alpha = 30;
00061 int DEFAULT_live_os_conn_timeout = 60;
00062 int DEFAULT_live_os_conn_retries = 2;
00063 int DEFAULT_dead_os_conn_timeout = 15;
00064 int DEFAULT_dead_os_conn_retries = 1;
00065 int DEFAULT_max_connection = -1;
00066 char *DEFAULT_congestion_scheme_str = NULL;
00067 int DEFAULT_congestion_scheme = PER_IP;
00068
00069
00070 #define CONG_RULE_MAX_max_connection_failures \
00071 (1<<(sizeof(cong_hist_t) * 8))
00072
00073 #define CONG_RULE_ULIMITED_max_connection_failures -1
00074 #define CONG_RULE_ULIMITED_mac_connection -1
00075
00076 struct CongestionMatcherTable :
00077 public ControlMatcher<CongestionControlRecord, CongestionControlRule>,
00078 public ConfigInfo
00079 {
00080 CongestionMatcherTable(const char * file_var, const char * name, const matcher_tags * tags)
00081 : ControlMatcher<CongestionControlRecord, CongestionControlRule>(file_var, name, tags) {
00082 }
00083
00084 static void reconfigure();
00085
00086 static int configid;
00087 };
00088
00089 int CongestionMatcherTable::configid = 0;
00090
00091 static CongestionMatcherTable *CongestionMatcher = NULL;
00092 static ConfigUpdateHandler<CongestionMatcherTable> * CongestionControlUpdate;
00093 int congestionControlEnabled = 0;
00094 int congestionControlLocalTime = 0;
00095
00096 CongestionControlRecord::CongestionControlRecord(const CongestionControlRecord & rec)
00097 {
00098 prefix = ats_strdup(rec.prefix);
00099 prefix_len = rec.prefix_len;
00100 port = rec.port;
00101 congestion_scheme = rec.congestion_scheme;
00102 error_page = ats_strdup(rec.error_page);
00103 max_connection_failures = rec.max_connection_failures;
00104 fail_window = rec.fail_window;
00105 proxy_retry_interval = rec.proxy_retry_interval;
00106 client_wait_interval = rec.client_wait_interval;
00107 wait_interval_alpha = rec.wait_interval_alpha;
00108 live_os_conn_timeout = rec.live_os_conn_timeout;
00109 live_os_conn_retries = rec.live_os_conn_retries;
00110 dead_os_conn_timeout = rec.dead_os_conn_timeout;
00111 dead_os_conn_retries = rec.dead_os_conn_retries;
00112 max_connection = rec.max_connection;
00113 pRecord = NULL;
00114 ref_count = 1;
00115 line_num = rec.line_num;
00116 rank = 0;
00117 }
00118
00119 void
00120 CongestionControlRecord::setdefault()
00121 {
00122 cleanup();
00123 congestion_scheme = DEFAULT_congestion_scheme;
00124 port = 0;
00125 prefix_len = 0;
00126 rank = 0;
00127 max_connection_failures = DEFAULT_max_connection_failures;
00128 fail_window = DEFAULT_fail_window;
00129 proxy_retry_interval = DEFAULT_proxy_retry_interval;
00130 client_wait_interval = DEFAULT_client_wait_interval;
00131 wait_interval_alpha = DEFAULT_wait_interval_alpha;
00132 live_os_conn_timeout = DEFAULT_live_os_conn_timeout;
00133 live_os_conn_retries = DEFAULT_live_os_conn_retries;
00134 dead_os_conn_timeout = DEFAULT_dead_os_conn_timeout;
00135 dead_os_conn_retries = DEFAULT_dead_os_conn_retries;
00136 max_connection = DEFAULT_max_connection;
00137 }
00138
00139 char *
00140 CongestionControlRecord::validate()
00141 {
00142 char *error_buf = NULL;
00143 int error_len = 1024;
00144
00145 #define IsGt0(var)\
00146 if ( var < 1 ) { \
00147 error_buf = (char*)ats_malloc(error_len); \
00148 snprintf(error_buf, error_len, "line %d: invalid %s = %d, %s must > 0", \
00149 line_num, #var, var, #var); \
00150 cleanup(); \
00151 return error_buf; \
00152 }
00153
00154 if (error_page == NULL)
00155 error_page = ats_strdup(DEFAULT_error_page);
00156 if (max_connection_failures >= CONG_RULE_MAX_max_connection_failures ||
00157 (max_connection_failures <= 0 && max_connection_failures != CONG_RULE_ULIMITED_max_connection_failures)
00158 ) {
00159 error_buf = (char *)ats_malloc(error_len);
00160 snprintf(error_buf, error_len, "line %d: invalid %s = %d not in [1, %d) range",
00161 line_num, "max_connection_failures", max_connection_failures, CONG_RULE_MAX_max_connection_failures);
00162 cleanup();
00163 return error_buf;
00164 }
00165
00166 IsGt0(fail_window);
00167 IsGt0(proxy_retry_interval);
00168 IsGt0(client_wait_interval);
00169 IsGt0(wait_interval_alpha);
00170 IsGt0(live_os_conn_timeout);
00171 IsGt0(live_os_conn_retries);
00172 IsGt0(dead_os_conn_timeout);
00173 IsGt0(dead_os_conn_retries);
00174
00175
00176
00177
00178 #undef IsGt0
00179 return error_buf;
00180 }
00181
00182 char *
00183 CongestionControlRecord::Init(matcher_line * line_info)
00184 {
00185 char *errBuf;
00186 const int errBufLen = 1024;
00187 const char *tmp;
00188 char *label;
00189 char *val;
00190 line_num = line_info->line_num;
00191
00192
00193 setdefault();
00194
00195 for (int i = 0; i < MATCHER_MAX_TOKENS; i++) {
00196 label = line_info->line[0][i];
00197 val = line_info->line[1][i];
00198
00199 if (label == NULL) {
00200 continue;
00201 }
00202 if (strcasecmp(label, "max_connection_failures") == 0) {
00203 max_connection_failures = atoi(val);
00204 } else if (strcasecmp(label, "fail_window") == 0) {
00205 fail_window = atoi(val);
00206 } else if (strcasecmp(label, "proxy_retry_interval") == 0) {
00207 proxy_retry_interval = atoi(val);
00208 } else if (strcasecmp(label, "client_wait_interval") == 0) {
00209 client_wait_interval = atoi(val);
00210 } else if (strcasecmp(label, "wait_interval_alpha") == 0) {
00211 wait_interval_alpha = atoi(val);
00212 } else if (strcasecmp(label, "live_os_conn_timeout") == 0) {
00213 live_os_conn_timeout = atoi(val);
00214 } else if (strcasecmp(label, "live_os_conn_retries") == 0) {
00215 live_os_conn_retries = atoi(val);
00216 } else if (strcasecmp(label, "dead_os_conn_timeout") == 0) {
00217 dead_os_conn_timeout = atoi(val);
00218 } else if (strcasecmp(label, "dead_os_conn_retries") == 0) {
00219 dead_os_conn_retries = atoi(val);
00220 } else if (strcasecmp(label, "max_connection") == 0) {
00221 max_connection = atoi(val);
00222 } else if (strcasecmp(label, "congestion_scheme") == 0) {
00223 if (!strcasecmp(val, "per_ip")) {
00224 congestion_scheme = PER_IP;
00225 } else if (!strcasecmp(val, "per_host")) {
00226 congestion_scheme = PER_HOST;
00227 } else {
00228 congestion_scheme = PER_IP;
00229 }
00230 } else if (strcasecmp(label, "error_page") == 0) {
00231 error_page = ats_strdup(val);
00232 } else if (strcasecmp(label, "prefix") == 0) {
00233 prefix = ats_strdup(val);
00234 prefix_len = strlen(prefix);
00235 rank += 1;
00236
00237 continue;
00238 } else if (strcasecmp(label, "port") == 0) {
00239 port = atoi(val);
00240 rank += 2;
00241
00242 continue;
00243 } else
00244 continue;
00245
00246 line_info->line[0][i] = NULL;
00247 line_info->num_el--;
00248 }
00249 if (line_info->num_el > 0) {
00250 tmp = ProcessModifiers(line_info);
00251
00252 if (tmp != NULL) {
00253 errBuf = (char *)ats_malloc(errBufLen * sizeof(char));
00254 snprintf(errBuf, errBufLen, "%s %s at line %d in congestion.config", congestPrefix, tmp, line_num);
00255 return errBuf;
00256 }
00257
00258 }
00259
00260 char *err_msg = validate();
00261 if (err_msg == NULL) {
00262 pRecord = new CongestionControlRecord(*this);
00263 }
00264 return err_msg;
00265 }
00266
00267 void
00268 CongestionControlRecord::UpdateMatch(CongestionControlRule * pRule, RequestData * rdata)
00269 {
00270
00271
00272
00273
00274
00275
00276
00277
00278 if (pRule->record == 0 ||
00279 pRule->record->rank < rank || (pRule->record->line_num > line_num && pRule->record->rank == rank)) {
00280 if (rank > 0) {
00281 if (rdata->data_type() == RequestData::RD_CONGEST_ENTRY) {
00282
00283 if (port != 0 && port != ((CongestionEntry *) rdata)->pRecord->port)
00284 return;
00285 if (prefix != NULL && ((CongestionEntry *) rdata)->pRecord->prefix == NULL)
00286 return;
00287 if (prefix != NULL && strncmp(prefix, ((CongestionEntry *) rdata)->pRecord->prefix, prefix_len))
00288 return;
00289 } else if (!this->CheckModifiers((HttpRequestData *) rdata)) {
00290 return;
00291 }
00292 }
00293 pRule->record = this;
00294 Debug("congestion_config", "Matched with record %p at line %d", this, line_num);
00295 }
00296 }
00297
00298 void
00299 CongestionControlRecord::Print()
00300 {
00301 #define PrintNUM(var) \
00302 Debug("congestion_config", "%30s = %d", #var, var);
00303 #define PrintSTR(var) \
00304 Debug("congestion_config", "%30s = %s", #var, (var == NULL? "NULL" : var));
00305
00306 PrintNUM(line_num);
00307 PrintSTR(prefix);
00308 PrintNUM(congestion_scheme);
00309 PrintSTR(error_page);
00310 PrintNUM(max_connection_failures);
00311 PrintNUM(fail_window);
00312 PrintNUM(proxy_retry_interval);
00313 PrintNUM(client_wait_interval);
00314 PrintNUM(wait_interval_alpha);
00315 PrintNUM(live_os_conn_timeout);
00316 PrintNUM(live_os_conn_retries);
00317 PrintNUM(dead_os_conn_timeout);
00318 PrintNUM(dead_os_conn_retries);
00319 PrintNUM(max_connection);
00320 #undef PrintNUM
00321 #undef PrintSTR
00322 }
00323
00324 extern void initCongestionDB();
00325
00326
00327 static int
00328 CongestionControlEnabledChanged(const char * , RecDataT ,
00329 RecData , void * )
00330 {
00331 if (congestionControlEnabled == 1 || congestionControlEnabled == 2) {
00332 revalidateCongestionDB();
00333 }
00334 return 0;
00335 }
00336
00337 static int
00338 CongestionControlDefaultSchemeChanged(const char * , RecDataT ,
00339 RecData , void * )
00340 {
00341 if (strcasecmp(DEFAULT_congestion_scheme_str, "per_host") == 0) {
00342 DEFAULT_congestion_scheme = PER_HOST;
00343 } else {
00344 DEFAULT_congestion_scheme = PER_IP;
00345 }
00346 return 0;
00347 }
00348
00349
00350
00351
00352
00353 extern void init_CongestionRegressionTest();
00354
00355 void
00356 initCongestionControl()
00357 {
00358
00359 #if TS_HAS_TESTS
00360 init_CongestionRegressionTest();
00361 #endif
00362 ink_assert(CongestionMatcher == NULL);
00363
00364 register_congest_stats();
00365
00366 CongestionControlUpdate = new ConfigUpdateHandler<CongestionMatcherTable>();
00367
00368
00369 REC_EstablishStaticConfigInt32(congestionControlEnabled, "proxy.config.http.congestion_control.enabled");
00370 REC_EstablishStaticConfigInt32(DEFAULT_max_connection_failures, "proxy.config.http.congestion_control.default.max_connection_failures");
00371 REC_EstablishStaticConfigInt32(DEFAULT_fail_window, "proxy.config.http.congestion_control.default.fail_window");
00372 REC_EstablishStaticConfigInt32(DEFAULT_proxy_retry_interval, "proxy.config.http.congestion_control.default.proxy_retry_interval");
00373 REC_EstablishStaticConfigInt32(DEFAULT_client_wait_interval, "proxy.config.http.congestion_control.default.client_wait_interval");
00374 REC_EstablishStaticConfigInt32(DEFAULT_wait_interval_alpha, "proxy.config.http.congestion_control.default.wait_interval_alpha");
00375 REC_EstablishStaticConfigInt32(DEFAULT_live_os_conn_timeout, "proxy.config.http.congestion_control.default.live_os_conn_timeout");
00376 REC_EstablishStaticConfigInt32(DEFAULT_live_os_conn_retries, "proxy.config.http.congestion_control.default.live_os_conn_retries");
00377 REC_EstablishStaticConfigInt32(DEFAULT_dead_os_conn_timeout, "proxy.config.http.congestion_control.default.dead_os_conn_timeout");
00378 REC_EstablishStaticConfigInt32(DEFAULT_dead_os_conn_retries, "proxy.config.http.congestion_control.default.dead_os_conn_retries");
00379 REC_EstablishStaticConfigInt32(DEFAULT_max_connection, "proxy.config.http.congestion_control.default.max_connection");
00380 REC_EstablishStaticConfigStringAlloc(DEFAULT_congestion_scheme_str, "proxy.config.http.congestion_control.default.congestion_scheme");
00381 REC_EstablishStaticConfigStringAlloc(DEFAULT_error_page, "proxy.config.http.congestion_control.default.error_page");
00382 REC_EstablishStaticConfigInt32(congestionControlLocalTime, "proxy.config.http.congestion_control.localtime");
00383 {
00384 RecData recdata;
00385 recdata.rec_int = 0;
00386 CongestionControlDefaultSchemeChanged(NULL, RECD_NULL, recdata, NULL);
00387 }
00388
00389 if (congestionControlEnabled) {
00390 CongestionMatcherTable::reconfigure();
00391 } else {
00392 Debug("congestion_config", "congestion control disabled");
00393 }
00394
00395 RecRegisterConfigUpdateCb("proxy.config.http.congestion_control.default.congestion_scheme", &CongestionControlDefaultSchemeChanged, NULL);
00396 RecRegisterConfigUpdateCb("proxy.config.http.congestion_control.enabled", &CongestionControlEnabledChanged, NULL);
00397
00398 CongestionControlUpdate->attach("proxy.config.http.congestion_control.filename");
00399 }
00400
00401 void
00402 CongestionMatcherTable::reconfigure()
00403 {
00404 Note("congestion control config changed, reloading");
00405 CongestionMatcher = new CongestionMatcherTable("proxy.config.http.congestion_control.filename", congestPrefix, &congest_dest_tags);
00406
00407 #ifdef DEBUG_CONGESTION_MATCHER
00408 CongestionMatcher->Print();
00409 #endif
00410
00411 configid = configProcessor.set(configid, CongestionMatcher);
00412 if (congestionControlEnabled) {
00413 revalidateCongestionDB();
00414 }
00415 }
00416
00417 CongestionControlRecord *
00418 CongestionControlled(RequestData * rdata)
00419 {
00420 if (congestionControlEnabled) {
00421 CongestionControlRule result;
00422 CongestionMatcher->Match(rdata, &result);
00423 if (result.record) {
00424 return result.record->pRecord;
00425 }
00426 } else {
00427 return NULL;
00428 }
00429 return NULL;
00430 }
00431
00432 uint64_t
00433 make_key(char *hostname, sockaddr const* ip, CongestionControlRecord * record)
00434 {
00435 int host_len = 0;
00436 if (hostname) {
00437 host_len = strlen(hostname);
00438 }
00439 return make_key(hostname, host_len, ip, record);
00440 }
00441
00442 uint64_t
00443 make_key(char *hostname, int len, sockaddr const* ip, CongestionControlRecord * record)
00444 {
00445 INK_MD5 md5;
00446 INK_DIGEST_CTX ctx;
00447 ink_code_incr_md5_init(&ctx);
00448 if (record->congestion_scheme == PER_HOST && len > 0)
00449 ink_code_incr_md5_update(&ctx, hostname, len);
00450 else
00451 ink_code_incr_md5_update(&ctx, reinterpret_cast<char const*>(ats_ip_addr8_cast(ip)), ats_ip_addr_size(ip));
00452 if (record->port != 0) {
00453 unsigned short p = record->port;
00454 p = htons(p);
00455 ink_code_incr_md5_update(&ctx, (char *) &p, 2);
00456 }
00457 if (record->prefix != NULL) {
00458 ink_code_incr_md5_update(&ctx, record->prefix, record->prefix_len);
00459 }
00460 ink_code_incr_md5_final((char *) &md5, &ctx);
00461
00462 return md5.fold();
00463 }
00464
00465 uint64_t
00466 make_key(char *hostname, int len, sockaddr const* ip, char *prefix, int prelen, short port)
00467 {
00468
00469 INK_MD5 md5;
00470 INK_DIGEST_CTX ctx;
00471 ink_code_incr_md5_init(&ctx);
00472 if (hostname && len > 0)
00473 ink_code_incr_md5_update(&ctx, hostname, len);
00474 else
00475 ink_code_incr_md5_update(&ctx, reinterpret_cast<char const*>(ats_ip_addr8_cast(ip)), ats_ip_addr_size(ip));
00476 if (port != 0) {
00477 unsigned short p = port;
00478 p = htons(p);
00479 ink_code_incr_md5_update(&ctx, (char *) &p, 2);
00480 }
00481 if (prefix != NULL) {
00482 ink_code_incr_md5_update(&ctx, prefix, prelen);
00483 }
00484 ink_code_incr_md5_final((char *) &md5, &ctx);
00485
00486 return md5.fold();
00487 }
00488
00489
00490
00491
00492 void
00493 FailHistory::init(int window)
00494 {
00495 bin_len = (window + CONG_HIST_ENTRIES) / CONG_HIST_ENTRIES;
00496 if (bin_len <= 0)
00497 bin_len = 1;
00498 length = bin_len * CONG_HIST_ENTRIES;
00499 for (int i = 0; i < CONG_HIST_ENTRIES; i++) {
00500 bins[i] = 0;
00501 }
00502 last_event = 0;
00503 cur_index = 0;
00504 events = 0;
00505 start = 0;
00506 }
00507
00508 void
00509 FailHistory::init_event(long t, int n)
00510 {
00511 last_event = t;
00512 cur_index = 0;
00513 events = n;
00514 bins[0] = n;
00515 for (int i = 1; i < CONG_HIST_ENTRIES; i++) {
00516 bins[i] = 0;
00517 }
00518 start = (last_event + bin_len) - last_event % bin_len - length;
00519 }
00520
00521 int
00522 FailHistory::regist_event(long t, int n)
00523 {
00524 if (t < start)
00525 return events;
00526 if (t > last_event + length) {
00527 init_event(t, n);
00528 return events;
00529 }
00530 if (t < start + length) {
00531 bins[((t - start) / bin_len + 1 + cur_index) % CONG_HIST_ENTRIES] += n;
00532 } else {
00533 do {
00534 start += bin_len;
00535 cur_index++;
00536 if (cur_index == CONG_HIST_ENTRIES)
00537 cur_index = 0;
00538 events -= bins[cur_index];
00539 bins[cur_index] = 0;
00540 } while (start + length < t);
00541 bins[cur_index] = n;
00542 }
00543 events += n;
00544 if (last_event < t)
00545 last_event = t;
00546 return events;
00547 }
00548
00549
00550
00551
00552 CongestionEntry::CongestionEntry(const char *hostname, sockaddr const* ip, CongestionControlRecord * rule, uint64_t key)
00553 :m_key(key),
00554 m_last_congested(0),
00555 m_congested(0),
00556 m_stat_congested_conn_failures(0),
00557 m_M_congested(0), m_last_M_congested(0), m_num_connections(0), m_stat_congested_max_conn(0), m_ref_count(1)
00558 {
00559 memset(&m_ip, 0, sizeof(m_ip));
00560 if (ip != NULL) {
00561 ats_ip_copy(&m_ip.sa, ip);
00562 }
00563 m_hostname = ats_strdup(hostname);
00564 rule->get();
00565 pRecord = rule;
00566 clearFailHistory();
00567 m_hist_lock = new_ProxyMutex();
00568 }
00569
00570 void
00571 CongestionEntry::init(CongestionControlRecord * rule)
00572 {
00573 if (pRecord)
00574 pRecord->put();
00575 rule->get();
00576 pRecord = rule;
00577 clearFailHistory();
00578
00579
00580 if ((pRecord->max_connection > m_num_connections)
00581 && ink_atomic_swap(&m_M_congested, 0)) {
00582
00583 }
00584 }
00585
00586 bool
00587 CongestionEntry::validate()
00588 {
00589 CongestionControlRecord *p = CongestionControlled(this);
00590 if (p == NULL) {
00591 return false;
00592 }
00593
00594 uint64_t key = make_key(m_hostname,
00595 &m_ip.sa,
00596 p);
00597 if (key != m_key) {
00598 return false;
00599 }
00600 applyNewRule(p);
00601 return true;
00602 }
00603
00604 void
00605 CongestionEntry::applyNewRule(CongestionControlRecord * rule)
00606 {
00607 if (pRecord->fail_window != rule->fail_window) {
00608 init(rule);
00609 return;
00610 }
00611 int mcf = pRecord->max_connection_failures;
00612 pRecord->put();
00613 rule->get();
00614 pRecord = rule;
00615
00616 if (((pRecord->max_connection < 0)
00617 || (pRecord->max_connection > m_num_connections))
00618 && ink_atomic_swap(&m_M_congested, 0)) {
00619
00620 }
00621
00622 if (pRecord->max_connection_failures < 0) {
00623 if (ink_atomic_swap(&m_congested, 0)) {
00624
00625 }
00626 return;
00627 }
00628
00629 if (mcf < pRecord->max_connection_failures) {
00630 if (ink_atomic_swap(&m_congested, 0)) {
00631
00632 }
00633 } else if (mcf > pRecord->max_connection_failures && m_history.events >= pRecord->max_connection_failures) {
00634 if (!ink_atomic_swap(&m_congested, 1)) {
00635
00636 }
00637 }
00638 }
00639
00640 int
00641 CongestionEntry::sprint(char *buf, int buflen, int format)
00642 {
00643 char str_time[100] = " ";
00644 char addrbuf[INET6_ADDRSTRLEN];
00645 int len = 0;
00646 ink_hrtime timestamp = 0;
00647 char state;
00648 if (pRecord->max_connection >= 0 && m_num_connections >= pRecord->max_connection) {
00649 timestamp = ink_hrtime_to_sec(ink_get_hrtime());
00650 state = 'M';
00651 } else {
00652 timestamp = m_last_congested;
00653 state = (m_congested ? 'F' : ' ');
00654 }
00655 len += snprintf(buf + len, buflen - len, "%" PRId64 "|%d|%s|%s",
00656 timestamp,
00657 pRecord->line_num,
00658 (m_hostname ? m_hostname : " "), (ats_is_ip(&m_ip) ? ats_ip_ntop(&m_ip.sa, addrbuf, sizeof(addrbuf)) : " "));
00659
00660 len += snprintf(buf + len, buflen - len, "|%s|%s|%c",
00661 (pRecord->congestion_scheme == PER_IP ? "per_ip" : "per_host"),
00662 (pRecord->prefix ? pRecord->prefix : " "), state);
00663
00664 len += snprintf(buf + len, buflen - len, "|%d|%d", m_stat_congested_conn_failures, m_stat_congested_max_conn);
00665
00666 if (format > 0) {
00667 if (m_congested) {
00668 struct tm time;
00669 time_t seconds = m_last_congested;
00670 if (congestionControlLocalTime) {
00671 ink_localtime_r(&seconds, &time);
00672 } else {
00673 gmtime_r(&seconds, &time);
00674 }
00675 snprintf(str_time, sizeof(str_time), "%04d/%02d/%02d %02d:%02d:%02d",
00676 time.tm_year + 1900, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
00677 }
00678 len += snprintf(buf + len, buflen - len, "|%s", str_time);
00679
00680 if (format > 1) {
00681 len += snprintf(buf + len, buflen - len, "|%" PRIu64 "", m_key);
00682
00683 if (format > 2) {
00684 len += snprintf(buf + len, buflen - len, "|%ld", m_history.last_event);
00685
00686 if (format > 3) {
00687 len += snprintf(buf + len, buflen - len, "|%d|%d|%d", m_history.events, m_ref_count, m_num_connections);
00688 }
00689 }
00690 }
00691 }
00692 len += snprintf(buf + len, buflen - len, "\n");
00693 return len;
00694 }
00695
00696
00697
00698
00699
00700
00701 void
00702 CongestionEntry::failed_at(ink_hrtime t)
00703 {
00704 if (pRecord->max_connection_failures == -1)
00705 return;
00706
00707 long time = t;
00708 Debug("congestion_control", "failed_at: %ld", time);
00709 MUTEX_TRY_LOCK(lock, m_hist_lock, this_ethread());
00710 if (lock) {
00711 m_history.regist_event(time);
00712 if (!m_congested) {
00713 int32_t new_congested = compCongested();
00714
00715 if (new_congested && !ink_atomic_swap(&m_congested, 1)) {
00716 m_last_congested = m_history.last_event;
00717
00718 }
00719 }
00720 } else {
00721 Debug("congestion_control", "failure info lost due to lock contention(Entry: %p, Time: %ld)", (void *) this, time);
00722 }
00723 }
00724
00725 void
00726 CongestionEntry::go_alive()
00727 {
00728
00729 if (ink_atomic_swap(&m_congested, 0)) {
00730
00731 }
00732 }
00733
00734 #define SERVER_CONGESTED_SIG REC_SIGNAL_HTTP_CONGESTED_SERVER
00735 #define SERVER_ALLEVIATED_SIG REC_SIGNAL_HTTP_ALLEVIATED_SERVER