• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

Congestion.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /*****************************************************************************
00025  *
00026  *  Congestion.cc - Content and User Access Control
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 /* default congestion control values */
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 /* congestion control limits */
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   // max_connection_failures <= 0  no failure num control
00175   // max_connection == -1 no max_connection control
00176   // max_connection_failures <= 0 && max_connection == -1 no congestion control for the rule
00177   // max_connection == 0, no connection allow to the origin server for the rule
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   /* initialize the rule to defaults */
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       // prefix will be used in the ControlBase
00237       continue;
00238     } else if (strcasecmp(label, "port") == 0) {
00239       port = atoi(val);
00240       rank += 2;
00241       // port will be used in the ControlBase;
00242       continue;
00243     } else
00244       continue;
00245     // Consume the label/value pair we used
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  * Select the first matching rule specified in congestion.config
00272  * rank     Matches
00273  *   3       dest && prefix && port
00274  *   2       dest && port
00275  *   1       dest && prefix
00276  *   0       dest
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         // Enforce the same port and prefix
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 // place holder for congestion control enable config
00327 static int
00328 CongestionControlEnabledChanged(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00329                                 RecData /* data ATS_UNUSED */, void * /* cookie ATS_UNUSED */)
00330 {
00331   if (congestionControlEnabled == 1 || congestionControlEnabled == 2) {
00332     revalidateCongestionDB();
00333   }
00334   return 0;
00335 }
00336 
00337 static int
00338 CongestionControlDefaultSchemeChanged(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */,
00339                                       RecData /* data ATS_UNUSED */, void * /* cookie ATS_UNUSED */)
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 // hack for link the RegressionTest into the
00351 //  TS binary
00352 //-----------------------------------------------
00353 extern void init_CongestionRegressionTest();
00354 
00355 void
00356 initCongestionControl()
00357 {
00358   // TODO: This is very, very strange, we run the regression tests even on a normal startup??
00359 #if TS_HAS_TESTS
00360   init_CongestionRegressionTest();
00361 #endif
00362   ink_assert(CongestionMatcher == NULL);
00363 // register the stats variables
00364   register_congest_stats();
00365 
00366   CongestionControlUpdate = new ConfigUpdateHandler<CongestionMatcherTable>();
00367 
00368 // register config variables
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   /* if the hostname != NULL, use hostname, else, use ip */
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 // FailHistory Implementation
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 // CongestionEntry Implementation
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   // TODO: This used to signal via SNMP
00580   if ((pRecord->max_connection > m_num_connections)
00581       && ink_atomic_swap(&m_M_congested, 0)) {
00582     // action not congested?
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   // TODO: This used to signal via SNMP
00616   if (((pRecord->max_connection < 0)
00617        || (pRecord->max_connection > m_num_connections))
00618       && ink_atomic_swap(&m_M_congested, 0)) {
00619     // action not congested ?
00620   }
00621   // TODO: This used to signal via SNMP
00622   if (pRecord->max_connection_failures < 0) {
00623     if (ink_atomic_swap(&m_congested, 0)) {
00624       // action not congested ?
00625     }
00626     return;
00627   }
00628   // TODO: This used to signal via SNMP
00629   if (mcf < pRecord->max_connection_failures) {
00630     if (ink_atomic_swap(&m_congested, 0)) {
00631       // action not congested?
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       // action congested?
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 // When a connection failure happened, try to get the lock
00698 //  first and change register the event, if we can not get
00699 //  the lock, discard the event
00700 //-------------------------------------------------------------
00701 void
00702 CongestionEntry::failed_at(ink_hrtime t)
00703 {
00704   if (pRecord->max_connection_failures == -1)
00705     return;
00706   // long time = ink_hrtime_to_sec(t);
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       // TODO: This used to signal via SNMP
00715       if (new_congested && !ink_atomic_swap(&m_congested, 1)) {
00716         m_last_congested = m_history.last_event;
00717         // action congested ?
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   // TODO: This used to signal via SNMP
00729   if (ink_atomic_swap(&m_congested, 0)) {
00730     // Action not congested ?
00731   }
00732 }
00733 
00734 #define SERVER_CONGESTED_SIG  REC_SIGNAL_HTTP_CONGESTED_SERVER
00735 #define SERVER_ALLEVIATED_SIG REC_SIGNAL_HTTP_ALLEVIATED_SERVER

Generated by  doxygen 1.7.1