diff options
Diffstat (limited to '')
-rw-r--r-- | linden/indra/llcommon/llworkerthread.cpp | 39 | ||||
-rw-r--r-- | linden/indra/llcommon/llworkerthread.h | 8 | ||||
-rw-r--r-- | linden/indra/newview/lltexturecache.cpp | 679 | ||||
-rw-r--r-- | linden/indra/newview/lltexturecache.h | 37 | ||||
-rw-r--r-- | linden/indra/newview/lltexturefetch.cpp | 2 |
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. | ||
64 | void 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 |
64 | S32 LLWorkerThread::update(U32 max_time_ms) | 85 | S32 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() | |||
364 | void LLWorkerClass::setPriority(U32 priority) | 399 | void 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 | ||
83 | protected: | ||
84 | void clearDeleteList() ; | ||
85 | |||
83 | private: | 86 | private: |
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 | |||
101 | private: | ||
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 | ||
55 | const 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. |
55 | const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE;//1024; | ||
56 | const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit | 56 | const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit |
57 | const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate) | 57 | const 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 | ||
748 | LLTextureCache::~LLTextureCache() | 750 | LLTextureCache::~LLTextureCache() |
749 | { | 751 | { |
752 | clearDeleteList() ; | ||
753 | writeUpdatedEntries() ; | ||
750 | } | 754 | } |
751 | 755 | ||
752 | ////////////////////////////////////////////////////////////////////////////// | 756 | ////////////////////////////////////////////////////////////////////////////// |
@@ -754,6 +758,9 @@ LLTextureCache::~LLTextureCache() | |||
754 | //virtual | 758 | //virtual |
755 | S32 LLTextureCache::update(U32 max_time_ms) | 759 | S32 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 | ||
814 | bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize) | 827 | //debug |
828 | BOOL 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 | ||
837 | BOOL 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 | ||
899 | S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only) | 909 | //is called in the main thread before initCache(...) is called. |
910 | void LLTextureCache::setReadOnly(BOOL read_only) | ||
900 | { | 911 | { |
901 | mReadOnly = read_only; | 912 | mReadOnly = read_only; |
902 | 913 | } | |
914 | |||
915 | //called in the main thread. | ||
916 | S64 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 | ||
947 | void LLTextureCache::closeHeaderEntriesFile() | 979 | void 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 | ||
964 | void LLTextureCache::writeEntriesHeader() | 1006 | void LLTextureCache::writeEntriesHeader() |
@@ -970,8 +1012,7 @@ void LLTextureCache::writeEntriesHeader() | |||
970 | } | 1012 | } |
971 | } | 1013 | } |
972 | 1014 | ||
973 | static S32 mHeaderEntriesMaxWriteIdx = 0; | 1015 | //mHeaderMutex is locked before calling this. |
974 | |||
975 | S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create) | 1016 | S32 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 | ||
1057 | void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry) | 1099 | //mHeaderMutex is locked before calling this. |
1100 | void 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. | ||
1136 | void 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. | ||
1152 | void 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) | 1172 | bool 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 | ||
1087 | U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) | 1225 | U32 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 | ||
1298 | void 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. | ||
1311 | void 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. | ||
1464 | void 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 | |||
1262 | void LLTextureCache::purgeAllTextures(bool purge_directories) | 1486 | void 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 | ||
1295 | void LLTextureCache::purgeTextures(bool validate) | 1524 | void 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 |
1441 | S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize) | 1667 | S32 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 |
1455 | S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize) | 1679 | S32 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. | ||
1517 | bool LLTextureCache::readComplete(handle_t handle, bool abort) | 1736 | bool 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 | ||
1546 | LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 priority, | 1765 | LLTextureCache::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 | ||
1592 | void LLTextureCache::prioritizeWrite(handle_t handle) | 1811 | void 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. |
1828 | void 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 | ||
1610 | bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id) | 1839 | //called after mHeaderMutex is locked. |
1840 | void 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 | ||
1631 | void LLTextureCache::removeFromCache(const LLUUID& id) | 1856 | bool 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 | ||
43 | class LLImageFormatted; | ||
43 | class LLTextureCacheWorker; | 44 | class LLTextureCacheWorker; |
44 | 45 | ||
45 | class LLTextureCache : public LLWorkerThread | 46 | class 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 | ||
135 | protected: | 145 | protected: |
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: | |||
145 | private: | 154 | private: |
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 | ||
162 | private: | 180 | private: |
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 | ||
1501 | LLTextureFetch::~LLTextureFetch() | 1501 | LLTextureFetch::~LLTextureFetch() |
1502 | { | 1502 | { |
1503 | clearDeleteList() ; | ||
1504 | |||
1503 | // ~LLQueuedThread() called here | 1505 | // ~LLQueuedThread() called here |
1504 | } | 1506 | } |
1505 | 1507 | ||