aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/llcommon/llworkerthread.cpp39
-rw-r--r--linden/indra/llcommon/llworkerthread.h8
-rw-r--r--linden/indra/newview/lltexturecache.cpp679
-rw-r--r--linden/indra/newview/lltexturecache.h37
-rw-r--r--linden/indra/newview/lltexturefetch.cpp2
5 files changed, 533 insertions, 232 deletions
diff --git a/linden/indra/llcommon/llworkerthread.cpp b/linden/indra/llcommon/llworkerthread.cpp
index 8195e1c..67664c7 100644
--- a/linden/indra/llcommon/llworkerthread.cpp
+++ b/linden/indra/llcommon/llworkerthread.cpp
@@ -60,6 +60,27 @@ LLWorkerThread::~LLWorkerThread()
60 // ~LLQueuedThread() will be called here 60 // ~LLQueuedThread() will be called here
61} 61}
62 62
63//called only in destructor.
64void LLWorkerThread::clearDeleteList()
65{
66 // Delete any workers in the delete queue (should be safe - had better be!)
67 if (!mDeleteList.empty())
68 {
69 llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size()
70 << " entries in delete list." << llendl;
71
72 mDeleteMutex->lock();
73 for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter)
74 {
75 (*iter)->mRequestHandle = LLWorkerThread::nullHandle();
76 (*iter)->clearFlags(LLWorkerClass::WCF_HAVE_WORK);
77 delete *iter ;
78 }
79 mDeleteList.clear() ;
80 mDeleteMutex->unlock() ;
81 }
82}
83
63// virtual 84// virtual
64S32 LLWorkerThread::update(U32 max_time_ms) 85S32 LLWorkerThread::update(U32 max_time_ms)
65{ 86{
@@ -183,6 +204,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na
183 : mWorkerThread(workerthread), 204 : mWorkerThread(workerthread),
184 mWorkerClassName(name), 205 mWorkerClassName(name),
185 mRequestHandle(LLWorkerThread::nullHandle()), 206 mRequestHandle(LLWorkerThread::nullHandle()),
207 mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
186 mMutex(NULL), 208 mMutex(NULL),
187 mWorkFlags(0) 209 mWorkFlags(0)
188{ 210{
@@ -314,7 +336,20 @@ bool LLWorkerClass::checkWork(bool aborting)
314 if (mRequestHandle != LLWorkerThread::nullHandle()) 336 if (mRequestHandle != LLWorkerThread::nullHandle())
315 { 337 {
316 LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); 338 LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
317 llassert_always(workreq); 339 if(!workreq)
340 {
341 if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running
342 {
343 mRequestHandle = LLWorkerThread::nullHandle();
344 clearFlags(WCF_HAVE_WORK);
345 }
346 else
347 {
348 llassert_always(workreq);
349 }
350 return true ;
351 }
352
318 LLQueuedThread::status_t status = workreq->getStatus(); 353 LLQueuedThread::status_t status = workreq->getStatus();
319 if (status == LLWorkerThread::STATUS_ABORTED) 354 if (status == LLWorkerThread::STATUS_ABORTED)
320 { 355 {
@@ -364,7 +399,7 @@ void LLWorkerClass::scheduleDelete()
364void LLWorkerClass::setPriority(U32 priority) 399void LLWorkerClass::setPriority(U32 priority)
365{ 400{
366 mMutex.lock(); 401 mMutex.lock();
367 if (mRequestHandle != LLWorkerThread::nullHandle()) 402 if (mRequestHandle != LLWorkerThread::nullHandle() && mRequestPriority != priority)
368 { 403 {
369 mRequestPriority = priority; 404 mRequestPriority = priority;
370 mWorkerThread->setPriority(mRequestHandle, priority); 405 mWorkerThread->setPriority(mRequestHandle, priority);
diff --git a/linden/indra/llcommon/llworkerthread.h b/linden/indra/llcommon/llworkerthread.h
index 708d812..d1868bc 100644
--- a/linden/indra/llcommon/llworkerthread.h
+++ b/linden/indra/llcommon/llworkerthread.h
@@ -80,6 +80,9 @@ public:
80 S32 mParam; 80 S32 mParam;
81 }; 81 };
82 82
83protected:
84 void clearDeleteList() ;
85
83private: 86private:
84 typedef std::list<LLWorkerClass*> delete_list_t; 87 typedef std::list<LLWorkerClass*> delete_list_t;
85 delete_list_t mDeleteList; 88 delete_list_t mDeleteList;
@@ -93,8 +96,11 @@ public:
93 96
94 handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); 97 handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
95 98
96 void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
97 S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug 99 S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
100
101private:
102 void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
103
98}; 104};
99 105
100//============================================================================ 106//============================================================================
diff --git a/linden/indra/newview/lltexturecache.cpp b/linden/indra/newview/lltexturecache.cpp
index 46c125f..0a76742 100644
--- a/linden/indra/newview/lltexturecache.cpp
+++ b/linden/indra/newview/lltexturecache.cpp
@@ -48,11 +48,11 @@
48// Unordered array of Entry structs 48// Unordered array of Entry structs
49// cache/texture.cache 49// cache/texture.cache
50// First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order 50// First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
51// Entry size same as header packet, so we're not 0-padding unless whole image is contained in header.
52// cache/textures/[0-F]/UUID.texture 51// cache/textures/[0-F]/UUID.texture
53// Actual texture body files 52// Actual texture body files
54 53
55const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; 54//note: there is no good to define 1024 for TEXTURE_CACHE_ENTRY_SIZE while FIRST_PACKET_SIZE is 600 on sim side.
55const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024;
56const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit 56const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
57const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate) 57const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
58 58
@@ -390,6 +390,7 @@ bool LLTextureCacheRemoteWorker::doRead()
390 } 390 }
391 else 391 else
392 { 392 {
393 //llinfos << "texture " << mID.asString() << " found in local_assets" << llendl;
393 mImageSize = local_size; 394 mImageSize = local_size;
394 mImageLocal = TRUE; 395 mImageLocal = TRUE;
395 } 396 }
@@ -400,7 +401,8 @@ bool LLTextureCacheRemoteWorker::doRead()
400 // Second state / stage : identify the cache or not... 401 // Second state / stage : identify the cache or not...
401 if (!done && (mState == CACHE)) 402 if (!done && (mState == CACHE))
402 { 403 {
403 idx = mCache->getHeaderCacheEntry(mID, mImageSize); 404 LLTextureCache::Entry entry ;
405 idx = mCache->getHeaderCacheEntry(mID, entry);
404 if (idx < 0) 406 if (idx < 0)
405 { 407 {
406 // The texture is *not* cached. We're done here... 408 // The texture is *not* cached. We're done here...
@@ -409,6 +411,7 @@ bool LLTextureCacheRemoteWorker::doRead()
409 } 411 }
410 else 412 else
411 { 413 {
414 mImageSize = entry.mImageSize ;
412 // If the read offset is bigger than the header cache, we read directly from the body 415 // If the read offset is bigger than the header cache, we read directly from the body
413 // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER 416 // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
414 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; 417 mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
@@ -536,6 +539,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
536 { 539 {
537 llassert_always(mOffset == 0); // We currently do not support write offsets 540 llassert_always(mOffset == 0); // We currently do not support write offsets
538 llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative... 541 llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
542 llassert_always(mImageSize >= mDataSize);
539 mState = CACHE; 543 mState = CACHE;
540 } 544 }
541 545
@@ -545,14 +549,19 @@ bool LLTextureCacheRemoteWorker::doWrite()
545 if (!done && (mState == CACHE)) 549 if (!done && (mState == CACHE))
546 { 550 {
547 bool alreadyCached = false; 551 bool alreadyCached = false;
548 S32 cur_imagesize = 0; 552 LLTextureCache::Entry entry ;
553
549 // Checks if this image is already in the entry list 554 // Checks if this image is already in the entry list
550 idx = mCache->getHeaderCacheEntry(mID, cur_imagesize); 555 idx = mCache->getHeaderCacheEntry(mID, entry);
551 if (idx >= 0 && (cur_imagesize >= 0)) 556 if(idx < 0)
557 {
558 idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry.
559 }
560 else
552 { 561 {
553 alreadyCached = true; // already there and non empty 562 alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry.
554 } 563 }
555 idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry 564
556 if (idx < 0) 565 if (idx < 0)
557 { 566 {
558 llwarns << "LLTextureCacheWorker: " << mID 567 llwarns << "LLTextureCacheWorker: " << mID
@@ -562,10 +571,6 @@ bool LLTextureCacheRemoteWorker::doWrite()
562 } 571 }
563 else 572 else
564 { 573 {
565 if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
566 {
567 alreadyCached = false; // re-write the header if the size changed in all cases
568 }
569 if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)) 574 if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
570 { 575 {
571 // Small texture already cached case: we're done with writing 576 // Small texture already cached case: we're done with writing
@@ -628,7 +633,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
628 { 633 {
629 llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise... 634 llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise...
630 S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; 635 S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
631 if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size)) 636
632 { 637 {
633 // build the cache file name from the UUID 638 // build the cache file name from the UUID
634 std::string filename = mCache->getTextureFileName(mID); 639 std::string filename = mCache->getTextureFileName(mID);
@@ -645,10 +650,7 @@ bool LLTextureCacheRemoteWorker::doWrite()
645 done = true; 650 done = true;
646 } 651 }
647 } 652 }
648 else 653
649 {
650 mDataSize = 0; // no data written
651 }
652 // Nothing else to do at that point... 654 // Nothing else to do at that point...
653 done = true; 655 done = true;
654 } 656 }
@@ -739,7 +741,7 @@ LLTextureCache::LLTextureCache(bool threaded)
739 mHeaderMutex(NULL), 741 mHeaderMutex(NULL),
740 mListMutex(NULL), 742 mListMutex(NULL),
741 mHeaderAPRFile(NULL), 743 mHeaderAPRFile(NULL),
742 mReadOnly(FALSE), 744 mReadOnly(TRUE), //do not allow to change the texture cache until setReadOnly() is called.
743 mTexturesSizeTotal(0), 745 mTexturesSizeTotal(0),
744 mDoPurge(FALSE) 746 mDoPurge(FALSE)
745{ 747{
@@ -747,6 +749,8 @@ LLTextureCache::LLTextureCache(bool threaded)
747 749
748LLTextureCache::~LLTextureCache() 750LLTextureCache::~LLTextureCache()
749{ 751{
752 clearDeleteList() ;
753 writeUpdatedEntries() ;
750} 754}
751 755
752////////////////////////////////////////////////////////////////////////////// 756//////////////////////////////////////////////////////////////////////////////
@@ -754,6 +758,9 @@ LLTextureCache::~LLTextureCache()
754//virtual 758//virtual
755S32 LLTextureCache::update(U32 max_time_ms) 759S32 LLTextureCache::update(U32 max_time_ms)
756{ 760{
761 static LLFrameTimer timer ;
762 static const F32 MAX_TIME_INTERVAL = 300.f ; //seconds.
763
757 S32 res; 764 S32 res;
758 res = LLWorkerThread::update(max_time_ms); 765 res = LLWorkerThread::update(max_time_ms);
759 766
@@ -789,6 +796,12 @@ S32 LLTextureCache::update(U32 max_time_ms)
789 responder->completed(success); 796 responder->completed(success);
790 } 797 }
791 798
799 if(!res && timer.getElapsedTimeF32() > MAX_TIME_INTERVAL)
800 {
801 timer.reset() ;
802 writeUpdatedEntries() ;
803 }
804
792 return res; 805 return res;
793} 806}
794 807
@@ -811,58 +824,54 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
811 return filename; 824 return filename;
812} 825}
813 826
814bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize) 827//debug
828BOOL LLTextureCache::isInCache(const LLUUID& id)
815{ 829{
816 bool res = false; 830 LLMutexLock lock(&mHeaderMutex);
817 bool purge = false; 831 id_map_t::const_iterator iter = mHeaderIDMap.find(id);
832
833 return (iter != mHeaderIDMap.end()) ;
834}
835
836//debug
837BOOL LLTextureCache::isInLocal(const LLUUID& id)
838{
839 S32 local_size = 0;
840 std::string local_filename;
841
842 std::string filename = getLocalFileName(id);
843 // Is it a JPEG2000 file?
818 { 844 {
819 mHeaderMutex.lock(); 845 local_filename = filename + ".j2c";
820 size_map_t::iterator iter1 = mTexturesSizeMap.find(id); 846 local_size = LLAPRFile::size(local_filename);
821 if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize) 847 if (local_size > 0)
822 { 848 {
823 llassert_always(bodysize > 0); 849 return TRUE ;
824
825 S32 oldbodysize = 0;
826 if (iter1 != mTexturesSizeMap.end())
827 {
828 oldbodysize = iter1->second;
829 }
830
831 Entry entry;
832 S32 idx = openAndReadEntry(id, entry, false);
833 if (idx < 0)
834 {
835 llwarns << "Failed to open entry: " << id << llendl;
836 mHeaderMutex.unlock();
837 removeFromCache(id);
838 return false;
839 }
840 else if (oldbodysize != entry.mBodySize)
841 {
842 llwarns << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
843 << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
844 }
845 entry.mBodySize = bodysize;
846 writeEntryAndClose(idx, entry);
847
848 mTexturesSizeTotal -= oldbodysize;
849 mTexturesSizeTotal += bodysize;
850
851 if (mTexturesSizeTotal > sCacheMaxTexturesSize)
852 {
853 purge = true;
854 }
855 res = true;
856 } 850 }
857 } 851 }
858 if (purge) 852
853 // If not, is it a jpeg file?
859 { 854 {
860 mDoPurge = TRUE; 855 local_filename = filename + ".jpg";
856 local_size = LLAPRFile::size(local_filename);
857 if (local_size > 0)
858 {
859 return TRUE ;
860 }
861 } 861 }
862 mHeaderMutex.unlock(); 862
863 return res; 863 // Hmm... What about a targa file? (used for UI texture mostly)
864 {
865 local_filename = filename + ".tga";
866 local_size = LLAPRFile::size(local_filename);
867 if (local_size > 0)
868 {
869 return TRUE ;
870 }
871 }
872
873 return FALSE ;
864} 874}
865
866////////////////////////////////////////////////////////////////////////////// 875//////////////////////////////////////////////////////////////////////////////
867 876
868//static 877//static
@@ -893,13 +902,21 @@ void LLTextureCache::purgeCache(ELLPath location)
893 LLAPRFile::remove(mHeaderEntriesFileName); 902 LLAPRFile::remove(mHeaderEntriesFileName);
894 LLAPRFile::remove(mHeaderDataFileName); 903 LLAPRFile::remove(mHeaderDataFileName);
895 } 904 }
905 //remove the current texture cache.
896 purgeAllTextures(true); 906 purgeAllTextures(true);
897} 907}
898 908
899S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only) 909//is called in the main thread before initCache(...) is called.
910void LLTextureCache::setReadOnly(BOOL read_only)
900{ 911{
901 mReadOnly = read_only; 912 mReadOnly = read_only;
902 913}
914
915//called in the main thread.
916S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_texture_cache)
917{
918 llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
919
903 S64 header_size = (max_size * 2) / 10; 920 S64 header_size = (max_size * 2) / 10;
904 S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE; 921 S64 max_entries = header_size / TEXTURE_CACHE_ENTRY_SIZE;
905 sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries)); 922 sCacheMaxEntries = (S32)(llmin((S64)sCacheMaxEntries, max_entries));
@@ -911,6 +928,15 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
911 sCacheMaxTexturesSize = max_size; 928 sCacheMaxTexturesSize = max_size;
912 max_size -= sCacheMaxTexturesSize; 929 max_size -= sCacheMaxTexturesSize;
913 930
931 if(disable_texture_cache) //the texture cache is disabled
932 {
933 llinfos << "The texture cache is disabled!" << llendl ;
934 setReadOnly(TRUE) ;
935 purgeAllTextures(true);
936
937 return max_size ;
938 }
939
914 LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries 940 LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries
915 << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL; 941 << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL;
916 942
@@ -919,6 +945,7 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
919 if (!mReadOnly) 945 if (!mReadOnly)
920 { 946 {
921 LLFile::mkdir(mTexturesDirName); 947 LLFile::mkdir(mTexturesDirName);
948
922 const char* subdirs = "0123456789abcdef"; 949 const char* subdirs = "0123456789abcdef";
923 for (S32 i=0; i<16; i++) 950 for (S32 i=0; i<16; i++)
924 { 951 {
@@ -929,6 +956,8 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
929 readHeaderCache(); 956 readHeaderCache();
930 purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it 957 purgeTextures(true); // calc mTexturesSize and make some room in the texture cache if we need it
931 958
959 llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized.
960
932 return max_size; // unused cache space 961 return max_size; // unused cache space
933} 962}
934 963
@@ -940,13 +969,20 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
940 llassert_always(mHeaderAPRFile == NULL); 969 llassert_always(mHeaderAPRFile == NULL);
941 apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY; 970 apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
942 mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, LLAPRFile::local); 971 mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, LLAPRFile::local);
943 mHeaderAPRFile->seek(APR_SET, offset); 972 if(offset > 0)
973 {
974 mHeaderAPRFile->seek(APR_SET, offset);
975 }
944 return mHeaderAPRFile; 976 return mHeaderAPRFile;
945} 977}
946 978
947void LLTextureCache::closeHeaderEntriesFile() 979void LLTextureCache::closeHeaderEntriesFile()
948{ 980{
949 llassert_always(mHeaderAPRFile != NULL); 981 if(!mHeaderAPRFile)
982 {
983 return ;
984 }
985
950 delete mHeaderAPRFile; 986 delete mHeaderAPRFile;
951 mHeaderAPRFile = NULL; 987 mHeaderAPRFile = NULL;
952} 988}
@@ -959,6 +995,12 @@ void LLTextureCache::readEntriesHeader()
959 { 995 {
960 LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo)); 996 LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo));
961 } 997 }
998 else //create an empty entries header.
999 {
1000 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion ;
1001 mHeaderEntriesInfo.mEntries = 0 ;
1002 writeEntriesHeader() ;
1003 }
962} 1004}
963 1005
964void LLTextureCache::writeEntriesHeader() 1006void LLTextureCache::writeEntriesHeader()
@@ -970,8 +1012,7 @@ void LLTextureCache::writeEntriesHeader()
970 } 1012 }
971} 1013}
972 1014
973static S32 mHeaderEntriesMaxWriteIdx = 0; 1015//mHeaderMutex is locked before calling this.
974
975S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create) 1016S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
976{ 1017{
977 S32 idx = -1; 1018 S32 idx = -1;
@@ -1011,8 +1052,7 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create
1011 if (iter3 != mHeaderIDMap.end() && iter3->second >= 0) 1052 if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
1012 { 1053 {
1013 idx = iter3->second; 1054 idx = iter3->second;
1014 mHeaderIDMap.erase(oldid); 1055 removeCachedTexture(oldid) ;//remove the existing cached texture to release the entry index.
1015 mTexturesSizeMap.erase(oldid);
1016 break; 1056 break;
1017 } 1057 }
1018 } 1058 }
@@ -1022,20 +1062,9 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create
1022 } 1062 }
1023 if (idx >= 0) 1063 if (idx >= 0)
1024 { 1064 {
1025 // Set the header index 1065 entry.mID = id ;
1026 mHeaderIDMap[id] = idx; 1066 entry.mImageSize = -1 ; //mark it is a brand-new entry.
1027 llassert_always(mTexturesSizeMap.erase(id) == 0); 1067 entry.mBodySize = 0 ;
1028 // Initialize the entry (will get written later)
1029 entry.init(id, time(NULL));
1030 // Update Header
1031 writeEntriesHeader();
1032 // Write Entry
1033 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1034 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
1035 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1036 llassert_always(bytes_written == sizeof(Entry));
1037 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
1038 closeHeaderEntriesFile();
1039 } 1068 }
1040 } 1069 }
1041 } 1070 }
@@ -1044,44 +1073,153 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create
1044 // Remove this entry from the LRU if it exists 1073 // Remove this entry from the LRU if it exists
1045 mLRU.erase(id); 1074 mLRU.erase(id);
1046 // Read the entry 1075 // Read the entry
1047 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); 1076 idx_entry_map_t::iterator iter = mUpdatedEntryMap.find(idx) ;
1048 LLAPRFile* aprfile = openHeaderEntriesFile(true, offset); 1077 if(iter != mUpdatedEntryMap.end())
1049 S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry)); 1078 {
1050 llassert_always(bytes_read == sizeof(Entry)); 1079 entry = iter->second ;
1051 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize); 1080 }
1052 closeHeaderEntriesFile(); 1081 else
1082 {
1083 readEntryFromHeaderImmediately(idx, entry) ;
1084 }
1085 if(entry.mImageSize <= entry.mBodySize)//it happens on 64-bit systems, do not know why
1086 {
1087 llwarns << "corrupted entry: " << id << " entry image size: " << entry.mImageSize << " entry body size: " << entry.mBodySize << llendl ;
1088
1089 //erase this entry and the cached texture from the cache.
1090 std::string tex_filename = getTextureFileName(id);
1091 removeEntry(idx, entry, tex_filename) ;
1092 mUpdatedEntryMap.erase(idx) ;
1093 idx = -1 ;
1094 }
1053 } 1095 }
1054 return idx; 1096 return idx;
1055} 1097}
1056 1098
1057void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry) 1099//mHeaderMutex is locked before calling this.
1100void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool write_header)
1101{
1102 LLAPRFile* aprfile ;
1103 S32 bytes_written ;
1104 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1105 if(write_header)
1106 {
1107 aprfile = openHeaderEntriesFile(false, 0);
1108 bytes_written = aprfile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ;
1109 if(bytes_written != sizeof(EntriesInfo))
1110 {
1111 clearCorruptedCache() ; //clear the cache.
1112 idx = -1 ;//mark the idx invalid.
1113 return ;
1114 }
1115
1116 mHeaderAPRFile->seek(APR_SET, offset);
1117 }
1118 else
1119 {
1120 aprfile = openHeaderEntriesFile(false, offset);
1121 }
1122 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
1123 if(bytes_written != sizeof(Entry))
1124 {
1125 clearCorruptedCache() ; //clear the cache.
1126 idx = -1 ;//mark the idx invalid.
1127
1128 return ;
1129 }
1130
1131 closeHeaderEntriesFile();
1132 mUpdatedEntryMap.erase(idx) ;
1133}
1134
1135//mHeaderMutex is locked before calling this.
1136void LLTextureCache::readEntryFromHeaderImmediately(S32& idx, Entry& entry)
1137{
1138 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
1139 LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
1140 S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
1141 closeHeaderEntriesFile();
1142
1143 if(bytes_read != sizeof(Entry))
1144 {
1145 clearCorruptedCache() ; //clear the cache.
1146 idx = -1 ;//mark the idx invalid.
1147 }
1148}
1149
1150//mHeaderMutex is locked before calling this.
1151//update an existing entry time stamp, delay writing.
1152void LLTextureCache::updateEntryTimeStamp(S32 idx, Entry& entry)
1058{ 1153{
1154 static const U32 MAX_ENTRIES_WITHOUT_TIME_STAMP = (U32)(LLTextureCache::sCacheMaxEntries * 0.75f) ;
1155
1156 if(mHeaderEntriesInfo.mEntries < MAX_ENTRIES_WITHOUT_TIME_STAMP)
1157 {
1158 return ; //there are enough empty entry index space, no need to stamp time.
1159 }
1160
1059 if (idx >= 0) 1161 if (idx >= 0)
1060 { 1162 {
1061 if (!mReadOnly) 1163 if (!mReadOnly)
1062 { 1164 {
1063 entry.mTime = time(NULL); 1165 entry.mTime = time(NULL);
1064 if(entry.mImageSize < entry.mBodySize) 1166 mUpdatedEntryMap[idx] = entry ;
1065 { 1167 }
1066 // Just say no, due to my messing around to cache discards other than 0 we can end up here 1168 }
1067 // after recalling an image from cache at a lower discard than cached. RC 1169}
1068 return;
1069 }
1070 1170
1071 llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize); 1171//update an existing entry, write to header file immediately.
1072 if (entry.mBodySize > 0) 1172bool LLTextureCache::updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 new_data_size)
1073 { 1173{
1074 mTexturesSizeMap[entry.mID] = entry.mBodySize; 1174 S32 new_body_size = llmax(0, new_data_size - TEXTURE_CACHE_ENTRY_SIZE) ;
1075 } 1175
1076// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl; 1176 if(new_image_size == entry.mImageSize && new_body_size == entry.mBodySize)
1077 S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); 1177 {
1078 LLAPRFile* aprfile = openHeaderEntriesFile(false, offset); 1178 return true ; //nothing changed.
1079 S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry)); 1179 }
1080 llassert_always(bytes_written == sizeof(Entry)); 1180 else
1081 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx); 1181 {
1082 closeHeaderEntriesFile(); 1182 bool purge = false ;
1183
1184 lockHeaders() ;
1185
1186 bool update_header = false ;
1187 if(entry.mImageSize < 0) //is a brand-new entry
1188 {
1189 mHeaderIDMap[entry.mID] = idx;
1190 mTexturesSizeMap[entry.mID] = new_body_size ;
1191 mTexturesSizeTotal += new_body_size ;
1192
1193 // Update Header
1194 update_header = true ;
1195 }
1196 else if (entry.mBodySize != new_body_size)
1197 {
1198 //already in mHeaderIDMap.
1199 mTexturesSizeMap[entry.mID] = new_body_size ;
1200 mTexturesSizeTotal -= entry.mBodySize ;
1201 mTexturesSizeTotal += new_body_size ;
1202 }
1203 entry.mTime = time(NULL);
1204 entry.mImageSize = new_image_size ;
1205 entry.mBodySize = new_body_size ;
1206
1207 writeEntryToHeaderImmediately(idx, entry, update_header) ;
1208
1209 if (mTexturesSizeTotal > sCacheMaxTexturesSize)
1210 {
1211 purge = true;
1212 }
1213
1214 unlockHeaders() ;
1215
1216 if (purge)
1217 {
1218 mDoPurge = TRUE;
1083 } 1219 }
1084 } 1220 }
1221
1222 return false ;
1085} 1223}
1086 1224
1087U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) 1225U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
@@ -1093,7 +1231,21 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
1093 mFreeList.clear(); 1231 mFreeList.clear();
1094 mTexturesSizeTotal = 0; 1232 mTexturesSizeTotal = 0;
1095 1233
1096 LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo)); 1234 LLAPRFile* aprfile = NULL;
1235 if(mUpdatedEntryMap.empty())
1236 {
1237 aprfile = openHeaderEntriesFile(true, (S32)sizeof(EntriesInfo));
1238 }
1239 else //update the header file first.
1240 {
1241 aprfile = openHeaderEntriesFile(false, 0);
1242 updatedHeaderEntriesFile() ;
1243 if(!aprfile)
1244 {
1245 return 0;
1246 }
1247 aprfile->seek(APR_SET, (S32)sizeof(EntriesInfo));
1248 }
1097 for (U32 idx=0; idx<num_entries; idx++) 1249 for (U32 idx=0; idx<num_entries; idx++)
1098 { 1250 {
1099 Entry entry; 1251 Entry entry;
@@ -1107,19 +1259,15 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
1107 } 1259 }
1108 entries.push_back(entry); 1260 entries.push_back(entry);
1109// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl; 1261// llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
1110 if (entry.mImageSize < 0) 1262 if(entry.mImageSize > entry.mBodySize)
1111 { 1263 {
1112 mFreeList.insert(idx); 1264 mHeaderIDMap[entry.mID] = idx;
1265 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1266 mTexturesSizeTotal += entry.mBodySize;
1113 } 1267 }
1114 else 1268 else
1115 { 1269 {
1116 mHeaderIDMap[entry.mID] = idx; 1270 mFreeList.insert(idx);
1117 if (entry.mBodySize > 0)
1118 {
1119 mTexturesSizeMap[entry.mID] = entry.mBodySize;
1120 mTexturesSizeTotal += entry.mBodySize;
1121 }
1122 llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
1123 } 1271 }
1124 } 1272 }
1125 closeHeaderEntriesFile(); 1273 closeHeaderEntriesFile();
@@ -1137,13 +1285,65 @@ void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
1137 for (S32 idx=0; idx<num_entries; idx++) 1285 for (S32 idx=0; idx<num_entries; idx++)
1138 { 1286 {
1139 S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry)); 1287 S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
1140 llassert_always(bytes_written == sizeof(Entry)); 1288 if(bytes_written != sizeof(Entry))
1289 {
1290 clearCorruptedCache() ; //clear the cache.
1291 return ;
1292 }
1141 } 1293 }
1142 mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
1143 closeHeaderEntriesFile(); 1294 closeHeaderEntriesFile();
1144 } 1295 }
1145} 1296}
1146 1297
1298void LLTextureCache::writeUpdatedEntries()
1299{
1300 lockHeaders() ;
1301 if (!mReadOnly && !mUpdatedEntryMap.empty())
1302 {
1303 openHeaderEntriesFile(false, 0);
1304 updatedHeaderEntriesFile() ;
1305 closeHeaderEntriesFile();
1306 }
1307 unlockHeaders() ;
1308}
1309
1310//mHeaderMutex is locked and mHeaderAPRFile is created before calling this.
1311void LLTextureCache::updatedHeaderEntriesFile()
1312{
1313 if (!mReadOnly && !mUpdatedEntryMap.empty() && mHeaderAPRFile)
1314 {
1315 //entriesInfo
1316 mHeaderAPRFile->seek(APR_SET, 0);
1317 S32 bytes_written = mHeaderAPRFile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ;
1318 if(bytes_written != sizeof(EntriesInfo))
1319 {
1320 clearCorruptedCache() ; //clear the cache.
1321 return ;
1322 }
1323
1324 //write each updated entry
1325 S32 entry_size = (S32)sizeof(Entry) ;
1326 S32 prev_idx = -1 ;
1327 S32 delta_idx ;
1328 for (idx_entry_map_t::iterator iter = mUpdatedEntryMap.begin(); iter != mUpdatedEntryMap.end(); ++iter)
1329 {
1330 delta_idx = iter->first - prev_idx - 1;
1331 prev_idx = iter->first ;
1332 if(delta_idx)
1333 {
1334 mHeaderAPRFile->seek(APR_CUR, delta_idx * entry_size);
1335 }
1336
1337 bytes_written = mHeaderAPRFile->write((void*)(&iter->second), entry_size);
1338 if(bytes_written != entry_size)
1339 {
1340 clearCorruptedCache() ; //clear the cache.
1341 return ;
1342 }
1343 }
1344 mUpdatedEntryMap.clear() ;
1345 }
1346}
1147//---------------------------------------------------------------------------- 1347//----------------------------------------------------------------------------
1148 1348
1149// Called from either the main thread or the worker thread 1349// Called from either the main thread or the worker thread
@@ -1169,28 +1369,27 @@ void LLTextureCache::readHeaderCache()
1169 if (num_entries) 1369 if (num_entries)
1170 { 1370 {
1171 U32 empty_entries = 0; 1371 U32 empty_entries = 0;
1172 typedef std::pair<U32, LLUUID> lru_data_t; 1372 typedef std::pair<U32, S32> lru_data_t;
1173 std::set<lru_data_t> lru; 1373 std::set<lru_data_t> lru;
1174 std::vector<LLUUID> purge_list; 1374 std::set<U32> purge_list;
1175 for (U32 i=0; i<num_entries; i++) 1375 for (U32 i=0; i<num_entries; i++)
1176 { 1376 {
1177 Entry& entry = entries[i]; 1377 Entry& entry = entries[i];
1178 const LLUUID& id = entry.mID; 1378 if (entry.mImageSize <= 0)
1179 if (entry.mImageSize < 0)
1180 { 1379 {
1181 // This will be in the Free List, don't put it in the LRU 1380 // This will be in the Free List, don't put it in the LRU
1182 ++empty_entries; 1381 ++empty_entries;
1183 } 1382 }
1184 else 1383 else
1185 { 1384 {
1186 lru.insert(std::make_pair(entry.mTime, id)); 1385 lru.insert(std::make_pair(entry.mTime, i));
1187 if (entry.mBodySize > 0) 1386 if (entry.mBodySize > 0)
1188 { 1387 {
1189 if (entry.mBodySize > entry.mImageSize) 1388 if (entry.mBodySize > entry.mImageSize)
1190 { 1389 {
1191 // Shouldn't happen, failsafe only 1390 // Shouldn't happen, failsafe only
1192 llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl; 1391 llwarns << "Bad entry: " << i << ": " << entry.mID << ": BodySize: " << entry.mBodySize << llendl;
1193 purge_list.push_back(id); 1392 purge_list.insert(i);
1194 } 1393 }
1195 } 1394 }
1196 } 1395 }
@@ -1200,22 +1399,24 @@ void LLTextureCache::readHeaderCache()
1200 // Special case: cache size was reduced, need to remove entries 1399 // Special case: cache size was reduced, need to remove entries
1201 // Note: After we prune entries, we will call this again and create the LRU 1400 // Note: After we prune entries, we will call this again and create the LRU
1202 U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries; 1401 U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
1402 llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl;
1203 if (entries_to_purge > 0) 1403 if (entries_to_purge > 0)
1204 { 1404 {
1205 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter) 1405 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1206 { 1406 {
1207 purge_list.push_back(iter->second); 1407 purge_list.insert(iter->second);
1208 if (--entries_to_purge <= 0) 1408 if (purge_list.size() >= entries_to_purge)
1209 break; 1409 break;
1210 } 1410 }
1211 } 1411 }
1412 llassert_always(purge_list.size() >= entries_to_purge);
1212 } 1413 }
1213 else 1414 else
1214 { 1415 {
1215 S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE); 1416 S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
1216 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter) 1417 for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
1217 { 1418 {
1218 mLRU.insert(iter->second); 1419 mLRU.insert(entries[iter->second].mID);
1219// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl; 1420// llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
1220 if (--lru_entries <= 0) 1421 if (--lru_entries <= 0)
1221 break; 1422 break;
@@ -1224,11 +1425,10 @@ void LLTextureCache::readHeaderCache()
1224 1425
1225 if (purge_list.size() > 0) 1426 if (purge_list.size() > 0)
1226 { 1427 {
1227 for (std::vector<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter) 1428 for (std::set<U32>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
1228 { 1429 {
1229 mHeaderMutex.unlock(); 1430 std::string tex_filename = getTextureFileName(entries[*iter].mID);
1230 removeFromCache(*iter); 1431 removeEntry((S32)*iter, entries[*iter], tex_filename);
1231 mHeaderMutex.lock();
1232 } 1432 }
1233 // If we removed any entries, we need to rebuild the entries list, 1433 // If we removed any entries, we need to rebuild the entries list,
1234 // write the header, and call this again 1434 // write the header, and call this again
@@ -1236,13 +1436,14 @@ void LLTextureCache::readHeaderCache()
1236 for (U32 i=0; i<num_entries; i++) 1436 for (U32 i=0; i<num_entries; i++)
1237 { 1437 {
1238 const Entry& entry = entries[i]; 1438 const Entry& entry = entries[i];
1239 if (entry.mImageSize >=0) 1439 if (entry.mImageSize > 0)
1240 { 1440 {
1241 new_entries.push_back(entry); 1441 new_entries.push_back(entry);
1242 } 1442 }
1243 } 1443 }
1244 llassert_always(new_entries.size() <= sCacheMaxEntries); 1444 llassert_always(new_entries.size() <= sCacheMaxEntries);
1245 mHeaderEntriesInfo.mEntries = new_entries.size(); 1445 mHeaderEntriesInfo.mEntries = new_entries.size();
1446 writeEntriesHeader();
1246 writeEntriesAndClose(new_entries); 1447 writeEntriesAndClose(new_entries);
1247 mHeaderMutex.unlock(); // unlock the mutex before calling again 1448 mHeaderMutex.unlock(); // unlock the mutex before calling again
1248 readHeaderCache(); // repeat with new entries file 1449 readHeaderCache(); // repeat with new entries file
@@ -1250,7 +1451,7 @@ void LLTextureCache::readHeaderCache()
1250 } 1451 }
1251 else 1452 else
1252 { 1453 {
1253 writeEntriesAndClose(entries); 1454 //entries are not changed, nothing here.
1254 } 1455 }
1255 } 1456 }
1256 } 1457 }
@@ -1259,6 +1460,29 @@ void LLTextureCache::readHeaderCache()
1259 1460
1260////////////////////////////////////////////////////////////////////////////// 1461//////////////////////////////////////////////////////////////////////////////
1261 1462
1463//the header mutex is locked before calling this.
1464void LLTextureCache::clearCorruptedCache()
1465{
1466 llwarns << "the texture cache is corrupted, need to be cleared." << llendl ;
1467
1468 closeHeaderEntriesFile();//close possible file handler
1469 purgeAllTextures(false) ; //clear the cache.
1470
1471 if (!mReadOnly) //regenerate the directory tree if not exists.
1472 {
1473 LLFile::mkdir(mTexturesDirName);
1474
1475 const char* subdirs = "0123456789abcdef";
1476 for (S32 i=0; i<16; i++)
1477 {
1478 std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i];
1479 LLFile::mkdir(dirname);
1480 }
1481 }
1482
1483 return ;
1484}
1485
1262void LLTextureCache::purgeAllTextures(bool purge_directories) 1486void LLTextureCache::purgeAllTextures(bool purge_directories)
1263{ 1487{
1264 if (!mReadOnly) 1488 if (!mReadOnly)
@@ -1269,6 +1493,7 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
1269 for (S32 i=0; i<16; i++) 1493 for (S32 i=0; i<16; i++)
1270 { 1494 {
1271 std::string dirname = mTexturesDirName + delem + subdirs[i]; 1495 std::string dirname = mTexturesDirName + delem + subdirs[i];
1496 llinfos << "Deleting files in directory: " << dirname << llendl;
1272 gDirUtilp->deleteFilesInDir(dirname,mask); 1497 gDirUtilp->deleteFilesInDir(dirname,mask);
1273 if (purge_directories) 1498 if (purge_directories)
1274 { 1499 {
@@ -1277,19 +1502,23 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
1277 } 1502 }
1278 if (purge_directories) 1503 if (purge_directories)
1279 { 1504 {
1505 gDirUtilp->deleteFilesInDir(mTexturesDirName, mask);
1280 LLFile::rmdir(mTexturesDirName); 1506 LLFile::rmdir(mTexturesDirName);
1281 } 1507 }
1282 } 1508 }
1283 mHeaderIDMap.clear(); 1509 mHeaderIDMap.clear();
1284 mTexturesSizeMap.clear(); 1510 mTexturesSizeMap.clear();
1285 mTexturesSizeTotal = 0; 1511 mTexturesSizeTotal = 0;
1286 mFreeList.clear(); 1512 mFreeList.clear();
1287 mTexturesSizeTotal = 0; 1513 mTexturesSizeTotal = 0;
1514 mUpdatedEntryMap.clear();
1288 1515
1289 // Info with 0 entries 1516 // Info with 0 entries
1290 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion; 1517 mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
1291 mHeaderEntriesInfo.mEntries = 0; 1518 mHeaderEntriesInfo.mEntries = 0;
1292 writeEntriesHeader(); 1519 writeEntriesHeader();
1520
1521 llinfos << "The entire texture cache is cleared." << llendl ;
1293} 1522}
1294 1523
1295void LLTextureCache::purgeTextures(bool validate) 1524void LLTextureCache::purgeTextures(bool validate)
@@ -1314,7 +1543,6 @@ void LLTextureCache::purgeTextures(bool validate)
1314 U32 num_entries = openAndReadEntries(entries); 1543 U32 num_entries = openAndReadEntries(entries);
1315 if (!num_entries) 1544 if (!num_entries)
1316 { 1545 {
1317 writeEntriesAndClose(entries);
1318 return; // nothing to purge 1546 return; // nothing to purge
1319 } 1547 }
1320 1548
@@ -1333,6 +1561,10 @@ void LLTextureCache::purgeTextures(bool validate)
1333 time_idx_set.insert(std::make_pair(entries[idx].mTime, idx)); 1561 time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
1334// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl; 1562// llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
1335 } 1563 }
1564 else
1565 {
1566 llerrs << "mTexturesSizeMap / mHeaderIDMap corrupted." << llendl ;
1567 }
1336 } 1568 }
1337 } 1569 }
1338 1570
@@ -1384,11 +1616,8 @@ void LLTextureCache::purgeTextures(bool validate)
1384 { 1616 {
1385 purge_count++; 1617 purge_count++;
1386 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL; 1618 LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
1387 LLAPRFile::remove(filename); 1619 removeEntry(idx, entries[idx], filename) ;
1388 cache_size -= entries[idx].mBodySize; 1620 cache_size -= entries[idx].mBodySize;
1389 mTexturesSizeTotal -= entries[idx].mBodySize;
1390 entries[idx].mBodySize = 0;
1391 mTexturesSizeMap.erase(entries[idx].mID);
1392 } 1621 }
1393 } 1622 }
1394 1623
@@ -1396,11 +1625,8 @@ void LLTextureCache::purgeTextures(bool validate)
1396 1625
1397 writeEntriesAndClose(entries); 1626 writeEntriesAndClose(entries);
1398 1627
1399 if (!mThreaded) 1628 // *FIX:Mani - watchdog back on.
1400 { 1629 LLAppViewer::instance()->resumeMainloopTimeout();
1401 // *FIX:Mani - watchdog back on.
1402 LLAppViewer::instance()->resumeMainloopTimeout();
1403 }
1404 1630
1405 LL_INFOS("TextureCache") << "TEXTURE CACHE:" 1631 LL_INFOS("TextureCache") << "TEXTURE CACHE:"
1406 << " PURGED: " << purge_count 1632 << " PURGED: " << purge_count
@@ -1438,40 +1664,38 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
1438// Called from work thread 1664// Called from work thread
1439 1665
1440// Reads imagesize from the header, updates timestamp 1666// Reads imagesize from the header, updates timestamp
1441S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize) 1667S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, Entry& entry)
1442{ 1668{
1443 LLMutexLock lock(&mHeaderMutex); 1669 LLMutexLock lock(&mHeaderMutex);
1444 Entry entry;
1445 S32 idx = openAndReadEntry(id, entry, false); 1670 S32 idx = openAndReadEntry(id, entry, false);
1446 if (idx >= 0) 1671 if (idx >= 0)
1447 { 1672 {
1448 imagesize = entry.mImageSize; 1673 updateEntryTimeStamp(idx, entry); // updates time
1449 writeEntryAndClose(idx, entry); // updates time
1450 } 1674 }
1451 return idx; 1675 return idx;
1452} 1676}
1453 1677
1454// Writes imagesize to the header, updates timestamp 1678// Writes imagesize to the header, updates timestamp
1455S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize) 1679S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize)
1456{ 1680{
1457 mHeaderMutex.lock(); 1681 mHeaderMutex.lock();
1458 llassert_always(imagesize >= 0);
1459 Entry entry;
1460 S32 idx = openAndReadEntry(id, entry, true); 1682 S32 idx = openAndReadEntry(id, entry, true);
1683 mHeaderMutex.unlock();
1684
1461 if (idx >= 0) 1685 if (idx >= 0)
1462 { 1686 {
1463 entry.mImageSize = imagesize; 1687 updateEntry(idx, entry, imagesize, datasize);
1464 writeEntryAndClose(idx, entry);
1465 mHeaderMutex.unlock();
1466 } 1688 }
1467 else // retry 1689
1690 if(idx < 0) // retry
1468 { 1691 {
1469 mHeaderMutex.unlock();
1470 readHeaderCache(); // We couldn't write an entry, so refresh the LRU 1692 readHeaderCache(); // We couldn't write an entry, so refresh the LRU
1693
1471 mHeaderMutex.lock(); 1694 mHeaderMutex.lock();
1472 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); 1695 llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
1473 mHeaderMutex.unlock(); 1696 mHeaderMutex.unlock();
1474 idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion 1697
1698 idx = setHeaderCacheEntry(id, entry, imagesize, datasize); // assert above ensures no inf. recursion
1475 } 1699 }
1476 return idx; 1700 return idx;
1477} 1701}
@@ -1508,39 +1732,34 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 pri
1508 return handle; 1732 return handle;
1509} 1733}
1510 1734
1511// Return true if the handle is not valid, which is the case 1735
1512// when the worker was already deleted or is scheduled for deletion.
1513//
1514// If the handle exists and a call to worker->complete() returns
1515// true or abort is true, then the handle is removed and the worker
1516// scheduled for deletion.
1517bool LLTextureCache::readComplete(handle_t handle, bool abort) 1736bool LLTextureCache::readComplete(handle_t handle, bool abort)
1518{ 1737{
1519 lockWorkers(); // Needed for access to mReaders. 1738 lockWorkers();
1520
1521 handle_map_t::iterator iter = mReaders.find(handle); 1739 handle_map_t::iterator iter = mReaders.find(handle);
1522 bool handle_is_valid = iter != mReaders.end();
1523 llassert_always(handle_is_valid || abort);
1524 LLTextureCacheWorker* worker = NULL; 1740 LLTextureCacheWorker* worker = NULL;
1525 bool delete_worker = false; 1741 bool complete = false;
1526 1742 if (iter != mReaders.end())
1527 if (handle_is_valid)
1528 { 1743 {
1529 worker = iter->second; 1744 worker = iter->second;
1530 delete_worker = worker->complete() || abort; 1745 complete = worker->complete();
1531 if (delete_worker) 1746
1747 if(!complete && abort)
1532 { 1748 {
1533 mReaders.erase(handle); 1749 abortRequest(handle, true) ;
1534 handle_is_valid = false;
1535 } 1750 }
1536 } 1751 }
1537 1752 if (worker && (complete || abort))
1538 unlockWorkers(); 1753 {
1539 1754 mReaders.erase(iter);
1540 if (delete_worker) worker->scheduleDelete(); 1755 unlockWorkers();
1541 1756 worker->scheduleDelete();
1542 // Return false if the handle is (still) valid. 1757 }
1543 return !handle_is_valid; 1758 else
1759 {
1760 unlockWorkers();
1761 }
1762 return (complete || abort);
1544} 1763}
1545 1764
1546LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority, 1765LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority,
@@ -1573,20 +1792,20 @@ bool LLTextureCache::writeComplete(handle_t handle, bool abort)
1573{ 1792{
1574 lockWorkers(); 1793 lockWorkers();
1575 handle_map_t::iterator iter = mWriters.find(handle); 1794 handle_map_t::iterator iter = mWriters.find(handle);
1576 llassert_always(iter != mWriters.end()); 1795 llassert(iter != mWriters.end());
1577 LLTextureCacheWorker* worker = iter->second; 1796 if (iter != mWriters.end())
1578 if (worker->complete() || abort)
1579 {
1580 mWriters.erase(handle);
1581 unlockWorkers();
1582 worker->scheduleDelete();
1583 return true;
1584 }
1585 else
1586 { 1797 {
1587 unlockWorkers(); 1798 LLTextureCacheWorker* worker = iter->second;
1588 return false; 1799 if (worker->complete() || abort)
1800 {
1801 mWriters.erase(handle);
1802 unlockWorkers();
1803 worker->scheduleDelete();
1804 return true;
1805 }
1589 } 1806 }
1807 unlockWorkers();
1808 return false;
1590} 1809}
1591 1810
1592void LLTextureCache::prioritizeWrite(handle_t handle) 1811void LLTextureCache::prioritizeWrite(handle_t handle)
@@ -1605,38 +1824,56 @@ void LLTextureCache::addCompleted(Responder* responder, bool success)
1605 1824
1606////////////////////////////////////////////////////////////////////////////// 1825//////////////////////////////////////////////////////////////////////////////
1607 1826
1608// Called from MAIN thread (endWork()) 1827//called after mHeaderMutex is locked.
1828void LLTextureCache::removeCachedTexture(const LLUUID& id)
1829{
1830 if(mTexturesSizeMap.find(id) != mTexturesSizeMap.end())
1831 {
1832 mTexturesSizeTotal -= mTexturesSizeMap[id] ;
1833 mTexturesSizeMap.erase(id);
1834 }
1835 mHeaderIDMap.erase(id);
1836 LLAPRFile::remove(getTextureFileName(id));
1837}
1609 1838
1610bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) 1839//called after mHeaderMutex is locked.
1840void LLTextureCache::removeEntry(S32 idx, Entry& entry, std::string& filename)
1611{ 1841{
1612 if (!mReadOnly) 1842 if(idx >= 0) //valid entry
1613 { 1843 {
1614 LLMutexLock lock(&mHeaderMutex); 1844 entry.mImageSize = -1;
1615 Entry entry; 1845 entry.mBodySize = 0;
1616 S32 idx = openAndReadEntry(id, entry, false); 1846 mHeaderIDMap.erase(entry.mID);
1617 if (idx >= 0) 1847 mTexturesSizeMap.erase(entry.mID);
1618 { 1848
1619 entry.mImageSize = -1; 1849 mTexturesSizeTotal -= entry.mBodySize;
1620 entry.mBodySize = 0; 1850 mFreeList.insert(idx);
1621 writeEntryAndClose(idx, entry);
1622 mFreeList.insert(idx);
1623 mHeaderIDMap.erase(id);
1624 mTexturesSizeMap.erase(id);
1625 return true;
1626 }
1627 } 1851 }
1628 return false; 1852
1853 LLAPRFile::remove(filename);
1629} 1854}
1630 1855
1631void LLTextureCache::removeFromCache(const LLUUID& id) 1856bool LLTextureCache::removeFromCache(const LLUUID& id)
1632{ 1857{
1633 //llwarns << "Removing texture from cache: " << id << llendl; 1858 //llwarns << "Removing texture from cache: " << id << llendl;
1859 bool ret = false ;
1634 if (!mReadOnly) 1860 if (!mReadOnly)
1635 { 1861 {
1636 removeHeaderCacheEntry(id); 1862 lockHeaders() ;
1637 LLMutexLock lock(&mHeaderMutex); 1863
1638 LLAPRFile::remove(getTextureFileName(id)); 1864 Entry entry;
1865 S32 idx = openAndReadEntry(id, entry, false);
1866 std::string tex_filename = getTextureFileName(id);
1867 removeEntry(idx, entry, tex_filename) ;
1868 if (idx >= 0)
1869 {
1870 writeEntryToHeaderImmediately(idx, entry);
1871 ret = true;
1872 }
1873
1874 unlockHeaders() ;
1639 } 1875 }
1876 return ret ;
1640} 1877}
1641 1878
1642////////////////////////////////////////////////////////////////////////////// 1879//////////////////////////////////////////////////////////////////////////////
diff --git a/linden/indra/newview/lltexturecache.h b/linden/indra/newview/lltexturecache.h
index 45804c2..f80be00 100644
--- a/linden/indra/newview/lltexturecache.h
+++ b/linden/indra/newview/lltexturecache.h
@@ -40,6 +40,7 @@
40 40
41#include "llworkerthread.h" 41#include "llworkerthread.h"
42 42
43class LLImageFormatted;
43class LLTextureCacheWorker; 44class LLTextureCacheWorker;
44 45
45class LLTextureCache : public LLWorkerThread 46class LLTextureCache : public LLWorkerThread
@@ -58,10 +59,16 @@ private:
58 }; 59 };
59 struct Entry 60 struct Entry
60 { 61 {
61 Entry() {} 62 Entry() :
63 mBodySize(0),
64 mImageSize(0),
65 mTime(0)
66 {
67 }
62 Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) : 68 Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) :
63 mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {} 69 mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {}
64 void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; } 70 void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; }
71 Entry& operator=(const Entry& entry) {mID = entry.mID, mImageSize = entry.mImageSize; mBodySize = entry.mBodySize; mTime = entry.mTime; return *this;}
65 LLUUID mID; // 16 bytes 72 LLUUID mID; // 16 bytes
66 S32 mImageSize; // total size of image if known 73 S32 mImageSize; // total size of image if known
67 S32 mBodySize; // size of body file in body cache 74 S32 mBodySize; // size of body file in body cache
@@ -103,7 +110,8 @@ public:
103 /*virtual*/ S32 update(U32 max_time_ms); 110 /*virtual*/ S32 update(U32 max_time_ms);
104 111
105 void purgeCache(ELLPath location); 112 void purgeCache(ELLPath location);
106 S64 initCache(ELLPath location, S64 maxsize, BOOL read_only); 113 void setReadOnly(BOOL read_only) ;
114 S64 initCache(ELLPath location, S64 maxsize, BOOL disable_texture_cache);
107 115
108 handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size, 116 handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size,
109 ReadResponder* responder); 117 ReadResponder* responder);
@@ -116,7 +124,7 @@ public:
116 bool writeComplete(handle_t handle, bool abort = false); 124 bool writeComplete(handle_t handle, bool abort = false);
117 void prioritizeWrite(handle_t handle); 125 void prioritizeWrite(handle_t handle);
118 126
119 void removeFromCache(const LLUUID& id); 127 bool removeFromCache(const LLUUID& id);
120 128
121 // For LLTextureCacheWorker::Responder 129 // For LLTextureCacheWorker::Responder
122 LLTextureCacheWorker* getReader(handle_t handle); 130 LLTextureCacheWorker* getReader(handle_t handle);
@@ -131,10 +139,11 @@ public:
131 S64 getMaxUsage() { return sCacheMaxTexturesSize; } 139 S64 getMaxUsage() { return sCacheMaxTexturesSize; }
132 U32 getEntries() { return mHeaderEntriesInfo.mEntries; } 140 U32 getEntries() { return mHeaderEntriesInfo.mEntries; }
133 U32 getMaxEntries() { return sCacheMaxEntries; }; 141 U32 getMaxEntries() { return sCacheMaxEntries; };
142 BOOL isInCache(const LLUUID& id) ;
143 BOOL isInLocal(const LLUUID& id) ;
134 144
135protected: 145protected:
136 // Accessed by LLTextureCacheWorker 146 // Accessed by LLTextureCacheWorker
137 bool updateTextureEntryList(const LLUUID& id, S32 size);
138 std::string getLocalFileName(const LLUUID& id); 147 std::string getLocalFileName(const LLUUID& id);
139 std::string getTextureFileName(const LLUUID& id); 148 std::string getTextureFileName(const LLUUID& id);
140 void addCompleted(Responder* responder, bool success); 149 void addCompleted(Responder* responder, bool success);
@@ -145,6 +154,7 @@ protected:
145private: 154private:
146 void setDirNames(ELLPath location); 155 void setDirNames(ELLPath location);
147 void readHeaderCache(); 156 void readHeaderCache();
157 void clearCorruptedCache();
148 void purgeAllTextures(bool purge_directories); 158 void purgeAllTextures(bool purge_directories);
149 void purgeTextures(bool validate); 159 void purgeTextures(bool validate);
150 LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset); 160 LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
@@ -152,12 +162,20 @@ private:
152 void readEntriesHeader(); 162 void readEntriesHeader();
153 void writeEntriesHeader(); 163 void writeEntriesHeader();
154 S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create); 164 S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
155 void writeEntryAndClose(S32 idx, Entry& entry); 165 bool updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 new_body_size);
166 void updateEntryTimeStamp(S32 idx, Entry& entry) ;
156 U32 openAndReadEntries(std::vector<Entry>& entries); 167 U32 openAndReadEntries(std::vector<Entry>& entries);
157 void writeEntriesAndClose(const std::vector<Entry>& entries); 168 void writeEntriesAndClose(const std::vector<Entry>& entries);
158 S32 getHeaderCacheEntry(const LLUUID& id, S32& imagesize); 169 void readEntryFromHeaderImmediately(S32& idx, Entry& entry) ;
159 S32 setHeaderCacheEntry(const LLUUID& id, S32 imagesize); 170 void writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool write_header = false) ;
160 bool removeHeaderCacheEntry(const LLUUID& id); 171 void removeEntry(S32 idx, Entry& entry, std::string& filename);
172 void removeCachedTexture(const LLUUID& id) ;
173 S32 getHeaderCacheEntry(const LLUUID& id, Entry& entry);
174 S32 setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize);
175 void writeUpdatedEntries() ;
176 void updatedHeaderEntriesFile() ;
177 void lockHeaders() { mHeaderMutex.lock(); }
178 void unlockHeaders() { mHeaderMutex.unlock(); }
161 179
162private: 180private:
163 // Internal 181 // Internal
@@ -194,6 +212,9 @@ private:
194 S64 mTexturesSizeTotal; 212 S64 mTexturesSizeTotal;
195 LLAtomic32<BOOL> mDoPurge; 213 LLAtomic32<BOOL> mDoPurge;
196 214
215 typedef std::map<S32, Entry> idx_entry_map_t;
216 idx_entry_map_t mUpdatedEntryMap;
217
197 // Statics 218 // Statics
198 static F32 sHeaderCacheVersion; 219 static F32 sHeaderCacheVersion;
199 static U32 sCacheMaxEntries; 220 static U32 sCacheMaxEntries;
diff --git a/linden/indra/newview/lltexturefetch.cpp b/linden/indra/newview/lltexturefetch.cpp
index 2184478..427e55a 100644
--- a/linden/indra/newview/lltexturefetch.cpp
+++ b/linden/indra/newview/lltexturefetch.cpp
@@ -1500,6 +1500,8 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
1500 1500
1501LLTextureFetch::~LLTextureFetch() 1501LLTextureFetch::~LLTextureFetch()
1502{ 1502{
1503 clearDeleteList() ;
1504
1503 // ~LLQueuedThread() called here 1505 // ~LLQueuedThread() called here
1504} 1506}
1505 1507