/* * Copyright (c) Xerox Corporation 1998. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Linking this file statically or dynamically with other modules is making * a combined work based on this file. Thus, the terms and conditions of * the GNU General Public License cover the whole combination. * * In addition, as a special exception, the copyright holders of this file * give you permission to combine this file with free software programs or * libraries that are released under the GNU LGPL and with code included in * the standard release of ns-2 under the Apache 2.0 license or under * otherwise-compatible licenses with advertising requirements (or modified * versions of such code, with unchanged license). You may copy and * distribute such a system following the terms of the GNU GPL for this * file and the licenses of the other code concerned, provided that you * include the source code of that other code when and as the GNU GPL * requires distribution of source code. * * Note that people who make modified versions of this file are not * obligated to grant this special exception for their modified versions; * it is their choice whether to do so. The GNU General Public License * gives permission to release a modified version without this exception; * this exception also makes it possible to release a modified version * which carries forward this exception. * * $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/pagepool.h,v 1.17 2005/09/18 23:33:35 tomh Exp $ * */ // // Definitions for class PagePool // #ifndef ns_pagepool_h #define ns_pagepool_h #include #include #include #include #include #include "config.h" enum WebPageType { HTML, MEDIA }; class Page { public: Page(int size) : size_(size) {} virtual ~Page () {} int size() const { return size_; } int& id() { return id_; } virtual WebPageType type() const = 0; // Page type: HTML or MEDIA protected: int size_; int id_; }; class ServerPage : public Page { public: ServerPage(int size, int id) : Page(size) { id_ = id, mtime_ = NULL, num_mtime_ = 0; } virtual ~ServerPage() { if (mtime_ != NULL) delete []mtime_; } virtual WebPageType type() const { return HTML; } int& size() { return size_; } int& mtime(int n) { return mtime_[n]; } int& num_mtime() { return num_mtime_; } void set_mtime(int *mt, int n); protected: int *mtime_; int num_mtime_; }; class HttpApp; // Page states const int HTTP_PAGE_STATE_MASK = 0x00FF; const int HTTP_ALL_PAGE_STATES = 0x00ff; // all page states const int HTTP_VALID_PAGE = 0x01; // Valid page const int HTTP_SERVER_DOWN = 0x02; // Server is down. Don't know if // page is valid const int HTTP_VALID_HEADER = 0x04; // Only meta-data is valid const int HTTP_UNREAD_PAGE = 0x08; // Unread valid page // Used only for server to manage its pages. A none-cacheable page won't be // stored by caches and clients. const int HTTP_UNCACHEABLE = 0x10; // Non-cacheable page // Page actions const int HTTP_PAGE_ACTION_MASK = 0xFF00; // Page action bit mask const int HTTP_MANDATORY_PUSH = 0x1000; // If the page is mandatory pushed struct PageID { PageID() : s_(NULL), id_(0) {} PageID(int *buffer) { PageID *realBuffer = reinterpret_cast (buffer); s_ = realBuffer->s_; id_ = realBuffer->id_; } PageID(HttpApp *app, int id) { s_ = app; id_ = id; } HttpApp* s_; int id_; }; class ClientPage : public Page { public: ClientPage(const char *n, int s, double mt, double et, double a); virtual ~ClientPage() {} virtual WebPageType type() const { return HTML; } virtual void print_info(char* buf); void name(char* buf); double& mtime() { return mtime_; } double& etime() { return etime_; } double& age() { return age_; } HttpApp* server() { return server_; } // Page becomes valid. Clear all other possible invalid bits void validate(double mtime) { if (mtime_ >= mtime) abort(); // This shouldn't happen! // Clear server down bit clear_page_state(HTTP_SERVER_DOWN); set_page_state(HTTP_VALID_PAGE); mtime_ = mtime; } void invalidate(double mtime) { if (mtime_ >= mtime) return; clear_page_state(HTTP_VALID_PAGE); clear_page_state(HTTP_VALID_HEADER); mtime_ = mtime; } int is_valid() const { return (status_ & HTTP_VALID_PAGE); } int is_header_valid() const { return ((status_ & HTTP_VALID_PAGE) || (status_ & HTTP_VALID_HEADER)); } inline void set_valid_hdr() { // XXX page invalid, but only header valid clear_page_state(HTTP_SERVER_DOWN); clear_page_state(HTTP_VALID_PAGE); set_page_state(HTTP_VALID_HEADER); } inline void set_uncacheable() { set_page_state(HTTP_UNCACHEABLE); } inline int is_uncacheable() { return (status_ & HTTP_UNCACHEABLE); } // Has nothing to do with valid/invalid/server_down etc. It can // be combined with all other page status inline void set_unread() { set_page_state(HTTP_UNREAD_PAGE); } inline void set_read() { clear_page_state(HTTP_UNREAD_PAGE); } inline int is_unread() { return (status_ & HTTP_UNREAD_PAGE); } inline int is_server_down() { return (status_ & HTTP_SERVER_DOWN); } inline void server_down() { // Set page as invalid // Don't change mtime, only change page status clear_page_state(HTTP_VALID_PAGE); clear_page_state(HTTP_VALID_HEADER); set_page_state(HTTP_SERVER_DOWN); } // Flags to indicate whether we want to do all push or selective push // If 0: selective push, otherwise all push static int PUSHALL_; inline int& counter() { if (PUSHALL_) counter_ = INT_MAX; return counter_; } inline int count_inval(int a, int th) { if (PUSHALL_) return INT_MAX; else { counter_ -= a; if (counter_ < th) counter_ = th; return counter_; } } inline int count_request(int b, int th) { if (PUSHALL_) return INT_MAX; else { counter_ += b; if (counter_ > th) counter_ = th; return counter_; } } inline void set_mpush(double time) { set_page_action(HTTP_MANDATORY_PUSH), mpushTime_ = time; } inline void clear_mpush() { clear_page_action(HTTP_MANDATORY_PUSH); } inline int is_mpush() { return status_ & HTTP_MANDATORY_PUSH; } inline double mpush_time() { return mpushTime_; } // Used to split page names into page identifiers static void split_name(const char* name, PageID& id); static void print_name(char* name, PageID& id); protected: void set_page_state(int state) { status_ |= state; } void clear_page_state(int state) { status_ = status_ & ~state; } void set_page_action(int action) { status_ |= action; } void clear_page_action(int action) { status_ = status_ & ~action; } HttpApp* server_; double age_; double mtime_; // modification time double etime_; // entry time int status_; // VALID or INVALID int counter_; // counter for invalidation & request double mpushTime_; }; // Abstract page pool, used for interface only class PagePool : public TclObject { public: PagePool() : num_pages_(0), start_time_(INT_MAX), end_time_(INT_MIN) {} int num_pages() const { return num_pages_; } protected: virtual int command(int argc, const char*const* argv); int num_pages_; double start_time_; double end_time_; int duration_; // Helper functions TclObject* lookup_obj(const char* name) { TclObject* obj = Tcl::instance().lookup(name); if (obj == NULL) fprintf(stderr, "Bad object name %s\n", name); return obj; } }; // Page pool based on real server traces const int TRACEPAGEPOOL_MAXBUF = 4096; // This trace must contain web page names and all of its modification times class TracePagePool : public PagePool { public: TracePagePool(const char *fn); virtual ~TracePagePool(); virtual int command(int argc, const char*const* argv); protected: Tcl_HashTable *namemap_, *idmap_; RandomVariable *ranvar_; ServerPage* load_page(FILE *fp); void change_time(); int add_page(const char* pgname, ServerPage *pg); ServerPage* get_page(int id); }; // Page pool based on mathematical models of request and page // modification patterns class MathPagePool : public PagePool { public: // XXX TBA: what should be here??? MathPagePool() : rvSize_(0), rvAge_(0) { num_pages_ = 1; } protected: virtual int command(int argc, const char*const* argv); // Single page RandomVariable *rvSize_; RandomVariable *rvAge_; }; // Assume one main page, which changes often, and multiple component pages class CompMathPagePool : public PagePool { public: CompMathPagePool(); protected: virtual int command(int argc, const char*const* argv); RandomVariable *rvMainAge_; // modtime for main page RandomVariable *rvCompAge_; // modtime for component pages int main_size_, comp_size_; }; class ClientPagePool : public PagePool { public: ClientPagePool(); virtual ~ClientPagePool(); virtual ClientPage* enter_page(int argc, const char*const* argv); virtual ClientPage* enter_metadata(int argc, const char*const* argv); virtual ClientPage* enter_page(const char *name, int size, double mt, double et, double age); virtual ClientPage* enter_metadata(const char *name, int size, double mt, double et, double age); virtual int remove_page(const char *name); void invalidate_server(int server_id); ClientPage* get_page(const char *name); int get_mtime(const char *name, double &mt); int set_mtime(const char *name, double mt); int exist_page(const char *name) { return (get_page(name) != NULL); } int get_size(const char *name, int &size); int get_age(const char *name, double &age); int get_etime(const char *name, double &et); int set_etime(const char *name, double et); int get_pageinfo(const char *name, char *buf); virtual int command(int argc, const char*const* argv); protected: int add_page(ClientPage *pg); Tcl_HashTable *namemap_; }; // This is *not* designed for BU trace files. We should write a script to // transform BU traces to a single trace file with the following format: // //