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

CongestionTest.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  *  CongestionTest.cc - Regression Test of the congestion control module
00027  *
00028  *
00029  ****************************************************************************/
00030 #include "libts.h"
00031 #include <math.h>
00032 #include "Main.h"
00033 #include "CongestionDB.h"
00034 #include "Congestion.h"
00035 #include "Error.h"
00036 
00037 //-------------------------------------------------------------
00038 // Test the HashTable implementation
00039 //-------------------------------------------------------------
00040 /* all of the elements inserted into the HashTable should be in the
00041  * table and can be easily retrived
00042  * also exercise the resizing of the table
00043  */
00044 EXCLUSIVE_REGRESSION_TEST(Congestion_HashTable) (RegressionTest * t, int /* atype ATS_UNUSED */, int *pstatus)
00045 {
00046   MTHashTable<long, long>*htable = new MTHashTable<long, long>(4);
00047   // add elements to the table;
00048   long i, count = 1 * 1024 * 1024;
00049   rprintf(t, "adding data into the hash table .", count);
00050   for (i = 1; i <= count; i++) {
00051     htable->insert_entry(i, i);
00052     if (i % (count / 50) == 0)
00053       fprintf(stderr, ".");
00054   }
00055   fprintf(stderr, "done\n");
00056   rprintf(t, "%d data added into the hash table\n", count);
00057   rprintf(t, "verifying the content");
00058   for (i = 1; i <= count; i++) {
00059     long data = htable->lookup_entry(i);
00060     if (i % (count / 50) == 0)
00061       fprintf(stderr, ".");
00062     if (data != i) {
00063       rprintf(t, "verify content failed: key(%d) data(%d)\n", i, data);
00064       *pstatus = REGRESSION_TEST_FAILED;
00065       return;
00066     }
00067   }
00068   fprintf(stderr, "done\n");
00069   long removed_count = 0;
00070   // delete some data
00071   rprintf(t, "removing data.");
00072   for (i = 1; i < count / 2; i++) {
00073     htable->remove_entry(i * 2);
00074     if (i % (count / 50) == 0)
00075       fprintf(stderr, ".");
00076     removed_count++;
00077   }
00078   fprintf(stderr, "done\n");
00079 
00080   rprintf(t, "%d data entries are removed\n", removed_count);
00081   rprintf(t, "verify the content again");
00082   for (i = 1; i <= count; i++) {
00083     long data = htable->lookup_entry(i);
00084     if (i % 2 == 1 && data == 0) {
00085       rprintf(t, "verify content failed: key(%d) deleted\n", i);
00086       *pstatus = REGRESSION_TEST_FAILED;
00087       return;
00088     }
00089     if (data != 0 && data != i) {
00090       rprintf(t, "verify content failed: key(%d) data(%d)\n", i, data);
00091       *pstatus = REGRESSION_TEST_FAILED;
00092       return;
00093     }
00094     if (i % (count / 50) == 0)
00095       fprintf(stderr, ".");
00096   }
00097   fprintf(stderr, "done\n");
00098 
00099   rprintf(t, "use iterator to list all the elements and delete half of them");
00100   HashTableIteratorState<long, long>it;
00101   int j, new_count = 0;
00102   for (j = 0; j < MT_HASHTABLE_PARTITIONS; j++) {
00103     int data = htable->first_entry(j, &it);
00104     while (data > 0) {
00105       new_count++;
00106       if (new_count % (count / 25) == 0)
00107         fprintf(stderr, ".");
00108 
00109       if (new_count % 2 == 0) {
00110         htable->remove_entry(j, &it);
00111         data = htable->cur_entry(j, &it);
00112         removed_count++;
00113       } else
00114         data = htable->next_entry(j, &it);
00115     }
00116   }
00117   fprintf(stderr, "done\n");
00118 
00119   rprintf(t, "verify the content once again");
00120   new_count = count - removed_count;
00121   for (j = 0; j < MT_HASHTABLE_PARTITIONS; j++) {
00122     int data = htable->first_entry(j, &it);
00123     while (data > 0) {
00124       new_count--;
00125       if (new_count % (count / 25) == 0)
00126         fprintf(stderr, ".");
00127       data = htable->next_entry(j, &it);
00128       if (data != htable->lookup_entry(data)) {
00129         rprintf(t, "verify content failed: key(%d) data(%d)\n", data, htable->lookup_entry(data));
00130         *pstatus = REGRESSION_TEST_FAILED;
00131         return;
00132       }
00133     }
00134   }
00135 
00136   fprintf(stderr, "done\n");
00137   if (new_count != 0) {
00138     rprintf(t, "there are %d extra entries in the table\n", new_count);
00139     *pstatus = REGRESSION_TEST_FAILED;
00140     return;
00141   }
00142 
00143   rprintf(t, "remove everything using iterator");
00144   new_count = count - removed_count;
00145   for (j = 0; j < MT_HASHTABLE_PARTITIONS; j++) {
00146     int data = htable->first_entry(j, &it);
00147     while (data > 0) {
00148       new_count--;
00149       if (new_count % (count / 25) == 0)
00150         fprintf(stderr, ".");
00151       htable->remove_entry(j, &it);
00152       data = htable->cur_entry(j, &it);
00153     }
00154   }
00155 
00156   fprintf(stderr, "done\n");
00157   if (new_count != 0) {
00158     rprintf(t, "there are %d extra entries in the table\n", new_count);
00159     *pstatus = REGRESSION_TEST_FAILED;
00160     return;
00161   }
00162 
00163   delete htable;
00164   *pstatus = REGRESSION_TEST_PASSED;
00165 }
00166 
00167 //-------------------------------------------------------------
00168 // Test the FailHistory implementation
00169 //-------------------------------------------------------------
00170 /* register events into the FailHistory and the number of events
00171  * should be correct
00172  */
00173 struct CCFailHistoryTestCont: public Continuation
00174 {
00175   enum
00176   { FAIL_WINDOW = 300 };
00177   enum
00178   {
00179     SIMPLE_TEST,
00180     MULTIPLE_THREAD_TEST,
00181     ROTATING_TEST
00182   };
00183   int test_mode;
00184   int final_status;
00185   bool complete;
00186   RegressionTest *test;
00187   int mainEvent(int event, Event * e);
00188     CCFailHistoryTestCont()
00189   : Continuation(new_ProxyMutex()),
00190     test_mode(SIMPLE_TEST), final_status(0), complete(false), failEvents(NULL), entry(NULL)
00191   {
00192   }
00193 
00194   CCFailHistoryTestCont(Ptr<ProxyMutex> _mutex, RegressionTest * _test)
00195   : Continuation(_mutex),
00196     test_mode(SIMPLE_TEST),
00197     final_status(REGRESSION_TEST_PASSED), complete(false), test(_test), failEvents(NULL), pending_action(NULL)
00198   {
00199     SET_HANDLER(&CCFailHistoryTestCont::mainEvent);
00200     rule = new CongestionControlRecord;
00201     rule->fail_window = FAIL_WINDOW;
00202     rule->max_connection_failures = 10;
00203     rule->pRecord = new CongestionControlRecord(*rule);
00204     entry = new CongestionEntry("dummy_host", 0, rule->pRecord, 0);
00205   }
00206 
00207   ~CCFailHistoryTestCont() {
00208     if (pending_action) {
00209       pending_action->cancel();
00210     }
00211     entry->put();
00212     delete rule;
00213     clear_events();
00214   }
00215 
00216   void init_events();
00217   void clear_events();
00218   int check_history(bool print);
00219   int schedule_event(int event, Event * e);
00220 
00221   struct FailEvents
00222   {
00223     time_t time;
00224       Link<FailEvents> link;
00225   };
00226   InkAtomicList *failEvents;
00227   CongestionControlRecord *rule;
00228   CongestionEntry *entry;
00229   Action *pending_action;
00230 
00231 };
00232 
00233 void
00234 CCFailHistoryTestCont::clear_events()
00235 {
00236   if (failEvents) {
00237     CCFailHistoryTestCont::FailEvents * events =
00238       (CCFailHistoryTestCont::FailEvents *) ink_atomiclist_popall(failEvents);
00239     while (events != NULL) {
00240       CCFailHistoryTestCont::FailEvents * next = events->link.next;
00241       delete events;
00242       events = next;
00243     }
00244     delete failEvents;
00245     failEvents = NULL;
00246   }
00247 }
00248 
00249 void
00250 CCFailHistoryTestCont::init_events()
00251 {
00252   clear_events();
00253 
00254   failEvents = new InkAtomicList;
00255   ink_atomiclist_init(failEvents, "failEvents", (uintptr_t) &((CCFailHistoryTestCont::FailEvents *) 0)->link);
00256 
00257   int i, j;
00258   CCFailHistoryTestCont::FailEvents * new_event = NULL;
00259 
00260   switch (test_mode) {
00261   case CCFailHistoryTestCont::ROTATING_TEST:
00262     for (i = 0; i < 16384; i++) {
00263       for (j = 0; j < 10; j++) {
00264         new_event = new CCFailHistoryTestCont::FailEvents;
00265         // coverity[secure_coding]
00266         new_event->time = rand() % (FAIL_WINDOW) + j * FAIL_WINDOW;
00267         ink_atomiclist_push(failEvents, new_event);
00268       }
00269     }
00270     break;
00271   case CCFailHistoryTestCont::SIMPLE_TEST:
00272   default:
00273     for (i = 0; i < 65536; i++) {
00274       new_event = new CCFailHistoryTestCont::FailEvents;
00275       // coverity[secure_coding]
00276       new_event->time = rand() % FAIL_WINDOW;
00277       ink_atomiclist_push(failEvents, new_event);
00278     }
00279   }
00280 }
00281 
00282 int
00283 CCFailHistoryTestCont::schedule_event(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00284 {
00285   if (failEvents == NULL)
00286     return EVENT_DONE;
00287   CCFailHistoryTestCont::FailEvents * f = (CCFailHistoryTestCont::FailEvents *) ink_atomiclist_pop(failEvents);
00288   if (f != NULL) {
00289     entry->failed_at(f->time);
00290     delete f;
00291     return EVENT_CONT;
00292   }
00293   return EVENT_DONE;
00294 }
00295 
00296 int
00297 CCFailHistoryTestCont::check_history(bool print)
00298 {
00299   if (print) {
00300     rprintf(test, "Verify the result\n");
00301     rprintf(test, "Content of history\n");
00302     int e = 0;
00303     for (int i = 0; i < CONG_HIST_ENTRIES; i++) {
00304       e += entry->m_history.bins[i];
00305       rprintf(test, "bucket %d => events %d , sum = %d\n", i, entry->m_history.bins[i], e);
00306     }
00307     fprintf(stderr, "Events: %d, CurIndex: %d, LastEvent: %ld, HistLen: %d, BinLen: %d, Start: %ld\n",
00308             entry->m_history.events,
00309             entry->m_history.cur_index,
00310             entry->m_history.last_event, entry->m_history.length, entry->m_history.bin_len, entry->m_history.start);
00311     char buf[1024];
00312     entry->sprint(buf, 1024, 10);
00313     rprintf(test, "%s", buf);
00314   }
00315   if (test_mode == CCFailHistoryTestCont::SIMPLE_TEST && entry->m_history.events == 65536)
00316     return 0;
00317   return 0;
00318 }
00319 
00320 int
00321 CCFailHistoryTestCont::mainEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00322 {
00323   test_mode = CCFailHistoryTestCont::SIMPLE_TEST;
00324   init_events();
00325   entry->init(rule->pRecord);
00326   while (schedule_event(0, NULL) == EVENT_CONT);
00327   if (check_history(true) == 0) {
00328     final_status = REGRESSION_TEST_PASSED;
00329   } else {
00330     final_status = REGRESSION_TEST_FAILED;
00331     goto Ldone;
00332   }
00333 
00334   test_mode = CCFailHistoryTestCont::ROTATING_TEST;
00335   init_events();
00336   entry->init(rule->pRecord);
00337   while (schedule_event(0, NULL) == EVENT_CONT);
00338   if (check_history(true) == 0) {
00339     final_status = REGRESSION_TEST_PASSED;
00340   } else {
00341     final_status = REGRESSION_TEST_FAILED;
00342     goto Ldone;
00343   }
00344 
00345 Ldone:
00346   complete = true;
00347   if (complete) {
00348     test->status = final_status;
00349     delete this;
00350     return EVENT_DONE;
00351   }
00352   return EVENT_CONT;
00353 }
00354 
00355 EXCLUSIVE_REGRESSION_TEST(Congestion_FailHistory) (RegressionTest * t, int /* atype ATS_UNUSED */, int *pstatus)
00356 {
00357   CCFailHistoryTestCont *test = new CCFailHistoryTestCont(make_ptr(new_ProxyMutex()), t);
00358   eventProcessor.schedule_in(test, HRTIME_SECONDS(1));
00359   *pstatus = REGRESSION_TEST_INPROGRESS;
00360 }
00361 
00362 //-------------------------------------------------------------
00363 // Test the CongestionDB implementation
00364 //-------------------------------------------------------------
00365 /* Insert simulated CongestionEntry into the CongestionDB and
00366  * exercise the GC of the DB, remove entries from DB
00367  */
00368 
00369 struct CCCongestionDBTestCont: public Continuation
00370 {
00371   int final_status;
00372   bool complete;
00373   RegressionTest *test;
00374 
00375   int mainEvent(int event, Event * e);
00376 
00377   void init();
00378   int get_congest_list();
00379   CongestionControlRecord *rule;
00380   CongestionDB *db;
00381   int dbsize;
00382   CongestionEntry *gen_CongestionEntry(sockaddr const* ip, int congested = 0);
00383 
00384 
00385     CCCongestionDBTestCont(Ptr<ProxyMutex> _mutex, RegressionTest * _test):Continuation(_mutex),
00386     final_status(REGRESSION_TEST_PASSED), complete(false), test(_test), rule(NULL), db(NULL), dbsize(1024)
00387   {
00388     SET_HANDLER(&CCCongestionDBTestCont::mainEvent);
00389   }
00390   virtual ~ CCCongestionDBTestCont()
00391   {
00392     if (db) {
00393       db->removeAllRecords();
00394       delete db;
00395     }
00396     if (rule)
00397       delete rule;
00398   }
00399 };
00400 
00401 CongestionEntry *
00402 CCCongestionDBTestCont::gen_CongestionEntry(sockaddr const* ip, int congested)
00403 {
00404   char hostname[INET6_ADDRSTRLEN];
00405   uint64_t key;
00406   ats_ip_ntop(ip, hostname, sizeof(hostname));
00407   key = make_key(hostname, strlen(hostname), ip, rule->pRecord);
00408   CongestionEntry *ret = new CongestionEntry(hostname,
00409                                              ip,
00410                                              rule->pRecord,
00411                                              key);
00412   ret->m_congested = congested;
00413   ret->m_ref_count = 0;
00414   return ret;
00415 }
00416 
00417 void
00418 CCCongestionDBTestCont::init()
00419 {
00420 // create/clear db
00421   if (!db)
00422     db = new CongestionDB(dbsize / MT_HASHTABLE_PARTITIONS);
00423   else
00424     db->removeAllRecords();
00425   if (!rule) {
00426     rule = new CongestionControlRecord;
00427     rule->fail_window = 300;
00428     rule->max_connection_failures = 10;
00429     rule->pRecord = new CongestionControlRecord(*rule);
00430   }
00431 
00432 }
00433 
00434 int
00435 CCCongestionDBTestCont::get_congest_list()
00436 {
00437   int cnt = 0;
00438   if (db == NULL)
00439     return 0;
00440   for (int i = 0; i < db->getSize(); i++) {
00441     db->RunTodoList(i);
00442     char buf[1024];
00443     Iter it;
00444 
00445     CongestionEntry *pEntry = db->first_entry(i, &it);
00446     while (pEntry) {
00447       cnt++;
00448       if (cnt % 100 == 0) {
00449         pEntry->sprint(buf, 1024, 100);
00450         fprintf(stderr, "%s", buf);
00451       }
00452       pEntry = db->next_entry(i, &it);
00453     }
00454   }
00455   return cnt;
00456 }
00457 
00458 int
00459 CCCongestionDBTestCont::mainEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
00460 {
00461   int to_add = 1 * 1024 * 1024;
00462   int i;
00463   int items[10] = { 0 };
00464   init();
00465   rprintf(test, "Add %d records into the db", dbsize);
00466 
00467   for (i = 0; i < dbsize; i++) {
00468     if (i % (dbsize / 25) == 0)
00469       fprintf(stderr, ".");
00470 
00471     IpEndpoint ip;
00472     ats_ip4_set(&ip, i + 255);
00473     
00474     CongestionEntry *tmp = gen_CongestionEntry(&ip.sa);
00475     db->addRecord(tmp->m_key, tmp);
00476   }
00477   fprintf(stderr, "done\n");
00478 
00479   items[0] = get_congest_list();
00480 
00481   db->removeAllRecords();
00482 
00483   rprintf(test, "There are %d records in the db\n", items[0]);
00484 
00485 
00486   rprintf(test, "Add %d records into the db", to_add);
00487   for (i = 0; i < to_add; i++) {
00488     if (i % (to_add / 25) == 0)
00489       fprintf(stderr, ".");
00490 
00491     IpEndpoint ip;
00492     ats_ip4_set(&ip, i + 255);
00493     CongestionEntry *tmp = gen_CongestionEntry(&ip.sa);
00494     db->addRecord(tmp->m_key, tmp);
00495   }
00496 
00497   items[1] = get_congest_list();
00498 
00499   db->removeAllRecords();
00500 
00501   rprintf(test, "There are %d records in the db\n", items[1]);
00502 
00503   rprintf(test, "Add %d congested records into the db", to_add);
00504 
00505   for (i = 0; i < to_add; i++) {
00506     if (i % (to_add / 25) == 0)
00507       fprintf(stderr, ".");
00508 
00509     IpEndpoint ip;
00510     ats_ip4_set(&ip, i + 255);
00511     
00512     CongestionEntry *tmp = gen_CongestionEntry(&ip.sa, 1);
00513     db->addRecord(tmp->m_key, tmp);
00514   }
00515   items[2] = get_congest_list();
00516   rprintf(test, "There are %d records in the db\n", items[2]);
00517 
00518   db->removeAllRecords();
00519 
00520   for (i = 0; i < 3; i++) {
00521     rprintf(test, "After test [%d] there are %d records in the db\n", i + 1, items[i]);
00522   }
00523 
00524   complete = true;
00525   if (complete) {
00526     test->status = final_status;
00527     delete this;
00528     return EVENT_DONE;
00529   }
00530   return EVENT_CONT;
00531 }
00532 
00533 EXCLUSIVE_REGRESSION_TEST(Congestion_CongestionDB) (RegressionTest * t, int /* atype ATS_UNUSED */, int *pstatus)
00534 {
00535   CCCongestionDBTestCont *test = new CCCongestionDBTestCont(make_ptr(new_ProxyMutex()), t);
00536   eventProcessor.schedule_in(test, HRTIME_SECONDS(1));
00537   *pstatus = REGRESSION_TEST_INPROGRESS;
00538 }
00539 
00540 //-------------------------------------------------------------
00541 // Test the CongestionControl implementation
00542 //-------------------------------------------------------------
00543 /* test the whole thing
00544  * 1. Match rules
00545  * 2. Apply new rules
00546  */
00547 void
00548 init_CongestionRegressionTest()
00549 {
00550   (void) regressionTest_Congestion_HashTable;
00551   (void) regressionTest_Congestion_FailHistory;
00552   (void) regressionTest_Congestion_CongestionDB;
00553 }

Generated by  doxygen 1.7.1