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 <math.h>
00032 #include "Main.h"
00033 #include "CongestionDB.h"
00034 #include "Congestion.h"
00035 #include "Error.h"
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 EXCLUSIVE_REGRESSION_TEST(Congestion_HashTable) (RegressionTest * t, int , int *pstatus)
00045 {
00046   MTHashTable<long, long>*htable = new MTHashTable<long, long>(4);
00047   
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   
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 
00169 
00170 
00171 
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         
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       
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 * )
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 * )
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 , 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 
00364 
00365 
00366 
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 
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 * )
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 , 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 
00542 
00543 
00544 
00545 
00546 
00547 void
00548 init_CongestionRegressionTest()
00549 {
00550   (void) regressionTest_Congestion_HashTable;
00551   (void) regressionTest_Congestion_FailHistory;
00552   (void) regressionTest_Congestion_CongestionDB;
00553 }