00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <assert.h>
00054 #include <stdio.h>
00055
00056 #include "rap/media-app.h"
00057 #include "mcache.h"
00058
00059
00060 MediaPage::MediaPage(const char *n, int s, double mt, double et,
00061 double a, int l) :
00062 ClientPage(n, s, mt, et, a), num_layer_(l), locked_(0), realsize_(0)
00063 {
00064 for (int i = 0; i < num_layer_; i++) {
00065 hc_[i] = new HitCount(this, i);
00066 flags_[i] = 0;
00067 }
00068 }
00069
00070 MediaPage::~MediaPage()
00071 {
00072 int i;
00073 for (i = 0; i < num_layer_; i++) {
00074
00075
00076
00077 assert((hc_[i]->prev() == NULL) && (hc_[i]->next() == NULL));
00078 delete hc_[i];
00079
00080 layer_[i].destroy();
00081 }
00082 }
00083
00084 void MediaPage::print_info(char *buf)
00085 {
00086 ClientPage::print_info(buf);
00087 buf += strlen(buf);
00088 sprintf(buf, " pgtype MEDIA layer %d", num_layer_);
00089 }
00090
00091
00092 void MediaPage::create()
00093 {
00094 assert((num_layer_ >= 0) && (num_layer_ < MAX_LAYER));
00095 int i, sz = size_ / num_layer_;
00096 for (i = 0; i < num_layer_; i++) {
00097
00098 layer_[i].destroy();
00099 add_segment(i, MediaSegment(0, sz));
00100 set_complete_layer(i);
00101 }
00102 realsize_ = size_;
00103 }
00104
00105 void MediaPage::add_segment(int layer, const MediaSegment& s)
00106 {
00107 assert((layer >= 0) && (layer < MAX_LAYER));
00108 layer_[layer].add(s);
00109 realsize_ += s.datasize();
00110 if (s.is_last())
00111 set_complete_layer(layer);
00112 }
00113
00114 int MediaPage::is_complete()
00115 {
00116
00117
00118 for (int i = 0; i < num_layer_; i++)
00119 if (!is_complete_layer(i) && (layer_[i].length() > 0))
00120 return 0;
00121 return 1;
00122 }
00123
00124 void MediaPage::set_complete()
00125 {
00126 for (int i = 0; i < num_layer_; i++)
00127 set_complete_layer(i);
00128 }
00129
00130
00131 int MediaPage::evict_tail_segment(int layer, int size)
00132 {
00133 if (is_locked() || is_tlocked())
00134 return 0;
00135
00136 assert((layer >= 0) && (layer < MAX_LAYER));
00137
00138 #if 0
00139 char buf[20];
00140 name(buf);
00141 fprintf(stderr, "Page %s evicted layer %d: ", buf, layer);
00142 #endif
00143 int sz = layer_[layer].evict_tail(size);
00144 realsize_ -= sz;
00145
00146 #if 0
00147 fprintf(stderr, "\n");
00148 #endif
00149 return sz;
00150 }
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 void HitCountList::update(HitCount *h)
00161 {
00162 HitCount *tmp = h->prev();
00163 if ((tmp != NULL) && (tmp->hc() < h->hc())) {
00164
00165 detach(h);
00166 while ((tmp != NULL) && (tmp->hc() < h->hc())) {
00167 if ((tmp->page() == h->page()) &&
00168 (tmp->layer() < h->layer()))
00169
00170
00171 break;
00172 tmp = tmp->prev();
00173 }
00174 if (tmp == NULL)
00175
00176 insert(h, head_);
00177 else
00178 append(h, tmp);
00179 } else if ((h->next() != NULL) && (h->hc() < h->next()->hc())) {
00180
00181 tmp = h->next();
00182 detach(h);
00183 while ((tmp != NULL) && (h->hc() < tmp->hc())) {
00184 if ((h->page() == tmp->page()) &&
00185 (h->layer() < tmp->layer()))
00186
00187
00188 break;
00189 tmp = tmp->next();
00190 }
00191 if (tmp == NULL)
00192
00193 append(h, tail_);
00194 else
00195 insert(h, tmp);
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 }
00211
00212
00213 void HitCountList::check_integrity()
00214 {
00215 HitCount *p = (HitCount*)head_, *q;
00216 while (p != NULL) {
00217 q = p->next();
00218 while (q != NULL) {
00219
00220 if ((p->page() == q->page()) &&
00221 (p->layer() > q->layer())) {
00222 fprintf(stderr, "Wrong hit count list.\n");
00223 abort();
00224 }
00225 q = q->next();
00226 }
00227 p = p->next();
00228 }
00229 }
00230
00231 void HitCountList::add(HitCount *h)
00232 {
00233 HitCount *tmp = (HitCount*)head_;
00234
00235
00236
00237 while ((tmp != NULL) && (tmp->hc() > h->hc())) {
00238 if ((tmp->page() == h->page()) && (tmp->layer() > h->layer()))
00239 break;
00240 tmp = tmp->next();
00241 }
00242
00243 while ((tmp != NULL) && (tmp->hc() == h->hc()) &&
00244 (tmp->layer() < h->layer()))
00245 tmp = tmp->next();
00246
00247 if (tmp == NULL) {
00248 if (head_ == NULL)
00249 head_ = tail_ = h;
00250 else
00251 append(h, tail_);
00252 return;
00253 } else if ((tmp == head_) &&
00254 ((tmp->hc() < h->hc()) || (tmp->layer() > h->layer()))) {
00255 insert(h, head_);
00256 return;
00257 }
00258
00259
00260
00261 insert(h, tmp);
00262 }
00263
00264
00265 void HitCountList::print()
00266 {
00267 HitCount *p = (HitCount *)head_;
00268 int i = 0;
00269 char buf[20];
00270 while (p != NULL) {
00271 p->page()->name(buf);
00272 fprintf(stderr, "(%s %d %f) ", buf, p->layer(), p->hc());
00273 if (++i % 4 == 0)
00274 printf("\n");
00275 p = p->next();
00276 }
00277 if (i % 4 != 0)
00278 fprintf(stderr, "\n");
00279 }
00280
00281
00282
00283
00284 static class MClientPagePoolClass : public TclClass {
00285 public:
00286 MClientPagePoolClass() : TclClass("PagePool/Client/Media") {}
00287 TclObject* create(int, const char*const*) {
00288 return (new MClientPagePool());
00289 }
00290 } class_mclientpagepool_agent;
00291
00292 MClientPagePool::MClientPagePool() :
00293 used_size_(0), repl_style_(FINEGRAIN)
00294 {
00295 bind("max_size_", &max_size_);
00296 used_size_ = 0;
00297 }
00298
00299 int MClientPagePool::command(int argc, const char*const* argv)
00300 {
00301 if (argc == 3)
00302 if (strcmp(argv[1], "set-repl-style") == 0) {
00303
00304
00305 if (strcmp(argv[2], "FINEGRAIN") == 0)
00306 repl_style_ = FINEGRAIN;
00307 else if (strcmp(argv[2], "ATOMIC") == 0)
00308 repl_style_ = ATOMIC;
00309 else {
00310 fprintf(stderr, "Unknown style %s", argv[3]);
00311 return (TCL_ERROR);
00312 }
00313 return (TCL_OK);
00314 }
00315 return ClientPagePool::command(argc, argv);
00316 }
00317
00318 void MClientPagePool::hc_update(const char *name, int max_layer)
00319 {
00320 MediaPage *pg = (MediaPage*)get_page(name);
00321 assert(pg != NULL);
00322
00323 int i;
00324 HitCount *h;
00325
00326 for (i = 0; i <= max_layer; i++)
00327 pg->hit_layer(i);
00328
00329 for (i = 0; i <= max_layer; i++) {
00330 h = pg->get_hit_count(i);
00331 hclist_.update(h);
00332 }
00333 #if 1
00334 hclist_.check_integrity();
00335 #endif
00336 }
00337
00338
00339
00340 int MClientPagePool::add_segment(const char* name, int layer,
00341 const MediaSegment& s)
00342 {
00343 MediaPage* pg = (MediaPage *)get_page(name);
00344 if (pg == NULL)
00345 return -1;
00346 if (layer >= pg->num_layer()) {
00347 if (s.datasize() == 0)
00348 return 0;
00349 else {
00350 fprintf(stderr,
00351 "MClientPagePool: cannot add a new layer.\n");
00352 abort();
00353 }
00354 }
00355
00356
00357 if (used_size_ + s.datasize() > max_size_) {
00358
00359
00360
00361 cache_replace(pg, s.datasize());
00362
00363 #if 0
00364 fprintf(stderr,
00365 "Replaced for page %s segment (%d %d) layer %d\n",
00366 name, s.start(), s.end(), layer);
00367 #endif
00368 }
00369
00370
00371 used_size_ += s.datasize();
00372
00373
00374 if (pg->layer_size(layer) == 0)
00375 hclist_.add(pg->get_hit_count(layer));
00376
00377
00378 pg->add_segment(layer, s);
00379
00380 return 0;
00381 }
00382
00383 void MClientPagePool::fill_page(const char* pgname)
00384 {
00385 MediaPage *pg = (MediaPage*)get_page(pgname);
00386 used_size_ -= pg->realsize();
00387
00388 pg->lock();
00389 pg->create();
00390
00391 if (used_size_ + pg->size() > max_size_)
00392
00393 cache_replace(pg, pg->size());
00394 used_size_ += pg->size();
00395 pg->unlock();
00396 }
00397
00398 ClientPage* MClientPagePool::enter_page(int argc, const char*const* argv)
00399 {
00400 double mt = -1, et, age = -1, noc = 0;
00401 int size = -1, media_page = 0, layer = -1;
00402 for (int i = 3; i < argc; i+=2) {
00403 if (strcmp(argv[i], "modtime") == 0)
00404 mt = strtod(argv[i+1], NULL);
00405 else if (strcmp(argv[i], "size") == 0)
00406 size = atoi(argv[i+1]);
00407 else if (strcmp(argv[i], "age") == 0)
00408 age = strtod(argv[i+1], NULL);
00409 else if (strcmp(argv[i], "noc") == 0)
00410
00411 noc = 1;
00412 else if (strcmp(argv[i], "pgtype") == 0) {
00413 if (strcmp(argv[i+1], "MEDIA") == 0)
00414 media_page = 1;
00415 } else if (strcmp(argv[i], "layer") == 0)
00416 layer = atoi(argv[i+1]);
00417 }
00418
00419 if ((size < 0) || (media_page && (layer <= 0))) {
00420 fprintf(stderr, "%s: wrong page information %s\n",
00421 name_, argv[2]);
00422 return NULL;
00423 }
00424 et = Scheduler::instance().clock();
00425 ClientPage *pg;
00426 if (media_page)
00427 pg = new MediaPage(argv[2], size, mt, et, age, layer);
00428 else
00429 pg = new ClientPage(argv[2], size, mt, et, age);
00430 if (add_page(pg) < 0) {
00431 delete pg;
00432 return NULL;
00433 }
00434 if (noc)
00435 pg->set_uncacheable();
00436 if (media_page)
00437 ((MediaPage *)pg)->lock();
00438 return pg;
00439 }
00440
00441 int MClientPagePool::cache_replace(ClientPage *pg, int size)
00442 {
00443 switch (repl_style_) {
00444 case FINEGRAIN:
00445 return repl_finegrain(pg, size);
00446 case ATOMIC:
00447 #if 0
00448 char tmp[128];
00449 pg->name(tmp);
00450 fprintf(stderr, "Replaced for page %s size %d\n", tmp, size);
00451 fprintf(stderr, "Used size %d, max size %d\n", used_size_,
00452 max_size_);
00453 #endif
00454 return repl_atomic(pg, size);
00455 default:
00456 fprintf(stderr, "Corrupted replacement style.\n");
00457 abort();
00458 }
00459
00460 return -1;
00461 }
00462
00463 int MClientPagePool::repl_atomic(ClientPage*, int size)
00464 {
00465
00466
00467
00468
00469
00470
00471
00472 HitCount *h, *p;
00473 int sz, totalsz = 0;
00474
00475 h = (HitCount*)hclist_.tail();
00476 while (h != NULL) {
00477 if (h->layer() != 0) {
00478
00479 h = h->prev();
00480 continue;
00481 }
00482 MediaPage *pg = (MediaPage *)h->page();
00483
00484 if (pg->is_tlocked() || pg->is_locked()) {
00485 h = h->prev();
00486 continue;
00487 }
00488 sz = pg->realsize();
00489 totalsz += sz;
00490 char tmp[HTTP_MAXURLLEN];
00491 pg->name(tmp);
00492
00493
00494 p = h->prev();
00495 while ((p != NULL) && (p->page() == h->page()))
00496 p = p->prev();
00497 h = p;
00498
00499 for (int i = 0; i < pg->num_layer(); i++) {
00500 p = pg->get_hit_count(i);
00501 hclist_.detach(p);
00502 }
00503
00504 #if 0
00505 fprintf(stderr, "At time %g, atomic replacement evicted page %s\n",
00506 Scheduler::instance().clock(), tmp);
00507 fprintf(stderr, "Hit count list: \n");
00508 hclist_.print();
00509 fprintf(stderr,"----------------------------------------\n\n");
00510 #endif
00511 remove_page(tmp);
00512 if (sz >= size)
00513 return totalsz;
00514
00515 size -= sz;
00516 }
00517 fprintf(stderr, "Cache replacement cannot get enough space.\n");
00518 abort();
00519 return 0;
00520 }
00521
00522 int MClientPagePool::repl_finegrain(ClientPage *, int size)
00523 {
00524
00525
00526 HitCount *h, *p;
00527 int sz, totalsz = 0;
00528
00529
00530 h = (HitCount*)hclist_.tail();
00531 while (h != NULL) {
00532 MediaPage *pg = (MediaPage *)h->page();
00533
00534 if (pg->is_tlocked() || pg->is_locked()) {
00535 h = h->prev();
00536 continue;
00537 }
00538
00539 sz = pg->evict_tail_segment(h->layer(), size);
00540
00541 used_size_ -= sz;
00542 totalsz += sz;
00543
00544
00545 assert((sz == size) ||
00546 ((sz < size) && (pg->layer_size(h->layer()) == 0)));
00547
00548
00549
00550
00551 p = h;
00552 h = h->prev();
00553 if (pg->layer_size(p->layer()) == 0) {
00554
00555
00556
00557 hclist_.detach(p);
00558 p->reset();
00559 }
00560
00561 if (pg->realsize() == 0) {
00562
00563
00564
00565
00566 char tmp[HTTP_MAXURLLEN];
00567 pg->name(tmp);
00568 #if 0
00569 fprintf(stderr, "At time %g, fine-grain evicted page %s\n",
00570 Scheduler::instance().clock(), tmp);
00571 fprintf(stderr, "Hit count list: \n");
00572 hclist_.print();
00573 fprintf(stderr,
00574 "---------------------------------------\n\n");
00575 #endif
00576
00577 remove_page(tmp);
00578 }
00579
00580 if (sz >= size)
00581 return totalsz;
00582 size -= sz;
00583 }
00584 fprintf(stderr, "Cache replacement cannot get enough space.\n");
00585 abort();
00586 return 0;
00587 }
00588
00589
00590
00591 int MClientPagePool::force_remove(const char *name)
00592 {
00593
00594 ClientPage *pg = (ClientPage*)get_page(name);
00595
00596 assert(pg != NULL);
00597 if (pg->type() == MEDIA) {
00598 HitCount *p;
00599 MediaPage *q = (MediaPage*)pg;
00600 used_size_ -= q->realsize();
00601 for (int i = 0; i < q->num_layer(); i++) {
00602 p = q->get_hit_count(i);
00603 hclist_.detach(p);
00604 }
00605 } else if (pg->type() == HTML)
00606 used_size_ -= pg->size();
00607 return ClientPagePool::remove_page(name);
00608 }
00609
00610 int MClientPagePool::remove_page(const char *name)
00611 {
00612
00613 ClientPage *pg = (ClientPage*)get_page(name);
00614
00615 assert(pg != NULL);
00616 if (pg->type() == MEDIA)
00617 used_size_ -= ((MediaPage *)pg)->realsize();
00618 else if (pg->type() == HTML)
00619 used_size_ -= pg->size();
00620 return ClientPagePool::remove_page(name);
00621 }
00622
00623
00624
00625
00626
00627
00628
00629 static class MediaPagePoolClass : public TclClass {
00630 public:
00631 MediaPagePoolClass() : TclClass("PagePool/Media") {}
00632 TclObject* create(int, const char*const*) {
00633 return (new MediaPagePool());
00634 }
00635 } class_mediapagepool_agent;
00636
00637 MediaPagePool::MediaPagePool() : PagePool()
00638 {
00639 size_ = NULL;
00640 duration_ = 0;
00641 layer_ = 1;
00642 }
00643
00644
00645 int MediaPagePool::command(int argc, const char*const* argv)
00646 {
00647 Tcl& tcl = Tcl::instance();
00648
00649 if (argc == 2) {
00650 if (strcmp(argv[1], "get-poolsize") == 0) {
00651 tcl.resultf("%d", num_pages_);
00652 return TCL_OK;
00653 } else if (strcmp(argv[1], "get-start-time") == 0) {
00654 tcl.resultf("%.17g", start_time_);
00655 return TCL_OK;
00656 } else if (strcmp(argv[1], "get-duration") == 0) {
00657 tcl.resultf("%d", duration_);
00658 return TCL_OK;
00659 }
00660 } else if (argc == 3) {
00661 if (strcmp(argv[1], "gen-pageid") == 0) {
00662
00663 if (rvReq_ == NULL) {
00664 tcl.add_errorf("no page id ranvar.");
00665 return TCL_ERROR;
00666 }
00667 int p = (int)rvReq_->value();
00668 assert((p >= 0) && (p < num_pages_));
00669 tcl.resultf("%d", p);
00670 return TCL_OK;
00671 } else if (strcmp(argv[1], "is-media-page") == 0) {
00672
00673
00674
00675 tcl.result("1");
00676 return TCL_OK;
00677 } else if (strcmp(argv[1], "get-layer") == 0) {
00678
00679
00680 tcl.resultf("%d", layer_);
00681 return TCL_OK;
00682 } else if (strcmp(argv[1], "set-start-time") == 0) {
00683 double st = strtod(argv[2], NULL);
00684 start_time_ = st;
00685 end_time_ = st + duration_;
00686 return TCL_OK;
00687 } else if (strcmp(argv[1], "set-duration") == 0) {
00688
00689 duration_ = atoi(argv[2]);
00690 end_time_ = start_time_ + duration_;
00691 return TCL_OK;
00692 } else if (strcmp(argv[1], "gen-init-modtime") == 0) {
00693
00694
00695 tcl.resultf("%d", -1);
00696 return TCL_OK;
00697 } else if (strcmp(argv[1], "gen-size") == 0) {
00698 int pagenum = atoi(argv[2]);
00699 if (pagenum >= num_pages_) {
00700 tcl.add_errorf("Invalid page id %d", pagenum);
00701 return TCL_ERROR;
00702 }
00703 tcl.resultf("%d", size_[pagenum]);
00704 return TCL_OK;
00705 } else if (strcmp(argv[1], "set-layer") == 0) {
00706 layer_ = atoi(argv[2]);
00707 return TCL_OK;
00708 } else if (strcmp(argv[1], "set-num-pages") == 0) {
00709 if (size_ != NULL) {
00710 tcl.add_errorf("can't change number of pages");
00711 return TCL_ERROR;
00712 }
00713 num_pages_ = atoi(argv[2]);
00714 size_ = new int[num_pages_];
00715 return TCL_OK;
00716 } else if (strcmp(argv[1], "ranvar-req") == 0) {
00717 rvReq_ = (RandomVariable*)TclObject::lookup(argv[2]);
00718 return TCL_OK;
00719 }
00720 } else if (argc == 4) {
00721 if (strcmp(argv[1], "gen-modtime") == 0) {
00722
00723
00724 fprintf(stderr, "%s: gen-modtime called!\n", name());
00725 abort();
00726 } else if (strcmp(argv[1], "set-pagesize") == 0) {
00727
00728 int pagenum = atoi(argv[2]);
00729 if (pagenum >= num_pages_) {
00730 tcl.add_errorf("Invalid page id %d", pagenum);
00731 return TCL_ERROR;
00732 }
00733 size_[pagenum] = atoi(argv[3]);
00734 return TCL_OK;
00735 }
00736 }
00737 return PagePool::command(argc, argv);
00738 }
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769 static class MediaCacheClass : public TclClass {
00770 public:
00771 MediaCacheClass() : TclClass("Http/Cache/Media") {}
00772 TclObject* create(int, const char*const*) {
00773 return (new MediaCache());
00774 }
00775 } class_mediacache;
00776
00777
00778 MediaCache::MediaCache() : pref_style_(ONLINE_PREF)
00779 {
00780 cmap_ = new Tcl_HashTable;
00781 Tcl_InitHashTable(cmap_, TCL_ONE_WORD_KEYS);
00782 }
00783
00784 MediaCache::~MediaCache()
00785 {
00786 Tcl_HashEntry *he;
00787 Tcl_HashSearch hs;
00788 if (cmap_) {
00789 for (he = Tcl_FirstHashEntry(cmap_, &hs); he != NULL;
00790 he = Tcl_NextHashEntry(&hs))
00791 delete (RegInfo*)Tcl_GetHashValue(he);
00792 Tcl_DeleteHashTable(cmap_);
00793 delete cmap_;
00794 }
00795 }
00796
00797 AppData* MediaCache::get_data(int& size, AppData* req)
00798 {
00799 assert(req != NULL);
00800 if (req->type() != MEDIA_REQUEST) {
00801 return HttpApp::get_data(size, req);
00802 }
00803
00804 MediaRequest *r = (MediaRequest *)req;
00805
00806
00807 Tcl_HashEntry *he =
00808 Tcl_FindHashEntry(cmap_, (const char *)(r->app()));
00809 assert(he != NULL);
00810 RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he);
00811
00812
00813 if (r->request() == MEDIAREQ_GETSEG) {
00814
00815 MediaPage* pg = (MediaPage*)pool_->get_page(r->name());
00816 assert(pg != NULL);
00817 MediaSegment s1(r->st(), r->et());
00818 MediaSegment s2 = pg->next_overlap(r->layer(), s1);
00819 HttpMediaData *p;
00820 if (s2.datasize() == 0) {
00821
00822
00823
00824 size = 0;
00825 p = new HttpMediaData(name(), r->name(),
00826 r->layer(), 0, 0);
00827 } else {
00828 size = s2.datasize();
00829 p = new HttpMediaData(name(), r->name(),
00830 r->layer(), s2.start(), s2.end());
00831 }
00832
00833
00834
00835
00836
00837
00838 if (s2.is_last()) {
00839 p->set_last();
00840 if (!pg->is_locked() && (s2.datasize() == 0) &&
00841 (r->layer() == 0))
00842 p->set_finish();
00843 }
00844
00845
00846
00847
00848
00849 if (ri->hl_ < r->layer())
00850 ri->hl_ = r->layer();
00851 if (size > 0) {
00852
00853 ri->db_[r->layer()] += size;
00854
00855 ri->eb_[r->layer()] += ri->pref_size(r->layer(), s2);
00856 }
00857 return p;
00858 } else if (r->request() == MEDIAREQ_CHECKSEG) {
00859
00860 if (pref_style_ != ONLINE_PREF)
00861 return NULL;
00862
00863
00864 MediaPage* pg = (MediaPage*)pool_->get_page(r->name());
00865 assert(pg != NULL);
00866 if (pg->is_locked())
00867
00868 return NULL;
00869 MediaSegmentList ul = pg->is_available(r->layer(),
00870 MediaSegment(r->st(),r->et()));
00871 if (ul.length() == 0)
00872
00873 return NULL;
00874
00875 char *buf = ul.dump2buf();
00876 Tcl::instance().evalf("%s pref-segment %s %s %d %s", name(),
00877 r->app()->name(), r->name(),
00878 r->layer(), buf);
00879
00880 delete []buf;
00881 ul.destroy();
00882
00883
00884 Tcl_HashEntry *he =
00885 Tcl_FindHashEntry(cmap_, (const char *)(r->app()));
00886 assert(he != NULL);
00887 RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he);
00888 if (ri->hl_ < r->layer())
00889 ri->hl_ = r->layer();
00890 return NULL;
00891 }
00892
00893 fprintf(stderr,
00894 "MediaCache %s gets an unknown MediaRequest type %d\n",
00895 name(), r->request());
00896 abort();
00897 return NULL;
00898 }
00899
00900
00901 void MediaCache::process_data(int size, AppData* data)
00902 {
00903 switch (data->type()) {
00904 case MEDIA_DATA: {
00905 HttpMediaData* d = (HttpMediaData*)data;
00906
00907 if (mpool()->add_segment(d->page(), d->layer(),
00908 MediaSegment(*d)) == -1) {
00909 fprintf(stderr, "MediaCache %s gets a segment for an "
00910 "unknown page %s\n", name(), d->page());
00911 abort();
00912 }
00913 if (d->is_pref()) {
00914
00915 Tcl_HashEntry *he = Tcl_FindHashEntry(cmap_,
00916 (const char*)(d->conid()));
00917
00918
00919
00920
00921
00922
00923
00924
00925 if (he != NULL) {
00926 RegInfo *ri = (RegInfo *)Tcl_GetHashValue(he);
00927 ri->add_pref(d->layer(), MediaSegment(*d));
00928 ri->pb_[d->layer()] += d->datasize();
00929 }
00930 }
00931
00932 #if 1
00933 log("E RSEG p %s l %d s %d e %d z %d f %d\n",
00934 d->page(), d->layer(), d->st(), d->et(), d->datasize(),
00935 d->is_pref());
00936 #endif
00937 break;
00938 }
00939 default:
00940 HttpCache::process_data(size, data);
00941 }
00942 }
00943
00944 int MediaCache::command(int argc, const char*const* argv)
00945 {
00946 Tcl& tcl = Tcl::instance();
00947 if (argc == 2) {
00948 if (strcmp(argv[1], "get-pref-style") == 0) {
00949 switch (pref_style_) {
00950 case NOPREF:
00951 tcl.result("NOPREF");
00952 break;
00953 case ONLINE_PREF:
00954 tcl.result("ONLINE_PREF");
00955 break;
00956 case OFFLINE_PREF:
00957 tcl.result("OFFLINE_PREF");
00958 break;
00959 default:
00960 fprintf(stderr,
00961 "Corrupted prefetching style %d",
00962 pref_style_);
00963 return TCL_ERROR;
00964 }
00965 return TCL_OK;
00966 }
00967 } else if (argc == 3) {
00968 if (strcmp(argv[1], "offline-complete") == 0) {
00969
00970
00971 ClientPage *pg = mpool()->get_page(argv[2]);
00972 if (pg == NULL)
00973
00974
00975 return TCL_OK;
00976 assert(pg->type() == MEDIA);
00977 assert(!((MediaPage*)pg)->is_locked());
00978 mpool()->fill_page(argv[2]);
00979 return TCL_OK;
00980 } else if (strcmp(argv[1], "set-pref-style") == 0) {
00981
00982
00983
00984
00985 if (strcmp(argv[2], "NOPREF") == 0)
00986 pref_style_ = NOPREF;
00987 else if (strcmp(argv[2], "ONLINE_PREF") == 0)
00988 pref_style_ = ONLINE_PREF;
00989 else if (strcmp(argv[2], "OFFLINE_PREF") == 0)
00990 pref_style_ = OFFLINE_PREF;
00991 else {
00992 fprintf(stderr, "Wrong prefetching style %s",
00993 argv[2]);
00994 return TCL_ERROR;
00995 }
00996 return TCL_OK;
00997 } else if (strcmp(argv[1], "dump-page") == 0) {
00998
00999 ClientPage *p=(ClientPage*)mpool()->get_page(argv[2]);
01000 if (p->type() != MEDIA)
01001
01002 return TCL_OK;
01003 MediaPage *pg = (MediaPage *)p;
01004 char *buf;
01005 for (int i = 0; i < pg->num_layer(); i++) {
01006 buf = pg->print_layer(i);
01007 if (strlen(buf) > 0)
01008 log("E SEGS p %s l %d %s\n", argv[2],
01009 i, buf);
01010 delete []buf;
01011 }
01012 return TCL_OK;
01013 } else if (strcmp(argv[1], "stream-received") == 0) {
01014
01015 MediaPage *pg = (MediaPage*)mpool()->get_page(argv[2]);
01016 assert(pg != NULL);
01017 pg->unlock();
01018
01019 #ifdef MCACHE_DEBUG
01020
01021 char *buf;
01022 for (int i = 0; i < pg->num_layer(); i++) {
01023 buf = pg->print_layer(i);
01024 log("E SEGS p %s l %d %s\n", argv[2], i, buf);
01025 delete []buf;
01026 }
01027 #endif
01028
01029 log("E SIZ n %d z %d t %d\n", mpool()->num_pages(),
01030 mpool()->usedsize(), mpool()->maxsize());
01031 return TCL_OK;
01032 }
01033 } else if (argc == 5) {
01034 if (strcmp(argv[1], "register-client") == 0) {
01035
01036 TclObject *a = TclObject::lookup(argv[2]);
01037 assert(a != NULL);
01038 int newEntry;
01039 Tcl_HashEntry *he = Tcl_CreateHashEntry(cmap_,
01040 (const char *)a, &newEntry);
01041 if (he == NULL) {
01042 tcl.add_errorf("cannot create hash entry");
01043 return TCL_ERROR;
01044 }
01045 if (!newEntry) {
01046 tcl.add_errorf("duplicate connection");
01047 return TCL_ERROR;
01048 }
01049 RegInfo *p = new RegInfo;
01050 p->client_ = (HttpApp*)TclObject::lookup(argv[3]);
01051 assert(p->client_ != NULL);
01052 strcpy(p->name_, argv[4]);
01053 Tcl_SetHashValue(he, (ClientData)p);
01054
01055
01056 MediaPage *pg = (MediaPage*)mpool()->get_page(argv[4]);
01057 assert((pg != NULL) && (pg->type() == MEDIA));
01058 pg->tlock();
01059
01060 return TCL_OK;
01061 } else if (strcmp(argv[1], "unregister-client") == 0) {
01062
01063 TclObject *a = TclObject::lookup(argv[2]);
01064 assert(a != NULL);
01065 Tcl_HashEntry *he =
01066 Tcl_FindHashEntry(cmap_, (const char*)a);
01067 if (he == NULL) {
01068 tcl.add_errorf("cannot find hash entry");
01069 return TCL_ERROR;
01070 }
01071 RegInfo *ri = (RegInfo*)Tcl_GetHashValue(he);
01072
01073 mpool()->hc_update(argv[4], ri->hl_);
01074 #ifdef MCACHE_DEBUG
01075 printf("Cache %d hit counts: \n", id_);
01076 mpool()->dump_hclist();
01077 #endif
01078
01079 for (int i = 0; i <= ri->hl_; i++)
01080 log("E STAT p %s l %d d %d e %d p %d\n",
01081 ri->name_, i, ri->db_[i], ri->eb_[i],
01082 ri->pb_[i]);
01083 delete ri;
01084 Tcl_DeleteHashEntry(he);
01085
01086
01087 MediaPage *pg = (MediaPage*)mpool()->get_page(argv[4]);
01088 assert((pg != NULL) && (pg->type() == MEDIA));
01089 pg->tunlock();
01090
01091 return TCL_OK;
01092 }
01093 }
01094
01095 return HttpCache::command(argc, argv);
01096 }
01097
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107 static class HttpMediaClientClass : public TclClass {
01108 public:
01109 HttpMediaClientClass() : TclClass("Http/Client/Media") {}
01110 TclObject* create(int, const char*const*) {
01111 return (new MediaClient());
01112 }
01113 } class_httpmediaclient;
01114
01115
01116 void MediaClient::process_data(int size, AppData* data)
01117 {
01118 assert(data != NULL);
01119
01120 switch (data->type()) {
01121 case MEDIA_DATA: {
01122 HttpMediaData* d = (HttpMediaData*)data;
01123
01124 if (mpool()->add_segment(d->page(), d->layer(),
01125 MediaSegment(*d)) == -1) {
01126 fprintf(stderr,
01127 "MediaCache %s gets a segment for an unknown page %s\n", name(), d->page());
01128
01129 }
01130
01131
01132 #if 1
01133 log("C RSEG p %s l %d s %d e %d z %d\n",
01134 d->page(), d->layer(), d->st(), d->et(), d->datasize());
01135 #endif
01136 break;
01137 }
01138 default:
01139 HttpClient::process_data(size, data);
01140 }
01141 }
01142
01143 int MediaClient::command(int argc, const char*const* argv)
01144 {
01145 if (argc == 3) {
01146 if (strcmp(argv[1], "stream-received") == 0) {
01147
01148
01149
01150
01151 MediaPage *pg = (MediaPage*)mpool()->get_page(argv[2]);
01152 assert(pg != NULL);
01153
01154 char *buf;
01155 for (int i = 0; i < pg->num_layer(); i++) {
01156 buf = pg->print_layer(i);
01157 if (strlen(buf) > 0)
01158 log("C SEGS p %s l %d %s\n",
01159 argv[2], i, buf);
01160 delete []buf;
01161 }
01162
01163 mpool()->force_remove(argv[2]);
01164 return TCL_OK;
01165 }
01166 }
01167 return HttpClient::command(argc, argv);
01168 }
01169
01170
01171
01172
01173
01174
01175
01176 static class MediaServerClass : public TclClass {
01177 public:
01178 MediaServerClass() : TclClass("Http/Server/Media") {}
01179 TclObject* create(int, const char*const*) {
01180 return (new MediaServer());
01181 }
01182 } class_mediaserver;
01183
01184 MediaServer::MediaServer() : HttpServer()
01185 {
01186 long keySizeInBytes = sizeof (PageID);
01187 long keySizeInSizeOfInt;
01188 if ((keySizeInBytes % sizeof (int)) == 0) {
01189 keySizeInSizeOfInt = keySizeInBytes / sizeof (int);
01190 } else {
01191 keySizeInSizeOfInt = keySizeInBytes / sizeof (int) + 1;
01192 }
01193 pref_ = new Tcl_HashTable;
01194 Tcl_InitHashTable(pref_, keySizeInSizeOfInt);
01195 cmap_ = new Tcl_HashTable;
01196 Tcl_InitHashTable(cmap_, TCL_ONE_WORD_KEYS);
01197 }
01198
01199 MediaServer::~MediaServer()
01200 {
01201 Tcl_HashEntry *he;
01202 Tcl_HashSearch hs;
01203 if (pref_ != NULL) {
01204 for (he = Tcl_FirstHashEntry(pref_, &hs); he != NULL;
01205 he = Tcl_NextHashEntry(&hs)) {
01206 PrefInfo *pi = (PrefInfo*)Tcl_GetHashValue(he);
01207 pi->sl_->destroy();
01208 delete pi->sl_;
01209 }
01210 Tcl_DeleteHashTable(pref_);
01211 delete pref_;
01212 }
01213 if (cmap_ != NULL) {
01214 for (he = Tcl_FirstHashEntry(cmap_, &hs); he != NULL;
01215 he = Tcl_NextHashEntry(&hs))
01216 delete (RegInfo*)Tcl_GetHashValue(he);
01217 Tcl_DeleteHashTable(cmap_);
01218 delete cmap_;
01219 }
01220 }
01221
01222
01223 MediaSegment MediaServer::get_next_segment(MediaRequest *r, Application*& ci)
01224 {
01225 MediaPage* pg = (MediaPage*)pool_->get_page(r->name());
01226 assert(pg != NULL);
01227
01228
01229
01230 RegInfo *ri = get_reginfo(r->app());
01231 assert(ri != NULL);
01232 PrefInfoQ* q = get_piq(r->name(), ri->client_);
01233
01234
01235 if ((q == NULL) || (q->is_empty())) {
01236 MediaSegment s1(r->st(), r->et());
01237 return pg->next_overlap(r->layer(), s1);
01238 }
01239
01240
01241 int found = 0;
01242 int searched = 0;
01243 PrefInfo *pi;
01244 while (!found) {
01245 PrefInfoE *pe = q->dequeue();
01246 pi = pe->data();
01247 q->enqueue(pe);
01248
01249 for (int i = 0; i < pg->num_layer(); i++)
01250 if (pi->sl_[i].length() > 0)
01251 found = 1;
01252
01253 if (searched++ == q->size())
01254 return MediaSegment(0, 0);
01255 }
01256
01257
01258
01259 MediaSegmentList *p = pi->sl_;
01260
01261 ci = pi->conid_;
01262
01263
01264
01265 int l = r->layer(), i = 0;
01266 MediaSegment res;
01267 while ((res.datasize() == 0) && (i < pg->num_layer())) {
01268
01269
01270
01271 res = p[l].get_nextseg(MediaSegment(0, r->datasize()));
01272 i++;
01273 l = (l+1) % pg->num_layer();
01274 }
01275
01276
01277 if (res.start() < 0)
01278 res.set_start(0);
01279 if (res.end() > pg->layer_size(l))
01280 res.set_end(pg->layer_size(l));
01281 if (res.datasize() > 0) {
01282
01283 l = (l-1+pg->num_layer()) % pg->num_layer();
01284 if (l != r->layer())
01285 r->set_layer(l);
01286
01287
01288
01289 p[r->layer()].evict_head(r->datasize());
01290 }
01291
01292 res.set_pref();
01293 return res;
01294 }
01295
01296
01297 AppData* MediaServer::get_data(int& size, AppData *req)
01298 {
01299 assert((req != NULL) && (req->type() == MEDIA_REQUEST));
01300 MediaRequest *r = (MediaRequest *)req;
01301 Application* conid = NULL;
01302
01303 if (r->request() == MEDIAREQ_GETSEG) {
01304
01305 MediaSegment s2 = get_next_segment(r, conid);
01306 HttpMediaData *p;
01307 if (s2.datasize() == 0) {
01308
01309
01310 size = 0;
01311 p = new HttpMediaData(name(), r->name(),
01312 r->layer(), 0, 0);
01313 } else {
01314 size = s2.datasize();
01315 p = new HttpMediaData(name(), r->name(),
01316 r->layer(), s2.start(), s2.end());
01317 }
01318 if (s2.is_last()) {
01319 p->set_last();
01320
01321
01322 if ((s2.datasize() == 0) && (r->layer() == 0))
01323 p->set_finish();
01324 }
01325 if (s2.is_pref()) {
01326
01327 p->set_conid(conid);
01328 p->set_pref();
01329 }
01330 return p;
01331 } else if (r->request() == MEDIAREQ_CHECKSEG)
01332
01333 return NULL;
01334 else {
01335 fprintf(stderr,
01336 "MediaServer %s gets an unknown MediaRequest type %d\n",
01337 name(), r->request());
01338 abort();
01339 }
01340
01341 return NULL;
01342 }
01343
01344 int MediaServer::command(int argc, const char*const* argv)
01345 {
01346 Tcl& tcl = Tcl::instance();
01347 if (argc == 3) {
01348 if (strcmp(argv[1], "is-media-page") == 0) {
01349 ClientPage *pg = pool_->get_page(argv[2]);
01350 if (pg && (pg->type() == MEDIA))
01351 tcl.result("1");
01352 else
01353 tcl.result("0");
01354 return TCL_OK;
01355 }
01356 } else if (argc == 5) {
01357 if (strcmp(argv[1], "stop-prefetching") == 0) {
01358
01359
01360
01361 HttpApp *app = static_cast <HttpApp *> (TclObject::lookup(argv[2]));
01362 assert(app != NULL);
01363 int id = atoi (argv[4]);
01364 PageID pageId (app, id);
01365 Tcl_HashEntry *he =
01366 Tcl_FindHashEntry(pref_, (const char*)&pageId);
01367 if (he == NULL) {
01368 tcl.add_errorf(
01369 "Server %d cannot stop prefetching!\n", id_);
01370 return TCL_ERROR;
01371 }
01372 TclObject *conId = TclObject::lookup(argv[3]);
01373 assert(conId != NULL);
01374 PrefInfoQ *q = (PrefInfoQ*)Tcl_GetHashValue(he);
01375 PrefInfoE *pe = find_prefinfo(q, (Application*)conId);
01376 assert(pe != NULL);
01377 PrefInfo *pi = pe->data();
01378 MediaSegmentList *p = pi->sl_;
01379 assert(p != NULL);
01380 for (int i = 0; i < MAX_LAYER; i++)
01381 p[i].destroy();
01382 delete []p;
01383 delete pi;
01384 q->detach(pe);
01385 delete pe;
01386
01387
01388
01389
01390
01391 int res = 0;
01392 if (q->is_empty()) {
01393 delete q;
01394 Tcl_DeleteHashEntry(he);
01395 res = 1;
01396 }
01397 tcl.resultf("%d", res);
01398 return (TCL_OK);
01399 } else if (strcmp(argv[1], "register-client") == 0) {
01400
01401 TclObject *a = TclObject::lookup(argv[2]);
01402 assert(a != NULL);
01403 int newEntry;
01404 Tcl_HashEntry *he = Tcl_CreateHashEntry(cmap_,
01405 (const char *)a, &newEntry);
01406 if (he == NULL) {
01407 tcl.add_errorf("cannot create hash entry");
01408 return TCL_ERROR;
01409 }
01410 if (!newEntry) {
01411 tcl.add_errorf("duplicate connection");
01412 return TCL_ERROR;
01413 }
01414 RegInfo *p = new RegInfo;
01415 p->client_ = (HttpApp*)TclObject::lookup(argv[3]);
01416 assert(p->client_ != NULL);
01417 strcpy(p->name_, argv[4]);
01418 Tcl_SetHashValue(he, (ClientData)p);
01419 return TCL_OK;
01420 } else if (strcmp(argv[1], "unregister-client") == 0) {
01421
01422 TclObject *a = TclObject::lookup(argv[2]);
01423 assert(a != NULL);
01424 Tcl_HashEntry *he =
01425 Tcl_FindHashEntry(cmap_, (const char*)a);
01426 if (he == NULL) {
01427 tcl.add_errorf("cannot find hash entry");
01428 return TCL_ERROR;
01429 }
01430 RegInfo *p = (RegInfo*)Tcl_GetHashValue(he);
01431 delete p;
01432 Tcl_DeleteHashEntry(he);
01433 return TCL_OK;
01434 }
01435 } else {
01436 if (strcmp(argv[1], "enter-page") == 0) {
01437 ClientPage *pg = pool_->enter_page(argc, argv);
01438 if (pg == NULL)
01439 return TCL_ERROR;
01440 if (pg->type() == MEDIA)
01441 ((MediaPage*)pg)->create();
01442
01443 ((MediaPage*)pg)->unlock();
01444 return TCL_OK;
01445 } else if (strcmp(argv[1], "register-prefetch") == 0) {
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460 HttpApp *app = static_cast <HttpApp *> (TclObject::lookup(argv[2]));
01461 assert(app != NULL);
01462 int id = atoi (argv[3]);
01463 PageID pageId (app, id);
01464 int newEntry = 1;
01465 Tcl_HashEntry *he = Tcl_CreateHashEntry(pref_,
01466 (const char*)&pageId, &newEntry);
01467 if (he == NULL) {
01468 fprintf(stderr, "Cannot create entry.\n");
01469 return TCL_ERROR;
01470 }
01471 PrefInfo *pi;
01472 PrefInfoE *pe;
01473 PrefInfoQ *q;
01474 MediaSegmentList *p;
01475 TclObject *conId = TclObject::lookup(argv[4]);
01476 if (newEntry) {
01477 q = new PrefInfoQ;
01478 Tcl_SetHashValue(he, (ClientData)q);
01479 pe = NULL;
01480 } else {
01481 q = (PrefInfoQ *)Tcl_GetHashValue(he);
01482 pe = find_prefinfo(q, (Application*)conId);
01483 }
01484 if (pe == NULL) {
01485 pi = new PrefInfo;
01486 pi->conid_ = (Application*)conId;
01487 p = pi->sl_ = new MediaSegmentList[MAX_LAYER];
01488 q->enqueue(new PrefInfoE(pi));
01489 } else {
01490 pi = pe->data();
01491 p = pi->sl_;
01492 }
01493 assert((pi != NULL) && (p != NULL));
01494
01495
01496 int layer = atoi(argv[5]);
01497 p[layer].destroy();
01498
01499 assert(argc % 2 == 0);
01500 for (int i = 6; i < argc; i+=2)
01501 p[layer].add(MediaSegment(atoi(argv[i]),
01502 atoi(argv[i+1])));
01503 return TCL_OK;
01504 }
01505 }
01506
01507 return HttpServer::command(argc, argv);
01508 }