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
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #include <stdlib.h>
00044 #include <sys/types.h>
00045 #include <fcntl.h>
00046 #ifdef WIN32
00047 #include <windows.h>
00048 #include <io.h>
00049 #else
00050 #include <unistd.h>
00051 #include <sys/file.h>
00052 #endif
00053 #include <sys/stat.h>
00054
00055 #include <stdio.h>
00056 #include <limits.h>
00057 #include <ctype.h>
00058
00059 extern "C" {
00060 #include <otcl.h>
00061 }
00062 #include "pagepool.h"
00063 #include "http.h"
00064
00065
00066 int ClientPage::PUSHALL_ = 0;
00067
00068 void ServerPage::set_mtime(int *mt, int n)
00069 {
00070 if (mtime_ != NULL)
00071 delete []mtime_;
00072 mtime_ = new int[n];
00073 memcpy(mtime_, mt, sizeof(int)*n);
00074 }
00075
00076 ClientPage::ClientPage(const char *n, int s, double mt, double et, double a) :
00077 Page(s), age_(a), mtime_(mt), etime_(et),
00078 status_(HTTP_VALID_PAGE), counter_(0),
00079 mpushTime_(0)
00080 {
00081
00082 char *buf = new char[strlen(n) + 1];
00083 strcpy(buf, n);
00084 char *tmp = strtok(buf, ":");
00085 server_ = (HttpApp*)TclObject::lookup(tmp);
00086 if (server_ == NULL) {
00087 fprintf(stderr, "Non-exitent server name for page %s", n);
00088 abort();
00089 }
00090 tmp = strtok(NULL, ":");
00091 id_ = atol(tmp);
00092 delete []buf;
00093 }
00094
00095 void ClientPage::print_name(char* name, PageID& id)
00096 {
00097 sprintf(name, "%s:%-d", id.s_->name(), id.id_);
00098 }
00099
00100 void ClientPage::split_name(const char* name, PageID& id)
00101 {
00102 char *buf = new char[strlen(name)+1];
00103 strcpy(buf, name);
00104 char *tmp = strtok(buf, ":");
00105 id.s_ = (HttpApp*)TclObject::lookup(tmp);
00106 if (id.s_ == NULL) {
00107 fprintf(stderr, "Non-exitent server name for page %s\n", name);
00108 abort();
00109 }
00110 tmp = strtok(NULL, ":");
00111 id.id_ = atol(tmp);
00112 delete []buf;
00113 }
00114
00115 void ClientPage::print_info(char *buf)
00116 {
00117 sprintf(buf, "size %d modtime %.17g time %.17g age %.17g",
00118 size(), mtime(), etime(), age());
00119 if (is_uncacheable())
00120 strcat(buf, " noc 1");
00121 }
00122
00123 void ClientPage::name(char* buf)
00124 {
00125 sprintf(buf, "%s:%d", server_->name(), id());
00126 }
00127
00128
00129 static class PagePoolClass : public TclClass {
00130 public:
00131 PagePoolClass() : TclClass("PagePool") {}
00132 TclObject* create(int, const char*const*) {
00133 return (new PagePool());
00134 }
00135 } class_pagepool_agent;
00136
00137 int PagePool::command(int argc, const char*const* argv)
00138 {
00139 if (argc == 2) {
00140
00141 if (strcmp(argv[1], "set-allpush") == 0) {
00142 ClientPage::PUSHALL_ = 1;
00143 return (TCL_OK);
00144 }
00145 if (strcmp(argv[1], "set-selpush") == 0) {
00146 ClientPage::PUSHALL_ = 0;
00147 return (TCL_OK);
00148 }
00149 }
00150 return TclObject::command(argc, argv);
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164 static class TracePagePoolClass : public TclClass {
00165 public:
00166 TracePagePoolClass() : TclClass("PagePool/Trace") {}
00167 TclObject* create(int argc, const char*const* argv) {
00168 if (argc >= 5)
00169 return (new TracePagePool(argv[4]));
00170 return 0;
00171 }
00172 } class_tracepagepool_agent;
00173
00174 TracePagePool::TracePagePool(const char *fn) :
00175 PagePool(), ranvar_(0)
00176 {
00177 FILE *fp = fopen(fn, "r");
00178 if (fp == NULL) {
00179 fprintf(stderr,
00180 "TracePagePool: couldn't open trace file %s\n", fn);
00181 abort();
00182 }
00183
00184 namemap_ = new Tcl_HashTable;
00185 Tcl_InitHashTable(namemap_, TCL_STRING_KEYS);
00186 idmap_ = new Tcl_HashTable;
00187 Tcl_InitHashTable(idmap_, TCL_ONE_WORD_KEYS);
00188
00189 while (load_page(fp));
00190 change_time();
00191 }
00192
00193 TracePagePool::~TracePagePool()
00194 {
00195 if (namemap_ != NULL) {
00196 Tcl_DeleteHashTable(namemap_);
00197 delete namemap_;
00198 }
00199 if (idmap_ != NULL) {
00200 Tcl_DeleteHashTable(idmap_);
00201 delete idmap_;
00202 }
00203 }
00204
00205 void TracePagePool::change_time()
00206 {
00207 Tcl_HashEntry *he;
00208 Tcl_HashSearch hs;
00209 ServerPage *pg;
00210 int i, j;
00211
00212 for (i = 0, he = Tcl_FirstHashEntry(idmap_, &hs);
00213 he != NULL;
00214 he = Tcl_NextHashEntry(&hs), i++) {
00215 pg = (ServerPage *) Tcl_GetHashValue(he);
00216 for (j = 0; j < pg->num_mtime(); j++)
00217 pg->mtime(j) -= (int)start_time_;
00218 }
00219 end_time_ -= start_time_;
00220 start_time_ = 0;
00221 duration_ = (int)end_time_;
00222 }
00223
00224 ServerPage* TracePagePool::load_page(FILE *fp)
00225 {
00226 static char buf[TRACEPAGEPOOL_MAXBUF];
00227 char *delim = " \t\n";
00228 char *tmp1, *tmp2;
00229 ServerPage *pg;
00230
00231
00232 if (!fgets(buf, TRACEPAGEPOOL_MAXBUF, fp))
00233 return NULL;
00234
00235
00236 tmp1 = strtok(buf, delim);
00237
00238 tmp2 = strtok(NULL, delim);
00239 pg = new ServerPage(atoi(tmp2), num_pages_++);
00240
00241 if (add_page(tmp1, pg)) {
00242 delete pg;
00243 return NULL;
00244 }
00245
00246
00247 int num = 0;
00248 int *nmd = new int[5];
00249 while ((tmp1 = strtok(NULL, delim)) != NULL) {
00250 if (num >= 5) {
00251 int *tt = new int[num+5];
00252 memcpy(tt, nmd, sizeof(int)*num);
00253 delete []nmd;
00254 nmd = tt;
00255 }
00256 nmd[num] = atoi(tmp1);
00257 if (nmd[num] < start_time_)
00258 start_time_ = nmd[num];
00259 if (nmd[num] > end_time_)
00260 end_time_ = nmd[num];
00261 num++;
00262 }
00263 pg->num_mtime() = num;
00264 pg->set_mtime(nmd, num);
00265 delete []nmd;
00266 return pg;
00267 }
00268
00269 int TracePagePool::add_page(const char* name, ServerPage *pg)
00270 {
00271 int newEntry = 1;
00272 Tcl_HashEntry *he = Tcl_CreateHashEntry(namemap_,
00273 (const char *)name,
00274 &newEntry);
00275 if (he == NULL)
00276 return -1;
00277 if (newEntry)
00278 Tcl_SetHashValue(he, (ClientData)pg);
00279 else
00280 fprintf(stderr, "TracePagePool: Duplicate entry %s\n",
00281 name);
00282
00283 long key = pg->id();
00284 Tcl_HashEntry *hf =
00285 Tcl_CreateHashEntry(idmap_, (const char *)key, &newEntry);
00286 if (hf == NULL) {
00287 Tcl_DeleteHashEntry(he);
00288 return -1;
00289 }
00290 if (newEntry)
00291 Tcl_SetHashValue(hf, (ClientData)pg);
00292 else
00293 fprintf(stderr, "TracePagePool: Duplicate entry %d\n",
00294 pg->id());
00295
00296 return 0;
00297 }
00298
00299 ServerPage* TracePagePool::get_page(int id)
00300 {
00301 if ((id < 0) || (id >= num_pages_))
00302 return NULL;
00303 long key = id;
00304 Tcl_HashEntry *he = Tcl_FindHashEntry(idmap_, (const char *)key);
00305 if (he == NULL)
00306 return NULL;
00307 return (ServerPage *)Tcl_GetHashValue(he);
00308 }
00309
00310 int TracePagePool::command(int argc, const char *const* argv)
00311 {
00312 Tcl &tcl = Tcl::instance();
00313
00314 if (argc == 2) {
00315 if (strcmp(argv[1], "get-poolsize") == 0) {
00316
00317
00318
00319
00320 tcl.resultf("%d", num_pages_);
00321 return TCL_OK;
00322 } else if (strcmp(argv[1], "get-start-time") == 0) {
00323 tcl.resultf("%.17g", start_time_);
00324 return TCL_OK;
00325 } else if (strcmp(argv[1], "get-duration") == 0) {
00326 tcl.resultf("%d", duration_);
00327 return TCL_OK;
00328 }
00329 } else if (argc == 3) {
00330 if (strcmp(argv[1], "gen-pageid") == 0) {
00331
00332
00333
00334
00335 double tmp = ranvar_ ? ranvar_->value() :
00336 Random::uniform();
00337
00338 tmp = (tmp < 0) ? 0 : (tmp >= num_pages_) ?
00339 (num_pages_-1):tmp;
00340 if ((int)tmp >= num_pages_) abort();
00341 tcl.resultf("%d", (int)tmp);
00342 return TCL_OK;
00343 } else if (strcmp(argv[1], "gen-size") == 0) {
00344
00345
00346
00347 int id = atoi(argv[2]);
00348 ServerPage *pg = get_page(id);
00349 if (pg == NULL) {
00350 tcl.add_errorf("TracePagePool %s: page %d doesn't exists.\n",
00351 name_, id);
00352 return TCL_ERROR;
00353 }
00354 tcl.resultf("%d", pg->size());
00355 return TCL_OK;
00356 } else if (strcmp(argv[1], "ranvar") == 0) {
00357
00358
00359
00360
00361
00362 ranvar_ = (RandomVariable *)TclObject::lookup(argv[2]);
00363 return TCL_OK;
00364 } else if (strcmp(argv[1], "set-start-time") == 0) {
00365 double st = strtod(argv[2], NULL);
00366 start_time_ = st;
00367 end_time_ += st;
00368 } else if (strcmp(argv[1], "gen-init-modtime") == 0) {
00369 tcl.resultf("%.17g", Scheduler::instance().clock());
00370 return TCL_OK;
00371 }
00372 } else {
00373 if (strcmp(argv[1], "gen-modtime") == 0) {
00374
00375
00376
00377
00378
00379
00380
00381 int id = atoi(argv[2]);
00382 double mt = strtod(argv[3], NULL);
00383 ServerPage *pg = get_page(id);
00384 if (pg == NULL) {
00385 tcl.add_errorf("TracePagePool %s: page %d doesn't exists.\n",
00386 name_, id);
00387 return TCL_ERROR;
00388 }
00389 for (int i = 0; i < pg->num_mtime(); i++)
00390 if (pg->mtime(i) > mt) {
00391 tcl.resultf("%.17g",
00392 pg->mtime(i)+start_time_);
00393 return TCL_OK;
00394 }
00395
00396 tcl.resultf("%d", INT_MAX);
00397 return TCL_OK;
00398 }
00399 }
00400 return PagePool::command(argc, argv);
00401 }
00402
00403
00404
00405 static class MathPagePoolClass : public TclClass {
00406 public:
00407 MathPagePoolClass() : TclClass("PagePool/Math") {}
00408 TclObject* create(int, const char*const*) {
00409 return (new MathPagePool());
00410 }
00411 } class_mathpagepool_agent;
00412
00413
00414
00415 int MathPagePool::command(int argc, const char *const* argv)
00416 {
00417 Tcl& tcl = Tcl::instance();
00418
00419
00420 if (argc == 2) {
00421 if (strcmp(argv[1], "get-poolsize") == 0) {
00422 tcl.result("1");
00423 return TCL_OK;
00424 } else if (strcmp(argv[1], "get-start-time") == 0) {
00425 tcl.resultf("%.17g", start_time_);
00426 return TCL_OK;
00427 } else if (strcmp(argv[1], "get-duration") == 0) {
00428 tcl.resultf("%d", duration_);
00429 return TCL_OK;
00430 }
00431 } else if (argc == 3) {
00432 if (strcmp(argv[1], "gen-pageid") == 0) {
00433
00434 tcl.result("0");
00435 return TCL_OK;
00436 } else if (strcmp(argv[1], "gen-size") == 0) {
00437 if (rvSize_ == 0) {
00438 tcl.add_errorf("%s: no page size generator",
00439 name_);
00440 return TCL_ERROR;
00441 }
00442 int size = (int) rvSize_->value();
00443 if (size == 0)
00444
00445
00446 size = 1;
00447 tcl.resultf("%d", size);
00448 return TCL_OK;
00449 } else if (strcmp(argv[1], "ranvar-size") == 0) {
00450 rvSize_ = (RandomVariable*)TclObject::lookup(argv[2]);
00451 return TCL_OK;
00452 } else if (strcmp(argv[1], "ranvar-age") == 0) {
00453 rvAge_ = (RandomVariable*)TclObject::lookup(argv[2]);
00454 return TCL_OK;
00455 } else if (strcmp(argv[1], "set-start-time") == 0) {
00456 double st = strtod(argv[2], NULL);
00457 start_time_ = st;
00458 end_time_ += st;
00459 return TCL_OK;
00460 } else if (strcmp(argv[1], "gen-init-modtime") == 0) {
00461 tcl.resultf("%.17g", Scheduler::instance().clock());
00462 return TCL_OK;
00463 }
00464 } else {
00465 if (strcmp(argv[1], "gen-modtime") == 0) {
00466 if (rvAge_ == 0) {
00467 tcl.add_errorf("%s: no page age generator",
00468 name_);
00469 return TCL_ERROR;
00470 }
00471 double mt = strtod(argv[3], NULL);
00472 tcl.resultf("%.17g", mt + rvAge_->value());
00473 return TCL_OK;
00474 }
00475 }
00476
00477 return PagePool::command(argc, argv);
00478 }
00479
00480
00481
00482 static class CompMathPagePoolClass : public TclClass {
00483 public:
00484 CompMathPagePoolClass() : TclClass("PagePool/CompMath") {}
00485 TclObject* create(int, const char*const*) {
00486 return (new CompMathPagePool());
00487 }
00488 } class_compmathpagepool_agent;
00489
00490
00491 CompMathPagePool::CompMathPagePool()
00492 {
00493 bind("num_pages_", &num_pages_);
00494 bind("main_size_", &main_size_);
00495 bind("comp_size_", &comp_size_);
00496 }
00497
00498 int CompMathPagePool::command(int argc, const char *const* argv)
00499 {
00500 Tcl& tcl = Tcl::instance();
00501
00502
00503 if (argc == 2) {
00504 if (strcmp(argv[1], "get-poolsize") == 0) {
00505 tcl.result("1");
00506 return TCL_OK;
00507 } else if (strcmp(argv[1], "get-start-time") == 0) {
00508 tcl.resultf("%.17g", start_time_);
00509 return TCL_OK;
00510 } else if (strcmp(argv[1], "get-duration") == 0) {
00511 tcl.resultf("%d", duration_);
00512 return TCL_OK;
00513 }
00514
00515 } else if (argc == 3) {
00516 if (strcmp(argv[1], "gen-pageid") == 0) {
00517
00518 tcl.result("0");
00519 return TCL_OK;
00520 } else if (strcmp(argv[1], "gen-size") == 0) {
00521 int id = atoi(argv[2]);
00522 if (id == 0)
00523 tcl.resultf("%d", main_size_);
00524 else
00525 tcl.resultf("%d", comp_size_);
00526 return TCL_OK;
00527 } else if (strcmp(argv[1], "gen-obj-size") == 0) {
00528 tcl.resultf("%d", comp_size_);
00529 return (TCL_OK);
00530 } else if (strcmp(argv[1], "get-next-objs") == 0) {
00531 PageID id;
00532 ClientPage::split_name(argv[2], id);
00533
00534
00535
00536 for (int i = id.id_+1; i < num_pages_; i++) {
00537 tcl.resultf("%s %s:%d", tcl.result(),
00538 id.s_->name(), i);
00539 }
00540 return TCL_OK;
00541 } else if (strcmp(argv[1], "ranvar-main-age") == 0) {
00542 rvMainAge_ =
00543 (RandomVariable*)TclObject::lookup(argv[2]);
00544 return TCL_OK;
00545 } else if (strcmp(argv[1], "ranvar-obj-age") == 0) {
00546 rvCompAge_ =
00547 (RandomVariable*)TclObject::lookup(argv[2]);
00548 return TCL_OK;
00549 } else if (strcmp(argv[1], "set-start-time") == 0) {
00550 double st = strtod(argv[2], NULL);
00551 start_time_ = st;
00552 end_time_ += st;
00553 return TCL_OK;
00554 } else if (strcmp(argv[1], "gen-init-modtime") == 0) {
00555 tcl.resultf("%.17g", Scheduler::instance().clock());
00556 return TCL_OK;
00557 } else if (strcmp(argv[1], "is-mainpage") == 0) {
00558
00559
00560
00561
00562
00563 PageID t1;
00564 ClientPage::split_name(argv[2], t1);
00565 if (t1.id_ == 0)
00566 tcl.result("1");
00567 else
00568 tcl.result("0");
00569 return TCL_OK;
00570 } else if (strcmp(argv[1], "get-mainpage") == 0) {
00571
00572
00573
00574
00575
00576 PageID t1;
00577 ClientPage::split_name(argv[2], t1);
00578 tcl.resultf("%s:0", t1.s_->name());
00579 return TCL_OK;
00580 } else if (strcmp(argv[1], "get-obj-num") == 0) {
00581
00582
00583
00584 tcl.resultf("%d", num_pages_-1);
00585 return TCL_OK;
00586 }
00587
00588 } else {
00589
00590 if (strcmp(argv[1], "gen-modtime") == 0) {
00591 int id = atoi(argv[2]);
00592 if (id == 0) {
00593 if (rvMainAge_ == 0) {
00594 tcl.add_errorf("%s: no page age generator",
00595 name_);
00596 return TCL_ERROR;
00597 }
00598 double mt = strtod(argv[3], NULL);
00599 tcl.resultf("%.17g", mt + rvMainAge_->value());
00600 } else {
00601 if (rvCompAge_ == 0) {
00602 tcl.add_errorf("%s: no page age generator",
00603 name_);
00604 return TCL_ERROR;
00605 }
00606 double mt = atoi(argv[3]);
00607 tcl.resultf("%.17g", mt + rvCompAge_->value());
00608 }
00609 return TCL_OK;
00610 } else if (strcmp(argv[1], "gen-obj-modtime") == 0) {
00611 if (rvCompAge_ == 0) {
00612 tcl.add_errorf("%s: no page age generator",
00613 name_);
00614 return TCL_ERROR;
00615 }
00616 double mt = atoi(argv[3]);
00617 tcl.resultf("%.17g", mt + rvCompAge_->value());
00618 return TCL_OK;
00619 }
00620 }
00621
00622 return PagePool::command(argc, argv);
00623 }
00624
00625
00626 static class ClientPagePoolClass : public TclClass {
00627 public:
00628 ClientPagePoolClass() : TclClass("PagePool/Client") {}
00629 TclObject* create(int, const char*const*) {
00630 return (new ClientPagePool());
00631 }
00632 } class_clientpagepool_agent;
00633
00634 ClientPagePool::ClientPagePool()
00635 {
00636 namemap_ = new Tcl_HashTable;
00637 Tcl_InitHashTable(namemap_, 2);
00638 }
00639
00640 ClientPagePool::~ClientPagePool()
00641 {
00642 if (namemap_ != NULL) {
00643 Tcl_DeleteHashTable(namemap_);
00644 delete namemap_;
00645 }
00646 }
00647
00648
00649 int ClientPagePool::command(int argc, const char*const* argv)
00650 {
00651 Tcl& tcl = Tcl::instance();
00652 if (argc == 2) {
00653 if (strcmp(argv[1], "list-pages") == 0) {
00654 Tcl_HashEntry *he;
00655 Tcl_HashSearch hs;
00656 char *buf = new char[num_pages_*20];
00657 char *p = buf;
00658 for (he = Tcl_FirstHashEntry(namemap_, &hs);
00659 he != NULL;
00660 he = Tcl_NextHashEntry(&hs)) {
00661 int* t2 = (int*)Tcl_GetHashKey(namemap_, he);
00662 PageID t1(t2);
00663 #ifdef NEED_SUNOS_PROTOS
00664 sprintf(p, "%s:%-d ", t1.s_->name(),t1.id_);
00665 p += strlen(p);
00666 #else
00667 p += sprintf(p,"%s:%-d ",t1.s_->name(),t1.id_);
00668 #endif
00669 }
00670 tcl.resultf("%s", buf);
00671 delete []buf;
00672 return TCL_OK;
00673 }
00674 }
00675 return PagePool::command(argc, argv);
00676 }
00677
00678 ClientPage* ClientPagePool::get_page(const char *name)
00679 {
00680 PageID t1;
00681 ClientPage::split_name(name, t1);
00682
00683 Tcl_HashEntry *he = Tcl_FindHashEntry(namemap_, (const char *)&t1);
00684 if (he == NULL)
00685 return NULL;
00686 return (ClientPage *)Tcl_GetHashValue(he);
00687 }
00688
00689 int ClientPagePool::get_pageinfo(const char *name, char *buf)
00690 {
00691 ClientPage *pg = get_page(name);
00692 if (pg == NULL)
00693 return -1;
00694 pg->print_info(buf);
00695 return 0;
00696 }
00697
00698 ClientPage* ClientPagePool::enter_page(int argc, const char*const* argv)
00699 {
00700 double mt = -1, et, age = -1, noc = 0;
00701 int size = -1;
00702 for (int i = 3; i < argc; i+=2) {
00703 if (strcmp(argv[i], "modtime") == 0)
00704 mt = strtod(argv[i+1], NULL);
00705 else if (strcmp(argv[i], "size") == 0)
00706 size = atoi(argv[i+1]);
00707 else if (strcmp(argv[i], "age") == 0)
00708 age = strtod(argv[i+1], NULL);
00709 else if (strcmp(argv[i], "noc") == 0)
00710
00711 noc = 1;
00712 }
00713
00714 if (size < 0) {
00715 fprintf(stderr, "PagePool %s: wrong information for page %s\n",
00716 name_, argv[2]);
00717 return NULL;
00718 }
00719 et = Scheduler::instance().clock();
00720 ClientPage* pg = new ClientPage(argv[2], size, mt, et, age);
00721 if (add_page(pg) < 0) {
00722 delete pg;
00723 return NULL;
00724 }
00725 if (noc)
00726 pg->set_uncacheable();
00727 return pg;
00728 }
00729
00730 ClientPage* ClientPagePool::enter_page(const char *name, int size, double mt,
00731 double et, double age)
00732 {
00733 ClientPage* pg = new ClientPage(name, size, mt, et, age);
00734 if (add_page(pg) < 0) {
00735 delete pg;
00736 return NULL;
00737 }
00738 return pg;
00739 }
00740
00741
00742
00743 ClientPage* ClientPagePool::enter_metadata(int argc, const char*const* argv)
00744 {
00745 ClientPage *pg = enter_page(argc, argv);
00746 if (pg != NULL)
00747 pg->set_valid_hdr();
00748 return pg;
00749 }
00750
00751 ClientPage* ClientPagePool::enter_metadata(const char *name, int size,
00752 double mt, double et, double age)
00753 {
00754 ClientPage *pg = enter_page(name, size, mt, et, age);
00755 if (pg != NULL)
00756 pg->set_valid_hdr();
00757 return pg;
00758 }
00759
00760 int ClientPagePool::add_page(ClientPage* pg)
00761 {
00762 if (pg == NULL)
00763 return -1;
00764
00765 char buf[HTTP_MAXURLLEN];
00766 pg->name(buf);
00767
00768 PageID t1;
00769 ClientPage::split_name(buf, t1);
00770
00771 int newEntry = 1;
00772 Tcl_HashEntry *he = Tcl_CreateHashEntry(namemap_,
00773 (const char *)&t1,
00774 &newEntry);
00775 if (he == NULL)
00776 return -1;
00777
00778
00779
00780 if (newEntry) {
00781 Tcl_SetHashValue(he, (ClientData)pg);
00782 num_pages_++;
00783 } else {
00784
00785 ClientPage *q = (ClientPage *)Tcl_GetHashValue(he);
00786
00787 pg->counter() = q->counter();
00788
00789 if (q->is_mpush())
00790 pg->set_mpush(q->mpush_time());
00791 Tcl_SetHashValue(he, (ClientData)pg);
00792 delete q;
00793 }
00794 return 0;
00795 }
00796
00797 int ClientPagePool::remove_page(const char *name)
00798 {
00799 PageID t1;
00800 ClientPage::split_name(name, t1);
00801
00802
00803 Tcl_HashEntry *he = Tcl_FindHashEntry(namemap_, (const char *)&t1);
00804 if (he == NULL)
00805 return -1;
00806 ClientPage *pg = (ClientPage *)Tcl_GetHashValue(he);
00807 Tcl_DeleteHashEntry(he);
00808 delete pg;
00809 num_pages_--;
00810
00811
00812 return 0;
00813 }
00814
00815 int ClientPagePool::set_mtime(const char *name, double mt)
00816 {
00817 ClientPage *pg = (ClientPage *)get_page(name);
00818 if (pg == NULL)
00819 return -1;
00820 pg->mtime() = mt;
00821 return 0;
00822 }
00823
00824 int ClientPagePool::get_mtime(const char *name, double& mt)
00825 {
00826 ClientPage *pg = (ClientPage *)get_page(name);
00827 if (pg == NULL)
00828 return -1;
00829 mt = pg->mtime();
00830 return 0;
00831 }
00832
00833 int ClientPagePool::set_etime(const char *name, double et)
00834 {
00835 ClientPage *pg = (ClientPage *)get_page(name);
00836 if (pg == NULL)
00837 return -1;
00838 pg->etime() = et;
00839 return 0;
00840 }
00841
00842 int ClientPagePool::get_etime(const char *name, double& et)
00843 {
00844 ClientPage *pg = (ClientPage *)get_page(name);
00845 if (pg == NULL)
00846 return -1;
00847 et = pg->etime();
00848 return 0;
00849 }
00850
00851 int ClientPagePool::get_size(const char *name, int& size)
00852 {
00853 ClientPage *pg = (ClientPage *)get_page(name);
00854 if (pg == NULL)
00855 return -1;
00856 size = pg->size();
00857 return 0;
00858 }
00859
00860 int ClientPagePool::get_age(const char *name, double& age)
00861 {
00862 ClientPage *pg = (ClientPage *)get_page(name);
00863 if (pg == NULL)
00864 return -1;
00865 age = pg->age();
00866 return 0;
00867 }
00868
00869 void ClientPagePool::invalidate_server(int sid)
00870 {
00871 Tcl_HashEntry *he;
00872 Tcl_HashSearch hs;
00873 ClientPage *pg;
00874 int i;
00875
00876 for (i = 0, he = Tcl_FirstHashEntry(namemap_, &hs);
00877 he != NULL;
00878 he = Tcl_NextHashEntry(&hs), i++) {
00879 pg = (ClientPage *) Tcl_GetHashValue(he);
00880 if (pg->server()->id() == sid)
00881 pg->server_down();
00882 }
00883 }
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 static class ProxyTracePagePoolClass : public TclClass {
00898 public:
00899 ProxyTracePagePoolClass() : TclClass("PagePool/ProxyTrace") {}
00900 TclObject* create(int, const char*const*) {
00901 return (new ProxyTracePagePool());
00902 }
00903 } class_ProxyTracepagepool_agent;
00904
00905 ProxyTracePagePool::ProxyTracePagePool() :
00906 rvDyn_(NULL), rvStatic_(NULL), br_(0),
00907 size_(NULL), reqfile_(NULL), req_(NULL), lastseq_(0)
00908 {
00909 }
00910
00911 ProxyTracePagePool::~ProxyTracePagePool()
00912 {
00913 if (size_ != NULL)
00914 delete []size_;
00915 if (reqfile_ != NULL)
00916 fclose(reqfile_);
00917 if (req_ != NULL) {
00918 Tcl_DeleteHashTable(req_);
00919 delete req_;
00920 }
00921 }
00922
00923 int ProxyTracePagePool::init_req(const char *fn)
00924 {
00925 reqfile_ = fopen(fn, "r");
00926 if (reqfile_ == NULL) {
00927 fprintf(stderr,
00928 "ProxyTracePagePool: couldn't open trace file %s\n", fn);
00929 return TCL_ERROR;
00930 }
00931
00932
00933
00934
00935 return find_info();
00936 }
00937
00938 int ProxyTracePagePool::find_info()
00939 {
00940
00941 fseek(reqfile_, -128, SEEK_END);
00942 char buf[129];
00943 if (fread(buf, 1, 128, reqfile_) != 128) {
00944 fprintf(stderr,
00945 "ProxyTracePagePool: cannot read file information\n");
00946 return TCL_ERROR;
00947 }
00948 int i;
00949
00950 buf[128] = 0;
00951 if (buf[127] == '\n')
00952 buf[127] = 0;
00953 for (i = 127; i >= 0; i--)
00954 if (buf[i] == '\n') {
00955 i++;
00956 break;
00957 }
00958 if (buf[i] != 'i') {
00959 fprintf(stderr,
00960 "ProxyTracePagePool: trace file doesn't contain statistics.\n");
00961 abort();
00962 }
00963 double len;
00964 sscanf(buf+i+1, "%lf %u", &len, &num_pages_);
00965 duration_ = (int)ceil(len);
00966 #if 0
00967 printf("ProxyTracePagePool: duration %d pages %u\n",
00968 duration_, num_pages_);
00969 #endif
00970 rewind(reqfile_);
00971 return TCL_OK;
00972 }
00973
00974
00975 int ProxyTracePagePool::init_page(const char *fn)
00976 {
00977 FILE *fp = fopen(fn, "r");
00978 if (fp == NULL) {
00979 fprintf(stderr,
00980 "ProxyTracePagePool: couldn't open trace file %s\n", fn);
00981 return TCL_ERROR;
00982 }
00983 if (size_ != NULL)
00984 delete []size_;
00985 int* p = new int[num_pages_];
00986 size_ = p;
00987 for (int i = 0; i < num_pages_; i++, p++)
00988 fscanf(fp, "%*d %*d %d %*u\n", p);
00989 fclose(fp);
00990 return TCL_OK;
00991 }
00992
00993 ProxyTracePagePool::ClientRequest* ProxyTracePagePool::load_req(int cid)
00994 {
00995
00996 Tcl_HashEntry *he;
00997 ClientRequest *p;
00998 int dummy;
00999 long key = cid;
01000 if ((he = Tcl_FindHashEntry(req_, (const char*)key)) == NULL) {
01001
01002 p = new ClientRequest();
01003 p->seq_ = lastseq_++;
01004 he = Tcl_CreateHashEntry(req_, (const char*)key, &dummy);
01005 Tcl_SetHashValue(he, (const char*)p);
01006
01007 fseek(reqfile_, 0, SEEK_SET);
01008 } else {
01009 p = (ClientRequest*)Tcl_GetHashValue(he);
01010 if (p->nrt_ == -1)
01011
01012 return p;
01013
01014 fseek(reqfile_, p->fpos_, SEEK_SET);
01015 }
01016
01017
01018 double nrt;
01019 int ncid = -1, nurl;
01020 char buf[256];
01021 while (fgets(buf, 256, reqfile_)) {
01022 if (isalpha(buf[0])) {
01023
01024 ncid = -1;
01025 break;
01026 }
01027 sscanf(buf, "%lf %d %*d %d\n", &nrt, &ncid, &nurl);
01028 if ((ncid % nclient_) == p->seq_)
01029 break;
01030 }
01031 if ((ncid % nclient_) != p->seq_)
01032
01033 p->nrt_ = -1;
01034 else {
01035 p->nrt_ = nrt, p->nurl_ = nurl;
01036 p->nrt_ += start_time_;
01037 }
01038 p->fpos_ = ftell(reqfile_);
01039 return p;
01040 }
01041
01042
01043 int ProxyTracePagePool::command(int argc, const char*const* argv)
01044 {
01045 Tcl& tcl = Tcl::instance();
01046
01047 if (argc == 2) {
01048 if (strcmp(argv[1], "get-poolsize") == 0) {
01049 tcl.resultf("%u", num_pages_);
01050 return TCL_OK;
01051 } else if (strcmp(argv[1], "get-start-time") == 0) {
01052 tcl.resultf("%.17g", start_time_);
01053 return TCL_OK;
01054 } else if (strcmp(argv[1], "get-duration") == 0) {
01055 tcl.resultf("%d", duration_);
01056 return TCL_OK;
01057 } else if (strcmp(argv[1], "bimodal-ratio") == 0) {
01058 tcl.resultf("%g", br_ / 10);
01059 return TCL_OK;
01060 }
01061 } else if (argc == 3) {
01062 if (strcmp(argv[1], "set-client-num") == 0) {
01063
01064
01065 if (req_ != NULL)
01066 return TCL_ERROR;
01067 int num = atoi(argv[2]);
01068 req_ = new Tcl_HashTable;
01069 Tcl_InitHashTable(req_, TCL_ONE_WORD_KEYS);
01070 nclient_ = num;
01071 return TCL_OK;
01072 } else if (strcmp(argv[1], "gen-request") == 0) {
01073
01074 int id = atoi(argv[2]);
01075 ClientRequest *p = load_req(id);
01076 if ((p->nrt_ >= 0) &&
01077 (p->nrt_ < Scheduler::instance().clock())) {
01078
01079
01080
01081 fprintf(stderr,
01082 "%.17g: Wrong request time %g.\n",
01083 Scheduler::instance().clock(),
01084 p->nrt_);
01085
01086
01087 p->nrt_ = Scheduler::instance().clock()+0.001;
01088 }
01089 tcl.resultf("%lf %d",
01090 p->nrt_ - Scheduler::instance().clock(),
01091 p->nurl_);
01092 return TCL_OK;
01093 } else if (strcmp(argv[1], "gen-size") == 0) {
01094 int id = atoi(argv[2]);
01095 if ((id < 0) || (id > num_pages_)) {
01096 tcl.result("PagePool: id out of range.\n");
01097 return TCL_ERROR;
01098 }
01099 tcl.resultf("%d", size_[id]);
01100 return TCL_OK;
01101 } else if (strcmp(argv[1], "set-start-time") == 0) {
01102 start_time_ = strtod(argv[2], NULL);
01103 return TCL_OK;
01104 } else if (strcmp(argv[1], "bimodal-ratio") == 0) {
01105
01106
01107
01108
01109
01110
01111
01112 double ratio = strtod(argv[2], NULL);
01113
01114 br_ = (int)ceil(ratio*10);
01115 return TCL_OK;
01116 } else if (strcmp(argv[1], "ranvar-dp") == 0) {
01117
01118 rvDyn_ = (RandomVariable*)TclObject::lookup(argv[2]);
01119 return TCL_OK;
01120 } else if (strcmp(argv[1], "ranvar-sp") == 0) {
01121
01122 rvStatic_= (RandomVariable*)TclObject::lookup(argv[2]);
01123 return TCL_OK;
01124 } else if (strcmp(argv[1], "set-reqfile") == 0) {
01125 return init_req(argv[2]);
01126 } else if (strcmp(argv[1], "set-pagefile") == 0) {
01127 return init_page(argv[2]);
01128 } else if (strcmp(argv[1], "gen-init-modtime") == 0) {
01129 int id = atoi(argv[2]) % 10;
01130 if (id >= br_)
01131
01132 tcl.result("0");
01133 else
01134
01135 tcl.resultf("%.17g",
01136 Scheduler::instance().clock());
01137 return TCL_OK;
01138 }
01139 } else {
01140 if (strcmp(argv[1], "gen-modtime") == 0) {
01141 if ((rvDyn_ == 0) || (rvStatic_ == 0)) {
01142 tcl.add_errorf("%s: no page age generator",
01143 name_);
01144 return TCL_ERROR;
01145 }
01146
01147 int id = atoi(argv[2]) % 10;
01148 double mt = strtod(argv[3], NULL);
01149 if (id >= br_)
01150 tcl.resultf("%.17g", mt + rvStatic_->value());
01151 else
01152 tcl.resultf("%.17g", mt + rvDyn_->value());
01153 return TCL_OK;
01154 }
01155 }
01156
01157 return PagePool::command(argc, argv);
01158 }
01159
01160
01161
01162 static class EPAPagePoolClass : public TclClass {
01163 public:
01164 EPAPagePoolClass() : TclClass("PagePool/ProxyTrace/epa") {}
01165 TclObject* create(int, const char*const*) {
01166 return (new EPATracePagePool());
01167 }
01168 } class_epapagepool_agent;
01169
01170 int EPATracePagePool::command(int argc, const char*const* argv)
01171 {
01172 Tcl& tcl = Tcl::instance();
01173 if (argc == 2) {
01174 if (strcmp(argv[1], "pick-pagemod") == 0) {
01175 if (rvDyn_ == 0) {
01176 tcl.add_errorf("%s: no page age generator",
01177 name_);
01178 return (TCL_ERROR);
01179 }
01180 int j = (int)floor(rvDyn_->value());
01181
01182 tcl.resultf("%d", j/br_*10 + j % br_);
01183 return TCL_OK;
01184 }
01185 } else if (argc == 3) {
01186 if (strcmp(argv[1], "ranvar-dp") == 0) {
01187 rvDyn_ = (RandomVariable*)TclObject::lookup(argv[2]);
01188 if (rvDyn_ == 0) {
01189 tcl.add_errorf("%s: no page age generator",
01190 name_);
01191 return (TCL_ERROR);
01192 }
01193 ((UniformRandomVariable*)rvDyn_)->setmin(0);
01194 ((UniformRandomVariable*)rvDyn_)->setmax(num_pages_/10*br_ + num_pages_%br_ - 1);
01195 return TCL_OK;
01196 }
01197 } else {
01198 if (strcmp(argv[1], "gen-modtime") == 0) {
01199
01200 tcl.resultf("%d", INT_MAX);
01201 return TCL_OK;
01202 }
01203 }
01204 return ProxyTracePagePool::command(argc, argv);
01205 }
01206