mcache.h

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 
00003 /*
00004  * mcache.h
00005  * Copyright (C) 1997 by the University of Southern California
00006  * $Id: mcache.h,v 1.8 2005/09/18 23:33:35 tomh Exp $
00007  *
00008  * This program is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License,
00010  * version 2, as published by the Free Software Foundation.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along
00018  * with this program; if not, write to the Free Software Foundation, Inc.,
00019  * 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
00020  *
00021  *
00022  * The copyright of this module includes the following
00023  * linking-with-specific-other-licenses addition:
00024  *
00025  * In addition, as a special exception, the copyright holders of
00026  * this module give you permission to combine (via static or
00027  * dynamic linking) this module with free software programs or
00028  * libraries that are released under the GNU LGPL and with code
00029  * included in the standard release of ns-2 under the Apache 2.0
00030  * license or under otherwise-compatible licenses with advertising
00031  * requirements (or modified versions of such code, with unchanged
00032  * license).  You may copy and distribute such a system following the
00033  * terms of the GNU GPL for this module and the licenses of the
00034  * other code concerned, provided that you include the source code of
00035  * that other code when and as the GNU GPL requires distribution of
00036  * source code.
00037  *
00038  * Note that people who make modified versions of this module
00039  * are not obligated to grant this special exception for their
00040  * modified versions; it is their choice whether to do so.  The GNU
00041  * General Public License gives permission to release a modified
00042  * version without this exception; this exception also makes it
00043  * possible to release a modified version which carries forward this
00044  * exception.
00045  *
00046  */
00047 
00048 //
00049 // Multimedia caches
00050 // 
00051 // $Header: /nfs/jade/vint/CVSROOT/ns-2/webcache/mcache.h,v 1.8 2005/09/18 23:33:35 tomh Exp $
00052 
00053 #ifndef ns_mcache_h
00054 #define ns_mcache_h
00055 
00056 #include "config.h"
00057 #include "agent.h"
00058 #include "pagepool.h"
00059 #include "http.h"
00060 #include "rap/media-app.h"
00061 
00062 
00063 //----------------------------------------------------------------------
00064 // Priority list for hit counts at each layer
00065 //----------------------------------------------------------------------
00066 class HitCount : public DoubleListElem {
00067 public:
00068     HitCount(ClientPage *pg, short layer) : 
00069         DoubleListElem(), pg_(pg), layer_(layer), hc_(0) {}
00070 
00071     void update(float hc) { hc_ += hc; }
00072     float hc() { return hc_; }
00073     void reset() { hc_ = 0; }
00074     ClientPage* page() { return pg_; }
00075     short layer() { return layer_; }
00076 
00077     HitCount* next() { return (HitCount *)DoubleListElem::next(); }
00078     HitCount* prev() { return (HitCount *)DoubleListElem::prev(); }
00079 
00080 private:
00081     ClientPage* pg_;    // page
00082     short layer_;       // layer id
00083     float hc_;      // hit count
00084 };
00085 
00086 class HitCountList : public DoubleList {
00087 public:
00088     HitCountList() : DoubleList() {}
00089 
00090     void update(HitCount *h);   // Update layer hit count
00091     void add(HitCount *h);      // Add a new layer
00092 
00093     HitCount* detach_tail() {
00094         HitCount* tmp = (HitCount *)tail_;
00095         if (tmp) {
00096             tail_ = tail_->prev();
00097             tmp->detach();
00098         }
00099         return tmp;
00100     }
00101 
00102     // Debug only
00103     void print();
00104     void check_integrity(); 
00105 };
00106 
00107 
00108 
00109 //----------------------------------------------------------------------
00110 // Multimedia web objects
00111 //----------------------------------------------------------------------
00112 class MediaPage : public ClientPage {
00113 public:
00114     MediaPage(const char *n, int s, double mt, double et, double a, int l);
00115     virtual ~MediaPage();
00116 
00117     virtual WebPageType type() const { return MEDIA; }
00118     virtual void print_info(char *buf);
00119     int num_layer() const { return num_layer_; }
00120 
00121     HitCount* get_hit_count(int layer) { 
00122         assert((layer >= 0) && (layer < num_layer_));
00123         return hc_[layer]; 
00124     }
00125     void hit_layer(int layer) {
00126         assert((layer >= 0) && (layer < num_layer_));
00127         hc_[layer]->update((double)(layer_[layer].length()*num_layer_)
00128                    / (double)size_); 
00129     }
00130 
00131     int layer_size(int layer) { 
00132         assert((layer >= 0) && (layer < num_layer_));
00133         return layer_[layer].length();
00134     }
00135     void add_segment(int layer, const MediaSegment& s);
00136     int evict_tail_segment(int layer, int size);
00137 
00138     void add_layer(int layer) {
00139         assert((layer >= 0) && (layer < num_layer_));
00140         num_layer_ = (num_layer_ < layer) ? layer : num_layer_;
00141     }
00142     char* print_layer(int layer) {
00143         assert((layer >= 0) && (layer < num_layer_));
00144         return layer_[layer].dump2buf();
00145     }
00146     MediaSegmentList is_available(int layer, const MediaSegment& s) {
00147         assert((layer >= 0) && (layer < MAX_LAYER));
00148         return layer_[layer].check_holes(s);
00149     }
00150     // Return a media segment which is the closest one after 's'.
00151     // Used by MediaApps to request data.
00152     // Do NOT check if layer >= num_layer_. If it's empty, 
00153     // an empty MediaSegment will be returned. 
00154     MediaSegment next_available(int layer, const MediaSegment& s) {
00155         assert((layer >= 0) && (layer < MAX_LAYER));
00156         return layer_[layer].get_nextseg(s);
00157     }
00158     MediaSegment next_overlap(int layer, const MediaSegment& s) {
00159         assert((layer >= 0) && (layer < MAX_LAYER));
00160         MediaSegment s1 = layer_[layer].get_nextseg(s);
00161         if ((s1.end() <= s.start()) || (s1.start() >= s.end())) {
00162             MediaSegment s;
00163             if (s1.is_last())
00164                 s.set_last();
00165             return s;
00166         } else
00167             return s1;
00168     }
00169 
00170     enum {FETCHLOCK = 1, XMITLOCK = 2};
00171 
00172     // 1st type of lock: it is being fetched from the server
00173     void lock() { locked_ |= FETCHLOCK; }
00174     void unlock() { locked_ &= ~FETCHLOCK; }
00175     int is_locked() { return (locked_ & FETCHLOCK); }
00176     // 2nd type of lock: it is being transmitted to a client
00177     void tlock() { locked_ |= XMITLOCK; }
00178     void tunlock() { locked_ &= ~XMITLOCK; }
00179     int is_tlocked() { return (locked_ & XMITLOCK); }
00180 
00181     // Whether all layers are marked as "completed"
00182     int is_complete(); 
00183     // Set all layers as "completed"
00184     void set_complete();
00185 
00186     // Given the number of layers, evenly distribute the size among all
00187     // layers and create all segments.
00188     void create();
00189     int realsize() const { return realsize_; }
00190 
00191 protected:
00192     void set_complete_layer(int layer) {
00193         flags_[layer] = 1;
00194     }
00195     int is_complete_layer(int layer) {
00196         return flags_[layer] == 1; 
00197     }
00198 
00199     MediaSegmentList layer_[MAX_LAYER];
00200     int flags_[MAX_LAYER]; // If 1, marks the layer as completed
00201     HitCount* hc_[MAX_LAYER];
00202     int num_layer_; 
00203     int locked_;  // If 1, then no segment can be replaced
00204     int realsize_; // The size of stream data in this page.
00205 };
00206 
00207 // XXX Later we should add a generic replacement algorithm hook into 
00208 // ClientPagePool. But now we'll leave it there and get this media 
00209 // page pool work first. 
00210 
00211 // ClientPagePool enhanced with support for multimedia objects, and 
00212 // with replacement algorithms
00213 class MClientPagePool : public ClientPagePool {
00214 public:
00215     MClientPagePool();
00216 
00217     virtual ClientPage* enter_page(int argc, const char*const* argv);
00218     virtual int remove_page(const char *name);
00219     virtual int force_remove(const char *name);
00220 
00221     int add_segment(const char *name, int layer, const MediaSegment& s);
00222     void hc_update(const char *name, int max_layer);
00223 
00224     int maxsize() { return max_size_; }
00225     int usedsize() { return used_size_; }
00226 
00227     void fill_page(const char* pgname);
00228 
00229     // Debug only
00230     void dump_hclist() { hclist_.print(); }
00231 
00232 protected:
00233     virtual int command(int argc, const char*const* argv);
00234     virtual int cache_replace(ClientPage* page, int size);
00235 
00236     // Fine-grain replacement
00237     int repl_finegrain(ClientPage* p, int size);
00238     int repl_atomic(ClientPage* p, int size);
00239 
00240     // XXX Should change to quad_t, or use MB as unit
00241     int max_size_;      // PagePool size
00242     int used_size_;     // Available space size
00243     HitCountList hclist_; 
00244     // Replacement style
00245     enum { FINEGRAIN, ATOMIC } repl_style_;
00246 };
00247 
00248 // Provide page data and generate requests for servers and clients
00249 class MediaPagePool : public PagePool {
00250 public:
00251     MediaPagePool();
00252 protected:
00253     virtual int command(int argc, const char*const* argv);
00254     int layer_; // Number of layers of pages
00255     int *size_;     // Page sizes
00256     RandomVariable *rvReq_;
00257 };
00258 
00259 
00260 
00261 //--------------------
00262 // Multimedia caches
00263 //--------------------
00264 
00265 // Plain multimedia cache, which can interface with RapAgent
00266 class MediaCache : public HttpCache {
00267 public:
00268     MediaCache();
00269     ~MediaCache();
00270 
00271     // Handle app-specific data in C++
00272     virtual void process_data(int size, AppData* data);
00273     // Handle data request from RAP
00274     virtual AppData* get_data(int& size, AppData* data);
00275 
00276 protected:
00277     virtual int command(int argc, const char*const* argv);
00278 
00279     // Do we need to maintain links to MediaApp?? I doubt not
00280     // MediaApp* mapp_; // An array of incoming/outgoing RAP agents
00281     MClientPagePool* mpool() { return (MClientPagePool *)pool_; }
00282 
00283     // Information and statistics related to clients
00284     struct RegInfo {
00285         RegInfo() : client_(NULL), hl_(-1) {
00286             memset(pb_, 0, sizeof(unsigned int)*MAX_LAYER);
00287             memset(db_, 0, sizeof(unsigned int)*MAX_LAYER);
00288             memset(eb_, 0, sizeof(unsigned int)*MAX_LAYER);
00289         }
00290         ~RegInfo() {
00291             for (int i = 0; i < MAX_LAYER; i++)
00292                 pref_[i].destroy();
00293         }
00294 
00295         char name_[20];
00296         HttpApp* client_;
00297         int hl_;        // Highest layer this client has asked
00298         // Prefetched bytes
00299         unsigned int pb_[MAX_LAYER]; 
00300         // Prefetched bytes that were delivered
00301         unsigned int eb_[MAX_LAYER];
00302         // Total delivered bytes
00303         unsigned int db_[MAX_LAYER];
00304         MediaSegmentList pref_[MAX_LAYER];
00305 
00306         // Return the number of prefetched bytes in the given segment
00307         void add_pref(int layer, const MediaSegment& s) {
00308             assert((layer >= 0) && (layer < MAX_LAYER));
00309             pref_[layer].add(s);
00310         }
00311         int pref_size(int layer, const MediaSegment &s) const { 
00312             assert((layer >= 0) && (layer < MAX_LAYER));
00313             return pref_[layer].overlap_size(s);
00314         }
00315     };
00316     Tcl_HashTable *cmap_;   // client map
00317 
00318     // Prefetching/No-prefetching/Offline-prefetching flag
00319     enum {NOPREF, ONLINE_PREF, OFFLINE_PREF} pref_style_;
00320 };
00321 
00322 
00323 //----------------------------------------------------------------------
00324 // Multimedia web client
00325 //----------------------------------------------------------------------
00326 class MediaClient : public HttpClient {
00327 public:
00328     MediaClient() : HttpClient() {}
00329     virtual void process_data(int size, AppData* data);
00330     virtual int command(int argc, const char*const* argv);
00331 private:
00332     MClientPagePool* mpool() { return (MClientPagePool *)pool_; }
00333 };
00334 
00335 
00336 
00337 // Helper data structure
00338 
00339 template <class T> class Queue; // forward declaration
00340 
00341 template <class T> class QueueElem {
00342 public:
00343         QueueElem(T* d) : next_(0), data_(d) {}
00344 
00345         QueueElem<T>* next() const { return next_; }
00346         T* data() const { return data_; }
00347         void detachData() { data_ = NULL; }
00348         void append(QueueElem<T>* e) {
00349                 e->next_ = next_;
00350                 next_ = e;
00351         }
00352 
00353 protected:
00354         QueueElem<T>* next_;
00355         T* data_;
00356     friend class Queue<T>; 
00357 };
00358 
00359 template <class T> class Queue {
00360 public:
00361         Queue() : head_(0), tail_(0), size_(0) {}
00362         virtual ~Queue() {
00363                 QueueElem<T> *p = head_, *q;
00364                 while (p != NULL) {
00365                         q = p;
00366                         p = p->next();
00367                         delete q;
00368                 }
00369                 head_ = NULL;
00370         }
00371         virtual void reset() {
00372                 QueueElem<T> *p = head_, *q;
00373                 while (p != NULL) {
00374                         q = p;
00375                         p = p->next();
00376                         delete q;
00377                 }
00378                 head_ = NULL;
00379         }
00380         virtual void destroy() {
00381                 QueueElem<T> *p = head_, *q;
00382                 while (p != NULL) {
00383                         q = p;
00384                         p = p->next();
00385                         delete q->data();
00386                         delete q;
00387                 }
00388                 head_ = NULL;
00389         }
00390 
00391         void enqueue(QueueElem<T> *e) {
00392                 if (tail_ == 0)
00393                         head_ = tail_ = e;
00394                 else {
00395                         tail_->append(e);
00396             tail_ = e;
00397         }
00398                 size_++;
00399         }
00400         QueueElem<T>* dequeue() {
00401                 QueueElem<T> *p = head_;
00402                 if (head_ != 0) 
00403                         head_ = head_->next();
00404                 if (head_ == 0)
00405                         tail_ = 0;
00406                 p->next_ = 0;
00407                 size_--;
00408         if (size_ == 0) 
00409             assert((head_ == 0) && (tail_ == 0));
00410                 return p;
00411         }
00412     void detach(QueueElem<T>* e) {
00413         assert(head_ != 0);
00414         if (head_ == e) {
00415             dequeue();
00416             return;
00417         }
00418         QueueElem<T> *p = head_;
00419         while (p != NULL) {
00420             if (p->next_ != e)
00421                 p = p->next_;
00422             else
00423                 break;
00424         }
00425         assert(p != NULL);
00426         p->next_ = e->next_;
00427         if (tail_ == e)
00428             tail_ = p;
00429         size_--;
00430         if (size_ == 0) 
00431             assert((head_ == 0) && (tail_ == 0));
00432     }
00433         QueueElem<T>* getHead() { return head_; }
00434     int is_empty() const { return (size_ == 0); }
00435     int size() const { return size_; }
00436 
00437 protected:
00438         QueueElem<T> *head_, *tail_;
00439         int size_;
00440 };
00441 
00442 
00443 
00444 //----------------------------------------------------------------------
00445 // Multimedia server
00446 //----------------------------------------------------------------------
00447 class MediaServer : public HttpServer {
00448 public:
00449     MediaServer();
00450     ~MediaServer();
00451     virtual AppData* get_data(int& size, AppData* d);
00452 
00453 protected:
00454     virtual int command(int argc, const char*const* argv);
00455     MediaSegment get_next_segment(MediaRequest *r, Application*& ci);
00456 
00457     // Prefetching list
00458     struct RegInfo {
00459         char name_[20];
00460         HttpApp* client_;
00461     };
00462     struct PrefInfo {
00463         MediaSegmentList* sl_;
00464         Application* conid_;
00465     };
00466     typedef Queue<PrefInfo> PrefInfoQ;
00467     typedef QueueElem<PrefInfo> PrefInfoE;
00468     PrefInfoE* find_prefinfo(PrefInfoQ* q, Application* conid) {
00469         for (PrefInfoE *e = q->getHead(); e != NULL; e = e->next())
00470             if (e->data()->conid_ == conid)
00471                 return e;
00472         return NULL;
00473     }
00474 
00475     Tcl_HashTable *pref_; // Mapping <cache>:<pagenum> to PrefInfoQ
00476     Tcl_HashTable *cmap_; // Mapping MediaApps to clients
00477 
00478     PrefInfoQ* get_piq(const char* pgname, HttpApp* client) {
00479         PageID id;
00480         ClientPage::split_name(pgname, id);
00481         id.s_ = client;
00482         Tcl_HashEntry* he = 
00483             Tcl_FindHashEntry(pref_, (const char*)&id);
00484         if (he == NULL) 
00485             return NULL;
00486         return (PrefInfoQ*)Tcl_GetHashValue(he);
00487     }
00488     RegInfo* get_reginfo(Application* app) {
00489         Tcl_HashEntry *he = 
00490             Tcl_FindHashEntry(cmap_, (const char *)app);
00491         if (he == NULL) {
00492             fprintf(stderr, "Unknown connection!\n");
00493             abort();
00494         } 
00495         return (RegInfo *)Tcl_GetHashValue(he);
00496     }
00497 };
00498 
00499 
00500 #endif // ns_mcache_h

Generated on Tue Mar 6 16:47:47 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6