📄 mcache.cc
字号:
abort(); return 0; // Make msvc happy}int MClientPagePool::repl_finegrain(ClientPage *, int size){ // Traverse through hit count table, evict segments from the tail // of a layer with minimum hit counts HitCount *h, *p; int sz, totalsz = 0; // Repeatedly evict pages/segments until get enough space h = (HitCount*)hclist_.tail(); while (h != NULL) { MediaPage *pg = (MediaPage *)h->page(); // XXX Don't touch locked pages if (pg->is_tlocked() || pg->is_locked()) { h = h->prev(); continue; } // Try to get "size" space by evicting other segments sz = pg->evict_tail_segment(h->layer(), size); // Decrease the cache used space used_size_ -= sz; totalsz += sz; // If we have not got enough space, we must have got rid of // the entire layer assert((sz == size) || ((sz < size) && (pg->layer_size(h->layer()) == 0))); // If we don't have anything of this layer left, get rid of // the hit count record. // XXX Must do this BEFORE removing the page p = h; h = h->prev(); if (pg->layer_size(p->layer()) == 0) { // XXX Should NEVER delete a hit count record!! // A hit count record is ONLY deleted when the page // is deleted (evicted from cache: ~MediaPage()) hclist_.detach(p); p->reset(); } // Furthermore, if the page has nothing left, get rid of it if (pg->realsize() == 0) { // NOTE: we do not manually remove hit counts of // this page because if its realsize is 0, all // hit count records must have already been // detached from the page. char tmp[HTTP_MAXURLLEN]; pg->name(tmp);#if 0 fprintf(stderr, "At time %g, fine-grain evicted page %s\n", Scheduler::instance().clock(), tmp); fprintf(stderr, "Hit count list: \n"); hclist_.print(); fprintf(stderr, "---------------------------------------\n\n");#endif // Then the hit count record will be deleted in here remove_page(tmp); } // If we've got enough space, return; otherwise continue if (sz >= size) return totalsz; size -= sz; // Evict to fill the rest } fprintf(stderr, "Cache replacement cannot get enough space.\n"); abort(); return 0; // Make msvc happy}// Clean all hit count record of a page regardless of whether it's in the // hit count list. Used when hclist_ is not used at all, e.g., by MediaClient.int MClientPagePool::force_remove(const char *name){ // XXX Bad hack. Needs to integrate this into ClientPagePool. ClientPage *pg = (ClientPage*)get_page(name); // We should not remove a non-existent page!! assert(pg != NULL); if (pg->type() == MEDIA) { HitCount *p; MediaPage *q = (MediaPage*)pg; used_size_ -= q->realsize(); for (int i = 0; i < q->num_layer(); i++) { p = q->get_hit_count(i); hclist_.detach(p); } } else if (pg->type() == HTML) used_size_ -= pg->size(); return ClientPagePool::remove_page(name);}int MClientPagePool::remove_page(const char *name){ // XXX Bad hack. Needs to integrate this into ClientPagePool. ClientPage *pg = (ClientPage*)get_page(name); // We should not remove a non-existent page!! assert(pg != NULL); if (pg->type() == MEDIA) used_size_ -= ((MediaPage *)pg)->realsize(); else if (pg->type() == HTML) used_size_ -= pg->size(); return ClientPagePool::remove_page(name);}//------------------------------------------------------------// MediaPagePool// Generate requests and pages for clients and servers //------------------------------------------------------------static class MediaPagePoolClass : public TclClass {public: MediaPagePoolClass() : TclClass("PagePool/Media") {} TclObject* create(int, const char*const*) { return (new MediaPagePool()); }} class_mediapagepool_agent;MediaPagePool::MediaPagePool() : PagePool(){ size_ = NULL; duration_ = 0; layer_ = 1;}// For now, only one page, fixed size, fixed layerint MediaPagePool::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "get-poolsize") == 0) { 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) { // Generating requested page id if (rvReq_ == NULL) { tcl.add_errorf("no page id ranvar."); return TCL_ERROR; } int p = (int)rvReq_->value(); assert((p >= 0) && (p < num_pages_)); tcl.resultf("%d", p); return TCL_OK; } else if (strcmp(argv[1], "is-media-page") == 0) { // XXX Currently all pages are media pages. Should // be able to allow both normal pages and media pages // in the future tcl.result("1"); return TCL_OK; } else if (strcmp(argv[1], "get-layer") == 0) { // XXX Currently all pages have the same number of // layers. Should be able to change this in future. tcl.resultf("%d", layer_); return TCL_OK; } else if (strcmp(argv[1], "set-start-time") == 0) { double st = strtod(argv[2], NULL); start_time_ = st; end_time_ = st + duration_; return TCL_OK; } else if (strcmp(argv[1], "set-duration") == 0) { // XXX Need this info to set page mod time!! duration_ = atoi(argv[2]); end_time_ = start_time_ + duration_; return TCL_OK; } else if (strcmp(argv[1], "gen-init-modtime") == 0) { // XXX We are not interested in page consistency here, // so never change this page. tcl.resultf("%d", -1); return TCL_OK; } else if (strcmp(argv[1], "gen-size") == 0) { int pagenum = atoi(argv[2]); if (pagenum >= num_pages_) { tcl.add_errorf("Invalid page id %d", pagenum); return TCL_ERROR; } tcl.resultf("%d", size_[pagenum]); return TCL_OK; } else if (strcmp(argv[1], "set-layer") == 0) { layer_ = atoi(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "set-num-pages") == 0) { if (size_ != NULL) { tcl.add_errorf("can't change number of pages"); return TCL_ERROR; } num_pages_ = atoi(argv[2]); size_ = new int[num_pages_]; return TCL_OK; } else if (strcmp(argv[1], "ranvar-req") == 0) { rvReq_ = (RandomVariable*)TclObject::lookup(argv[2]); return TCL_OK; } } else if (argc == 4) { if (strcmp(argv[1], "gen-modtime") == 0) { // This should never be called, because we never // deals with page modifications!! fprintf(stderr, "%s: gen-modtime called!\n", name()); abort(); } else if (strcmp(argv[1], "set-pagesize") == 0) { // <pagepool> set-pagesize <pagenum> <size> int pagenum = atoi(argv[2]); if (pagenum >= num_pages_) { tcl.add_errorf("Invalid page id %d", pagenum); return TCL_ERROR; } size_[pagenum] = atoi(argv[3]); return TCL_OK; } } return PagePool::command(argc, argv);}//----------------------------------------------------------------------// PagePool that generates requests using the SURGE model//// Part of the code by Paul Barford (barford@cs.bu.edu).// Copyright (c) 1997 Trustees of Boston University//// Allow two options: (1) setting if all pages are media page or normal// HTTP pages; (2) average page size//----------------------------------------------------------------------// static class SurgePagePoolClass : public TclClass {// public:// SurgePagePoolClass() : TclClass("PagePool/Surge") {}// TclObject* create(int, const char*const*) {// return (new SurgePagePool());// }// } class_surgepagepool_agent;// SurgePagePool::SurgePagePool() : PagePool()// {// }//----------------------------------------------------------------------// Multimedia web applications: cache, etc.//----------------------------------------------------------------------static class MediaCacheClass : public TclClass {public: MediaCacheClass() : TclClass("Http/Cache/Media") {} TclObject* create(int, const char*const*) { return (new MediaCache()); }} class_mediacache;// By default we use online prefetchingMediaCache::MediaCache() : pref_style_(ONLINE_PREF){ cmap_ = new Tcl_HashTable; Tcl_InitHashTable(cmap_, TCL_ONE_WORD_KEYS);}MediaCache::~MediaCache(){ Tcl_HashEntry *he; Tcl_HashSearch hs; if (cmap_) { for (he = Tcl_FirstHashEntry(cmap_, &hs); he != NULL; he = Tcl_NextHashEntry(&hs)) delete (RegInfo*)Tcl_GetHashValue(he); Tcl_DeleteHashTable(cmap_); delete cmap_; }}AppData* MediaCache::get_data(int& size, AppData* req){ assert(req != NULL); if (req->type() != MEDIA_REQUEST) { return HttpApp::get_data(size, req); } MediaRequest *r = (MediaRequest *)req; // Get statistics block for the requestor Tcl_HashEntry *he = Tcl_FindHashEntry(cmap_, (const char *)(r->app())); assert(he != NULL); RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he); // Process request if (r->request() == MEDIAREQ_GETSEG) { // Get a new data segment MediaPage* pg = (MediaPage*)pool_->get_page(r->name()); assert(pg != NULL); MediaSegment s1(r->st(), r->et()); MediaSegment s2 = pg->next_overlap(r->layer(), s1); HttpMediaData *p; if (s2.datasize() == 0) { // No more data available for this layer, allocate // an ADU with data size 0 to signal the end // of transmission for this layer size = 0; p = new HttpMediaData(name(), r->name(), r->layer(), 0, 0); } else { size = s2.datasize(); p = new HttpMediaData(name(), r->name(), r->layer(), s2.start(), s2.end()); } // XXX If we are still receiving the stream, don't // ever say that this is the last segment. If the // page is not locked, it's still possible that we // return a NULL segment because the requested one // is not available. Don't set the 'LAST' flag in this // case. if (s2.is_last()) { p->set_last(); if (!pg->is_locked() && (s2.datasize() == 0) && (r->layer() == 0)) p->set_finish(); } //---------------------------------------- // Update statistics of this connection //---------------------------------------- // Update the highest layer that this client has requested if (ri->hl_ < r->layer()) ri->hl_ = r->layer(); if (size > 0) { // Update total delivered bytes ri->db_[r->layer()] += size; // Update prefetched bytes that've been delivered ri->eb_[r->layer()] += ri->pref_size(r->layer(), s2); } return p; } else if (r->request() == MEDIAREQ_CHECKSEG) { // If we are not doing online prefetching, return nothing if (pref_style_ != ONLINE_PREF) return NULL; // Check the availability of a new data segment // And refetch if it is not available MediaPage* pg = (MediaPage*)pool_->get_page(r->name()); assert(pg != NULL); if (pg->is_locked()) // If we are during the first retrieval, don't prefetch return NULL; MediaSegmentList ul = pg->is_available(r->layer(), MediaSegment(r->st(),r->et())); if (ul.length() == 0) // All segments are available return NULL; // Otherwise do prefetching on these "holes" char *buf = ul.dump2buf(); Tcl::instance().evalf("%s pref-segment %s %s %d %s", name(), r->app()->name(), r->name(), r->layer(), buf);// log("E PREF p %s l %d %s\n", r->name(), r->layer(), buf); delete []buf; ul.destroy(); // Update the highest layer that this client has requested Tcl_HashEntry *he = Tcl_FindHashEntry(cmap_, (const char *)(r->app())); assert(he != NULL); RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he); if (ri->hl_ < r->layer()) ri->hl_ = r->layer(); return NULL; } fprintf(stderr, "MediaCache %s gets an unknown MediaRequest type %d\n", name(), r->request()); abort(); return NULL; // Make msvc happy}// Add received media segment into page poolvoid MediaCache::process_data(int size, AppData* data) { switch (data->type()) { case MEDIA_DATA: { HttpMediaData* d = (HttpMediaData*)data; // Cache this segment, do replacement if necessary if (mpool()->add_segment(d->page(), d->layer(), MediaSegment(*d)) == -1) { fprintf(stderr, "MediaCache %s gets a segment for an " "unknown page %s\n", name(), d->page()); abort(); } if (d->is_pref()) { // Update total prefetched bytes Tcl_HashEntry *he = Tcl_FindHashEntry(cmap_, (const char*)(d->conid())); // Client-cache-server disconnection procedure: // (1) client disconnects from cache, then // (2) cache disconnects from server and shuts down // prefetching channel. // Therefore, after client disconnects, the cache // may still receive a few prefetched segments. // Ignore those because we no longer keep statistics // about the torn-down connection. if (he != NULL) { RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he); ri->add_pref(d->layer(), MediaSegment(*d)); ri->pb_[d->layer()] += d->datasize(); } } // XXX debugging only#if 1 log("E RSEG p %s l %d s %d e %d z %d f %d\n", d->page(), d->layer(), d->st(), d->et(), d->datasize(), d->is_pref());#endif break; } default: HttpCache::process_data(size, data); }}int MediaCache::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "get-pref-style") == 0) { switch (pref_style_) { case NOPREF: tcl.result("NOPREF"); break; case ONLINE_PREF: tcl.result("ONLINE_PREF"); break; case OFFLINE_PREF: tcl.result("OFFLINE_PREF"); break; default: fprintf(stderr, "Corrupted prefetching style %d", pref_style_); return TCL_ERROR; } return TCL_OK; } } else if (argc == 3) { if (strcmp(argv[1], "offline-complete") == 0) { // Delete whatever segments in the given page, // make it complete. Used by offline prefetching ClientPage *pg = mpool()->get_page(argv[2]); if (pg == NULL) // XXX It's possible that we've already kicked // it out of the cache. Do nothing. return TCL_OK; assert(pg->type() == MEDIA); assert(!((MediaPage*)pg)->is_locked()); mpool()->fill_page(argv[2]); return TCL_OK; } else if (strcmp(argv[1], "set-pref-style") == 0) { // Set prefetching style // <obj> set-pref-style <style> // // style can be: NOPREF, ONLINE_PREF, OFFLINE_PREF if (strcmp(argv[2], "NOPREF") == 0) pref_style_ = NOPREF; else if (strcmp(argv[2], "ONLINE_PREF") == 0) pref_style_ = ONLINE_PREF; else if (strcmp(argv[2], "OFFLINE_PREF") == 0) pref_style_ = OFFLINE_PREF; else { fprintf(stderr, "Wrong prefetching style %s", argv[2]); return TCL_ERROR; } return TCL_OK; } else if (strcmp(argv[1], "dump-page") == 0) { // Dump segments of a given page ClientPage *p=(ClientPage*)mpool()->get_page(argv[2]); if (p->type() != MEDIA) // Do nothing for non-media pages return TCL_OK; MediaPage *pg = (MediaPage *)p; char *buf; for (int i = 0; i < pg->num_layer(); i++) { buf = pg->print_layer(i); if (strlen(buf) > 0) log("E SEGS p %s l %d %s\n", argv[2], i, buf); delete []buf; } return TCL_OK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -