📄 pagepool.cc
字号:
// Copyright (c) Xerox Corporation 1998. All rights reserved.//// License is granted to copy, to use, and to make and to use derivative// works for research and evaluation purposes, provided that Xerox is// acknowledged in all documentation pertaining to any such copy or// derivative work. Xerox grants no other licenses expressed or// implied. The Xerox trade name should not be used in any advertising// without its written permission. //// XEROX CORPORATION MAKES NO REPRESENTATIONS CONCERNING EITHER THE// MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE// FOR ANY PARTICULAR PURPOSE. The software is provided "as is" without// express or implied warranty of any kind.//// These notices must be retained in any copies of any part of this// software. //// $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/pagepool.cc,v 1.14 1999/08/04 21:04:04 haoboy Exp $#include <stdlib.h>#include <sys/types.h>#include <fcntl.h>#ifdef WIN32#include <windows.h>#include <io.h>#else #include <unistd.h>#include <sys/file.h>#endif#include <sys/stat.h>#include <stdio.h>#include <limits.h>#include <ctype.h>extern "C" {#include <otcl.h>}#include "pagepool.h"#include "http.h"// Static/global variablesint ClientPage::PUSHALL_ = 0; // Initialized to selective pushvoid ServerPage::set_mtime(int *mt, int n){ if (mtime_ != NULL) delete []mtime_; mtime_ = new int[n]; memcpy(mtime_, mt, sizeof(int)*n);}ClientPage::ClientPage(const char *n, int s, double mt, double et, double a) : Page(s), age_(a), mtime_(mt), etime_(et), status_(HTTP_VALID_PAGE), counter_(0), mpushTime_(0){ // Parse name to get server and page id char *buf = new char[strlen(n) + 1]; strcpy(buf, n); char *tmp = strtok(buf, ":"); server_ = (HttpApp*)TclObject::lookup(tmp); if (server_ == NULL) { fprintf(stderr, "Non-exitent server name for page %s", n); abort(); } tmp = strtok(NULL, ":"); id_ = atol(tmp); delete []buf;}void ClientPage::print_name(char* name, PageID& id){ sprintf(name, "%s:%-d", id.s_->name(), id.id_);}void ClientPage::split_name(const char* name, PageID& id){ char *buf = new char[strlen(name)+1]; strcpy(buf, name); char *tmp = strtok(buf, ":"); id.s_ = (HttpApp*)TclObject::lookup(tmp); if (id.s_ == NULL) { fprintf(stderr, "Non-exitent server name for page %s\n", name); abort(); } tmp = strtok(NULL, ":"); id.id_ = atol(tmp); delete []buf;}void ClientPage::print_info(char *buf){ sprintf(buf, "size %d modtime %.17g time %.17g age %.17g", size(), mtime(), etime(), age()); if (is_uncacheable()) strcat(buf, " noc 1");}void ClientPage::name(char* buf) { sprintf(buf, "%s:%d", server_->name(), id());}static class PagePoolClass : public TclClass {public: PagePoolClass() : TclClass("PagePool") {} TclObject* create(int, const char*const*) { return (new PagePool()); }} class_pagepool_agent;int PagePool::command(int argc, const char*const* argv){ if (argc == 2) { // XXX Should be static class variables... if (strcmp(argv[1], "set-allpush") == 0) { ClientPage::PUSHALL_ = 1; return (TCL_OK); } if (strcmp(argv[1], "set-selpush") == 0) { ClientPage::PUSHALL_ = 0; return (TCL_OK); } } return TclObject::command(argc, argv);}// TracePagePool// Used for Worrell's filtered server traces only. For handling general // web server traces and proxy traces, have a look at ProxyTracePagePool below.//// Load a trace statistics file, and randomly generate requests and // page lifetimes from the trace.//// Trace statistics file format:// <URL> <size> {<modification time>}static class TracePagePoolClass : public TclClass {public: TracePagePoolClass() : TclClass("PagePool/Trace") {} TclObject* create(int argc, const char*const* argv) { if (argc >= 5) return (new TracePagePool(argv[4])); return 0; }} class_tracepagepool_agent;TracePagePool::TracePagePool(const char *fn) : PagePool(), ranvar_(0){ FILE *fp = fopen(fn, "r"); if (fp == NULL) { fprintf(stderr, "TracePagePool: couldn't open trace file %s\n", fn); abort(); // What else can we do? } namemap_ = new Tcl_HashTable; Tcl_InitHashTable(namemap_, TCL_STRING_KEYS); idmap_ = new Tcl_HashTable; Tcl_InitHashTable(idmap_, TCL_ONE_WORD_KEYS); while (load_page(fp)); change_time();}TracePagePool::~TracePagePool(){ if (namemap_ != NULL) { Tcl_DeleteHashTable(namemap_); delete namemap_; } if (idmap_ != NULL) { Tcl_DeleteHashTable(idmap_); delete idmap_; }}void TracePagePool::change_time(){ Tcl_HashEntry *he; Tcl_HashSearch hs; ServerPage *pg; int i, j; for (i = 0, he = Tcl_FirstHashEntry(idmap_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs), i++) { pg = (ServerPage *) Tcl_GetHashValue(he); for (j = 0; j < pg->num_mtime(); j++) pg->mtime(j) -= (int)start_time_; } end_time_ -= start_time_; start_time_ = 0; duration_ = (int)end_time_;}ServerPage* TracePagePool::load_page(FILE *fp){ static char buf[TRACEPAGEPOOL_MAXBUF]; char *delim = " \t\n"; char *tmp1, *tmp2; ServerPage *pg; // XXX Use internal variables of struct Page if (!fgets(buf, TRACEPAGEPOOL_MAXBUF, fp)) return NULL; // URL tmp1 = strtok(buf, delim); // Size tmp2 = strtok(NULL, delim); pg = new ServerPage(atoi(tmp2), num_pages_++); if (add_page(tmp1, pg)) { delete pg; return NULL; } // Modtimes, assuming they are in ascending time order int num = 0; int *nmd = new int[5]; while ((tmp1 = strtok(NULL, delim)) != NULL) { if (num >= 5) { int *tt = new int[num+5]; memcpy(tt, nmd, sizeof(int)*num); delete []nmd; nmd = tt; } nmd[num] = atoi(tmp1); if (nmd[num] < start_time_) start_time_ = nmd[num]; if (nmd[num] > end_time_) end_time_ = nmd[num]; num++; } pg->num_mtime() = num; pg->set_mtime(nmd, num); delete []nmd; return pg;}int TracePagePool::add_page(const char* name, ServerPage *pg){ int newEntry = 1; Tcl_HashEntry *he = Tcl_CreateHashEntry(namemap_, (const char *)name, &newEntry); if (he == NULL) return -1; if (newEntry) Tcl_SetHashValue(he, (ClientData)pg); else fprintf(stderr, "TracePagePool: Duplicate entry %s\n", name); Tcl_HashEntry *hf = Tcl_CreateHashEntry(idmap_, (const char *)pg->id(), &newEntry); if (hf == NULL) { Tcl_DeleteHashEntry(he); return -1; } if (newEntry) Tcl_SetHashValue(hf, (ClientData)pg); else fprintf(stderr, "TracePagePool: Duplicate entry %d\n", pg->id()); return 0;}ServerPage* TracePagePool::get_page(int id){ if ((id < 0) || (id >= num_pages_)) return NULL; Tcl_HashEntry *he = Tcl_FindHashEntry(idmap_, (const char *)id); if (he == NULL) return NULL; return (ServerPage *)Tcl_GetHashValue(he);}int TracePagePool::command(int argc, const char *const* argv){ Tcl &tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "get-poolsize") == 0) { /* * <pgpool> get-poolsize * Get the number of pages currently in pool */ tcl.resultf("%d", num_pages_); return TCL_OK; } else if (strcmp(argv[1], "get-start-time") == 0) { tcl.resultf("%.17g", start_time_); return TCL_OK; } else if (strcmp(argv[1], "get-duration") == 0) { tcl.resultf("%d", duration_); return TCL_OK; } } else if (argc == 3) { if (strcmp(argv[1], "gen-pageid") == 0) { /* * <pgpool> gen-pageid <client_id> * Randomly generate a page id from page pool */ double tmp = ranvar_ ? ranvar_->value() : Random::uniform(); // tmp should be in [0, num_pages_-1] tmp = (tmp < 0) ? 0 : (tmp >= num_pages_) ? (num_pages_-1):tmp; if ((int)tmp >= num_pages_) abort(); tcl.resultf("%d", (int)tmp); return TCL_OK; } else if (strcmp(argv[1], "gen-size") == 0) { /* * <pgpool> gen-size <pageid> */ int id = atoi(argv[2]); ServerPage *pg = get_page(id); if (pg == NULL) { tcl.add_errorf("TracePagePool %s: page %d doesn't exists.\n", name_, id); return TCL_ERROR; } tcl.resultf("%d", pg->size()); return TCL_OK; } else if (strcmp(argv[1], "ranvar") == 0) { /* * <pgpool> ranvar <ranvar> * Set a random var which is used to randomly pick * a page from the page pool. */ ranvar_ = (RandomVariable *)TclObject::lookup(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "set-start-time") == 0) { double st = strtod(argv[2], NULL); start_time_ = st; end_time_ += st; } else if (strcmp(argv[1], "gen-init-modtime") == 0) { tcl.resultf("%.17g", Scheduler::instance().clock()); return TCL_OK; } } else { if (strcmp(argv[1], "gen-modtime") == 0) { /* * <pgpool> get-modtime <pageid> <modtime> * * Return next modtime that is larger than modtime * To retrieve the first modtime (creation time), set * <modtime> to -1 in the request. */ int id = atoi(argv[2]); double mt = strtod(argv[3], NULL); ServerPage *pg = get_page(id); if (pg == NULL) { tcl.add_errorf("TracePagePool %s: page %d doesn't exists.\n", name_, id); return TCL_ERROR; } for (int i = 0; i < pg->num_mtime(); i++) if (pg->mtime(i) > mt) { tcl.resultf("%.17g", pg->mtime(i)+start_time_); return TCL_OK; } // When get to the last modtime, return -1 tcl.resultf("%d", INT_MAX); return TCL_OK; } } return PagePool::command(argc, argv);}static class MathPagePoolClass : public TclClass {public: MathPagePoolClass() : TclClass("PagePool/Math") {} TclObject* create(int, const char*const*) { return (new MathPagePool()); }} class_mathpagepool_agent;// Use 3 ranvars to generate requests, mod times and page sizeint MathPagePool::command(int argc, const char *const* argv){ Tcl& tcl = Tcl::instance(); // Keep the same tcl interface as PagePool/Trace if (argc == 2) { if (strcmp(argv[1], "get-poolsize") == 0) { tcl.result("1");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -