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