Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members
CacheManagerLRU.cpp
00001 /*********************************************************************** 00002 * * 00003 * ViTooKi * 00004 * * 00005 * title: CacheManagerLRU.cpp * 00006 * * 00007 * * 00008 * * 00009 * ITEC institute of the University of Klagenfurt (Austria) * 00010 * http://www.itec.uni-klu.ac.at * 00011 * * 00012 * * 00013 * For more information visit the ViTooKi homepage: * 00014 * http://ViTooKi.sourceforge.net * 00015 * vitooki-user@lists.sourceforge.net * 00016 * vitooki-devel@lists.sourceforge.net * 00017 * * 00018 * This file is part of ViTooKi, a free video toolkit. * 00019 * ViTooKi is free software; you can redistribute it and/or * 00020 * modify it under the terms of the GNU General Public License * 00021 * as published by the Free Software Foundation; either version 2 * 00022 * of the License, or (at your option) any later version. * 00023 * * 00024 * This program is distributed in the hope that it will be useful, * 00025 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00026 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00027 * GNU General Public License for more details. * 00028 * * 00029 * You should have received a copy of the GNU General Public License * 00030 * along with this program; if not, write to the Free Software * 00031 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, * 00032 * MA 02111-1307, USA. * 00033 * * 00034 ***********************************************************************/ 00035 00036 /*********************************************************************** 00037 * * 00038 * REVISION HISTORY: * 00039 * * 00040 * * 00041 * * 00042 ***********************************************************************/ 00043 00044 // Definition: LRU Cache Manager Implementation// 00045 00046 #include "CacheManagerLRU.hpp" 00047 #include "ESInfo.hpp" 00048 #include "VideoESInfo.hpp" 00049 #include "ContainerInfo.hpp" //includes metaitem+QualityInfo 00050 #include "container/Video4LinuxContainerFile.hpp" 00051 #include "global.hpp" 00052 #include "../net/Url.hpp" 00053 #include "ReferenceCounter.hpp" 00054 #include "BitField.hpp" 00055 00056 CacheManagerLRU::CacheManagerLRU(u32 size, bool serverMod) 00057 { 00058 serverMode=serverMod; 00059 cacheSize = size; 00060 actSize = 0; 00061 requests = 0; 00062 hits = 0; 00063 byteRequested = 0; 00064 byteHits = 0; 00065 qualityHits = 0.0; 00066 lock.initialize("CacheManagerLRU-lock"); 00067 }; 00068 00069 CacheManagerLRU::~CacheManagerLRU() 00070 { 00071 // we delete MetaObject, this deletes 00072 // all ContainerInfo objects too 00073 dprintf_full("~CacheManagerLRU() destructing\n"); 00074 00075 /* 00076 ** FIXME: the fopen already hangs the proxy on my system.. so turned off... 00077 FILE* fp=fopen("lru.stat","wb"); 00078 dprintf_full("~CacheManagerLRU() destructing af\n"); 00079 if(fp) { 00080 saveStatisticTo(fp); 00081 fclose(fp); 00082 } 00083 */ 00084 00085 00086 list < MetaObject * >::iterator start; 00087 start = metaObjects.begin(); 00088 00089 while (!metaObjects.empty()) { 00090 start = metaObjects.begin(); 00091 delete (*start); 00092 metaObjects.pop_front(); 00093 } 00094 lock.destroy(); 00095 } 00096 00097 void CacheManagerLRU::putVideo(ContainerInfo * video,u32 dskSpaceAlreadyReserved) 00098 { 00099 if(video==NULL) { 00100 actSize-= dskSpaceAlreadyReserved; 00101 return; 00102 } 00103 assert(video->getUsageCounter()->getUsage()==0); 00104 internalConsistencyCheck(); 00105 u32 videoSize = video->getFileSize(); 00106 byteRequested += videoSize; 00107 float percBits = 1; 00108 if (video->getFirstVisualES()) { 00109 percBits = video->getFirstVisualES()->getFrameStatistic()->getPercentageSetBits(); 00110 dprintf_full("CacheManagerLRU::putVideo Inserting video %s, comp%f\r\n",video->getUrl()->toString(),percBits); 00111 00112 if(percBits <=0.9) { 00113 actSize-= dskSpaceAlreadyReserved; 00114 prxStat.deletedDueToLowQuality++; 00115 video->destroy(); 00116 dprintf_full("Deleted incomplete video %s\n",video->getUrl()->toString()); 00117 return; 00118 } 00119 } 00120 else if (video->getFirstAudioES()) 00121 //FIXME: this stream only has audio, keep it in cache... 00122 dprintf_full("CacheManagerLRU::putVideo Inserting audio-only stream %s\r\n",video->getUrl()->toString()); 00123 00124 00125 list<ESInfo*> *les=video->getESList(); 00126 list<ESInfo*>::iterator lis; 00127 00128 for(lis=les->begin();lis!=les->end();lis++) { 00129 u64 fs=(*lis)->getCurrentDemuxedMediaSize(); 00130 fs*=8000; 00131 fs/=(*lis)->getDurationInMs(); 00132 (*lis)->setAvgBandwidth((u32)fs); 00133 if( (*lis)->getMaxBandwidth()<(*lis)->getAvgBandwidth()) 00134 (*lis)->setMaxBandwidth((*lis)->getAvgBandwidth()); 00135 } 00136 00137 00138 MetaObject* meta=findMetaObject(video->getUrl()); 00139 if(!meta) { 00140 meta=new MetaObject(video); 00141 metaObjects.push_front(meta); 00142 } 00143 else { 00144 if(!meta->addMP4Stream(video)) { 00145 video=NULL; // was deleted 00146 actSize-= dskSpaceAlreadyReserved; 00147 } 00148 } 00149 00150 if (video && videoSize <= cacheSize) { 00151 lrulist.push_front(video); 00152 actSize += video->getFileSize(); 00153 actSize-= dskSpaceAlreadyReserved; 00154 if (actSize > cacheSize) { 00155 dprintf_full("CacheManagerLRU::putVideo Cache Replacement needed\n"); 00156 replace(false); 00157 } 00158 } else if(video){ 00159 dprintf_full("CacheManagerLRU::putVideo: video %s deleted because its size %i is larger than CacheSize %i\r\n", 00160 video->getUrl()->toString(), videoSize, cacheSize); 00161 meta->deleteMP4Stream(video); 00162 actSize-= dskSpaceAlreadyReserved; 00163 video->destroy(); 00164 delete video; 00165 } 00166 internalConsistencyCheck(); 00167 dprintf_full("CacheManagerLRU::putVideo END\r\n"); 00168 }; 00169 00170 //PROBLEM: we have no way of knowing if its a quality hit or not --> session knows 00171 ContainerInfo *CacheManagerLRU::getVideo(const Url *name) 00172 { 00173 list < ContainerInfo * >::iterator start, end; 00174 ContainerInfo* vid = NULL; 00175 start = lrulist.begin(); 00176 end = lrulist.end(); 00177 internalConsistencyCheck(); 00178 requests++; 00179 printf("*******CacheManagerLRU::getVideo use URL: #%s#\n", name->toString()); 00180 if (strcmp(name->toString(), "v4l") != 0) 00181 { 00182 00183 if(start==end) { 00184 return NULL; 00185 } 00186 bool firstDel=false; 00187 00188 while(start != end) { 00189 00190 vid=(*start); 00191 dprintf_full("CacheManagerLRU::getVideo found Cached URL: #%s#\n",vid->getUrl()->toString()); 00192 VideoESInfo* ves=vid->getFirstVisualES(); 00193 // AudioESInfo* aes=vid->getFirstAudioES(); 00194 float qual=0.0; 00195 if(ves && ves->getFrameStatistic()) 00196 qual=ves->getFrameStatistic()->getPercentageSetBits(); 00197 dprintf_full("CacheManagerLRU::getVideo found %f complete (use %u)\n",qual,(*start)->getUsageCounter()->getUsage()); 00198 // quality too low and not used (aka quality will improve) 00199 /* if(qual<0.9 && (*start)->getUsageCounter()->deactivateWhenUsage(0)) { 00200 (*start)->destroy(); 00201 MetaObject* meta=(*start)->getMetaObject(); 00202 if(meta->getNumberOfVariations()==1) { 00203 deleteMetaObject(meta->getUrl()); 00204 } 00205 else { 00206 meta->deleteMP4Stream(*start); // frees *start 00207 } 00208 00209 list < ContainerInfo * >::iterator tmp= start; 00210 if(start!=lrulist.begin()) { 00211 start--; // point before the element which is deleted 00212 lrulist.erase(tmp); 00213 } 00214 else { // we delete the first element 00215 lrulist.erase(tmp); 00216 firstDel=true; 00217 start=lrulist.begin(); 00218 } 00219 } 00220 else*/ if ((*start)->getUrl()->isEqual(name,serverMode) ) { 00221 lrulist.push_front(*start); 00222 lrulist.erase(start); 00223 start = lrulist.begin(); 00224 hits++; 00225 byteRequested += (*start)->getFileSize(); 00226 byteHits += (*start)->getFileSize(); 00227 qualityHits += (*start)->getActQuality(); 00228 (*start)->setLastRequestTime(requests); 00229 return (*start); 00230 } 00231 if(!firstDel) 00232 ++start; 00233 } 00234 } 00235 #ifndef WIN32 00236 else 00237 { 00238 dprintf_full("CacheManagerLRU::getVideo: Using v4lContailerfile"); 00239 vid=Video4LinuxContainerFile::loadContainerInfo(); 00240 return vid; 00241 } 00242 #endif 00243 00244 return NULL; 00245 00246 00247 }; 00248 00249 MetaObject* CacheManagerLRU::findMetaObject(const Url* url) { 00250 00251 MetaObject* temp; 00252 ContainerInfo *tempInfo; 00253 list < MetaObject * >::iterator start, end; 00254 start = metaObjects.begin(); 00255 end = metaObjects.end(); 00256 00257 dprintf_full("CacheManagerLRU::findMetaObject URL: %s \n",url->toString()); 00258 #ifndef WIN32 00259 if (strcmp(url->getFileName(), "v4l") == 0) 00260 { 00261 dprintf_full("CacheManagerLRU::findMetaObject using v4l:\n"); 00262 tempInfo = Video4LinuxContainerFile::loadContainerInfo(); 00263 dprintf_full("CacheManagerLRU::findMetaObject v4l: creating v4l containerinfo ok!!\n"); 00264 temp = new MetaObject(tempInfo); 00265 if (temp == NULL) { 00266 dprintf_full("CacheManagerLRU::findMetaObject v4l: NULL!!\n"); 00267 } 00268 else { 00269 dprintf_full("CacheManagerLRU::findMetaObject v4l: OK, Number of variations : %d!!\n", temp->getNumberOfVariations()); 00270 } 00271 return temp; 00272 } 00273 #endif 00274 00275 for (; start != end; ++start) { 00276 const Url* tmp=(*start)->getUrl(); 00277 dprintf_full("CacheManagerLRU::findMetaObject compares %s with %s\n",url->toString(), tmp->toString()); 00278 if (url->isEqual(tmp,serverMode)) { 00279 return (*start); 00280 } 00281 } 00282 00283 return NULL; 00284 }; 00285 00286 void CacheManagerLRU::internalConsistencyCheck() 00287 { 00288 u32 metaVariations=0; 00289 u32 sumVar=0; 00290 list < MetaObject * >::iterator start, end; 00291 start = metaObjects.begin(); 00292 end = metaObjects.end(); 00293 for (; start != end; ++start) { 00294 metaVariations+=(*start)->getNumberOfVariations(); 00295 } 00296 list < ContainerInfo * >::iterator cstart, cend; 00297 cstart = lrulist.begin(); 00298 cend = lrulist.end(); 00299 sumVar=lrulist.size(); 00300 assert(sumVar==metaVariations); 00301 for (; cstart != cend; ++cstart) { 00302 assert((*cstart)->getMetaObject()); 00303 } 00304 }; 00305 00306 void CacheManagerLRU::deleteMetaObject(const Url* url) { 00307 00308 list < MetaObject * >::iterator start, end; 00309 start = metaObjects.begin(); 00310 end = metaObjects.end(); 00311 for (; start != end; ++start) { 00312 if ((*start)->getUrl()->isEqual(url,serverMode)) { 00313 delete (*start); 00314 metaObjects.erase(start); 00315 return; 00316 } 00317 } 00318 internalConsistencyCheck(); 00319 }; 00320 bool CacheManagerLRU::replace(bool testPriorDelete) 00321 { 00322 list < ContainerInfo * >::iterator end; 00323 internalConsistencyCheck(); 00324 if(testPriorDelete) { 00325 u32 maxMemFreeable=getSizeOfNotLockedObjects(); 00326 // is it possible to get actSize < cacheSize? 00327 assert(actSize>=maxMemFreeable); 00328 if(actSize-maxMemFreeable>cacheSize) 00329 return false; 00330 } 00331 00332 while (!lrulist.empty() && actSize > cacheSize) { 00333 end = --lrulist.end(); 00334 // find a video that is not in use 00335 while( end != lrulist.begin() && 00336 !(*end)->getUsageCounter()->deactivateWhenUsage(0)) 00337 --end; 00338 00339 if ((*end)->getUsageCounter()->getUsage() == 0) { 00340 actSize -= (*end)->getFileSize(); 00341 // LRU just deletes the file 00342 (*end)->destroy(); // deletes the file 00343 MetaObject* meta=(*end)->getMetaObject(); 00344 if(meta->getNumberOfVariations()==1) { 00345 deleteMetaObject(meta->getUrl()); 00346 } 00347 else { 00348 bool ok=meta->deleteMP4Stream(*end); // frees *end 00349 assert(ok); 00350 } 00351 lrulist.erase(end); 00352 } 00353 } 00354 internalConsistencyCheck(); 00355 return (actSize<cacheSize); 00356 } 00357 00359 u32 CacheManagerLRU::getSizeOfNotLockedObjects() 00360 { 00361 list < ContainerInfo * >::iterator ci; 00362 u32 results=0; 00363 for(ci=lrulist.begin();ci!=lrulist.end();++ci) { 00364 if ((*ci)->getUsageCounter()->getUsage() == 0) { 00365 results+=(*ci)->getFileSize(); 00366 } 00367 } 00368 return results; 00369 }; 00370 00371 u32 CacheManagerLRU::getCacheSize() const 00372 { 00373 return cacheSize; 00374 } 00375 00376 u32 CacheManagerLRU::getActSize() const 00377 { 00378 return actSize; 00379 } 00380 00381 u32 CacheManagerLRU::getRequests() const 00382 { 00383 return requests; 00384 } 00385 00386 u32 CacheManagerLRU::getHits() const 00387 { 00388 return hits; 00389 } 00390 00391 u64 CacheManagerLRU::getByteRequested() const 00392 { 00393 return byteRequested; 00394 } 00395 00396 u64 CacheManagerLRU::getByteHits() const 00397 { 00398 return byteHits; 00399 } 00400 00401 double CacheManagerLRU::getQualityHits() const 00402 { 00403 return qualityHits; 00404 } 00405 00406 00407 void CacheManagerLRU::getContent() 00408 { 00409 list < ContainerInfo * >::iterator start, end; 00410 start = lrulist.begin(); 00411 end = lrulist.end(); 00412 00413 00414 for (; start != end; ++start) { 00415 printf("%s [%d] | %d - %d\n", (*start)->getUrl()->toString(), (*start)->getFileSize(), (*start)->getLastRequestTime(), requests); 00416 } 00417 printf("##### actual cache size ##### %d\n",actSize); 00418 } 00419 00420 void CacheManagerLRU::saveCacheIndexToDir(const char* dir) 00421 { 00422 assert(dir!=NULL); 00423 list < ContainerInfo * >::iterator start, end; 00424 start = lrulist.begin(); 00425 end = lrulist.end(); 00426 char *dummy = new char[4096]; 00427 char* dummyP; 00428 char* tmp=NULL; 00429 strcpy(dummy,dir); 00430 dummyP=dummy+strlen(dummy); 00431 for (; start != end; ++start) { 00432 tmp=Url::transformUrlToLocalFile( (*start)->getUrl()); 00433 strcpy(dummyP,tmp); 00434 strcat(dummyP,".conf"); 00435 (*start)->saveToCfgFile(dummy); 00436 delete[] tmp; 00437 } 00438 delete [] dummy; 00439 00440 }