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