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