diff options
Diffstat (limited to 'indra/newview/lltexturecache.cpp')
-rw-r--r-- | indra/newview/lltexturecache.cpp | 322 |
1 files changed, 173 insertions, 149 deletions
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index df79725474..6a213309a0 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -2,31 +2,25 @@ * @file lltexturecache.cpp * @brief Object which handles local texture caching * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2009, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -391,6 +385,7 @@ bool LLTextureCacheRemoteWorker::doRead() } else { + //llinfos << "texture " << mID.asString() << " found in local_assets" << llendl; mImageSize = local_size; mImageLocal = TRUE; } @@ -401,7 +396,8 @@ bool LLTextureCacheRemoteWorker::doRead() // Second state / stage : identify the cache or not... if (!done && (mState == CACHE)) { - idx = mCache->getHeaderCacheEntry(mID, mImageSize); + LLTextureCache::Entry entry ; + idx = mCache->getHeaderCacheEntry(mID, entry); if (idx < 0) { // The texture is *not* cached. We're done here... @@ -410,6 +406,7 @@ bool LLTextureCacheRemoteWorker::doRead() } else { + mImageSize = entry.mImageSize ; // If the read offset is bigger than the header cache, we read directly from the body // Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY; @@ -531,13 +528,14 @@ bool LLTextureCacheRemoteWorker::doRead() bool LLTextureCacheRemoteWorker::doWrite() { bool done = false; - S32 idx = -1; + S32 idx = -1; // First state / stage : check that what we're trying to cache is in an OK shape if (mState == INIT) { llassert_always(mOffset == 0); // We currently do not support write offsets llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative... + llassert_always(mImageSize >= mDataSize); mState = CACHE; } @@ -547,14 +545,19 @@ bool LLTextureCacheRemoteWorker::doWrite() if (!done && (mState == CACHE)) { bool alreadyCached = false; - S32 cur_imagesize = 0; + LLTextureCache::Entry entry ; + // Checks if this image is already in the entry list - idx = mCache->getHeaderCacheEntry(mID, cur_imagesize); - if (idx >= 0 && (cur_imagesize > 0)) + idx = mCache->getHeaderCacheEntry(mID, entry); + if(idx < 0) + { + idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry. + } + else { - alreadyCached = true; // already there and non empty + alreadyCached = mCache->updateEntry(idx, entry, mImageSize, mDataSize); // update the existing entry. } - idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry + if (idx < 0) { llwarns << "LLTextureCacheWorker: " << mID @@ -564,10 +567,6 @@ bool LLTextureCacheRemoteWorker::doWrite() } else { - if (cur_imagesize > 0 && (mImageSize != cur_imagesize)) - { - alreadyCached = false; // re-write the header if the size changed in all cases - } if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)) { // Small texture already cached case: we're done with writing @@ -630,7 +629,7 @@ bool LLTextureCacheRemoteWorker::doWrite() { llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE); // wouldn't make sense to be here otherwise... S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE; - if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size)) + { // build the cache file name from the UUID std::string filename = mCache->getTextureFileName(mID); @@ -648,10 +647,7 @@ bool LLTextureCacheRemoteWorker::doWrite() done = true; } } - else - { - mDataSize = 0; // no data written - } + // Nothing else to do at that point... done = true; } @@ -825,53 +821,6 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id) return filename; } -bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize) -{ - bool res = false; - bool purge = false; - { - LLMutexLock lock(&mHeaderMutex); - size_map_t::iterator iter1 = mTexturesSizeMap.find(id); - if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize) - { - llassert_always(bodysize > 0); - - S32 oldbodysize = 0; - if (iter1 != mTexturesSizeMap.end()) - { - oldbodysize = iter1->second; - } - - Entry entry; - S32 idx = openAndReadEntry(id, entry, false); - if (idx < 0) - { - llwarns << "Failed to open entry: " << id << llendl; - removeCachedTexture(id) ; - return false; - } - else if (oldbodysize != entry.mBodySize) - { - // only happens to 64 bits systems, do not know why. - llwarns << "Entry mismatch in mTextureSizeMap / mHeaderIDMap" - << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl; - } - updateEntry(idx, entry, entry.mImageSize, bodysize); - - if (mTexturesSizeTotal > sCacheMaxTexturesSize) - { - purge = true; - } - res = true; - } - } - if (purge) - { - mDoPurge = TRUE; - } - return res; -} - //debug BOOL LLTextureCache::isInCache(const LLUUID& id) { @@ -978,7 +927,7 @@ void LLTextureCache::setReadOnly(BOOL read_only) } //called in the main thread. -S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_texture_cache) +S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache_mismatch) { llassert_always(getPending() == 0) ; //should not start accessing the texture cache before initialized. @@ -993,20 +942,23 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL disable_textu sCacheMaxTexturesSize = max_size; max_size -= sCacheMaxTexturesSize; - if(disable_texture_cache) //the texture cache is disabled - { - llinfos << "The texture cache is disabled!" << llendl ; - setReadOnly(TRUE) ; - purgeAllTextures(true); - - return max_size ; - } - LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL; setDirNames(location); + if(texture_cache_mismatch) + { + //if readonly, disable the texture cache, + //otherwise wipe out the texture cache. + purgeAllTextures(true); + + if(mReadOnly) + { + return max_size ; + } + } + if (!mReadOnly) { LLFile::mkdir(mTexturesDirName); @@ -1043,7 +995,11 @@ LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset) void LLTextureCache::closeHeaderEntriesFile() { - llassert_always(mHeaderAPRFile != NULL); + if(!mHeaderAPRFile) + { + return ; + } + delete mHeaderAPRFile; mHeaderAPRFile = NULL; } @@ -1160,7 +1116,7 @@ S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create } //mHeaderMutex is locked before calling this. -void LLTextureCache::writeEntryToHeaderImmediately(S32 idx, Entry& entry, bool write_header) +void LLTextureCache::writeEntryToHeaderImmediately(S32& idx, Entry& entry, bool write_header) { LLAPRFile* aprfile ; S32 bytes_written ; @@ -1169,7 +1125,13 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32 idx, Entry& entry, bool w { aprfile = openHeaderEntriesFile(false, 0); bytes_written = aprfile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ; - llassert_always(bytes_written == sizeof(EntriesInfo)); + if(bytes_written != sizeof(EntriesInfo)) + { + clearCorruptedCache() ; //clear the cache. + idx = -1 ;//mark the idx invalid. + return ; + } + mHeaderAPRFile->seek(APR_SET, offset); } else @@ -1177,19 +1139,31 @@ void LLTextureCache::writeEntryToHeaderImmediately(S32 idx, Entry& entry, bool w aprfile = openHeaderEntriesFile(false, offset); } bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry)); - llassert_always(bytes_written == sizeof(Entry)); + if(bytes_written != sizeof(Entry)) + { + clearCorruptedCache() ; //clear the cache. + idx = -1 ;//mark the idx invalid. + + return ; + } + closeHeaderEntriesFile(); mUpdatedEntryMap.erase(idx) ; } //mHeaderMutex is locked before calling this. -void LLTextureCache::readEntryFromHeaderImmediately(S32 idx, Entry& entry) +void LLTextureCache::readEntryFromHeaderImmediately(S32& idx, Entry& entry) { S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry); LLAPRFile* aprfile = openHeaderEntriesFile(true, offset); S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry)); - llassert_always(bytes_read == sizeof(Entry)); closeHeaderEntriesFile(); + + if(bytes_read != sizeof(Entry)) + { + clearCorruptedCache() ; //clear the cache. + idx = -1 ;//mark the idx invalid. + } } //mHeaderMutex is locked before calling this. @@ -1207,55 +1181,64 @@ void LLTextureCache::updateEntryTimeStamp(S32 idx, Entry& entry) { if (!mReadOnly) { - llassert_always(entry.mImageSize > entry.mBodySize); - entry.mTime = time(NULL); mUpdatedEntryMap[idx] = entry ; } } } -//mHeaderMutex is locked before calling this. //update an existing entry, write to header file immediately. -void LLTextureCache::updateEntry(S32 idx, Entry& entry, S32 new_image_size, S32 new_body_size) +bool LLTextureCache::updateEntry(S32& idx, Entry& entry, S32 new_image_size, S32 new_data_size) { - llassert_always(new_image_size > -1) ; - + S32 new_body_size = llmax(0, new_data_size - TEXTURE_CACHE_ENTRY_SIZE) ; + if(new_image_size == entry.mImageSize && new_body_size == entry.mBodySize) { - updateEntryTimeStamp(idx, entry) ; //nothing changed. + return true ; //nothing changed. } - else if (idx >= 0) + else { - if (!mReadOnly) - { - llassert_always(new_image_size > new_body_size) ; + bool purge = false ; - bool update_header = false ; - if(entry.mImageSize < 0) //is a brand-new entry - { - mHeaderIDMap[entry.mID] = idx; - mTexturesSizeMap[entry.mID] = new_body_size ; - mTexturesSizeTotal += new_body_size ; - - // Update Header - update_header = true ; - } - else if (entry.mBodySize != new_body_size) - { - //already in mHeaderIDMap. - mTexturesSizeMap[entry.mID] = new_body_size ; - mTexturesSizeTotal -= entry.mBodySize ; - mTexturesSizeTotal += new_body_size ; - } - entry.mTime = time(NULL); - entry.mImageSize = new_image_size ; - entry.mBodySize = new_body_size ; + lockHeaders() ; + + bool update_header = false ; + if(entry.mImageSize < 0) //is a brand-new entry + { + mHeaderIDMap[entry.mID] = idx; + mTexturesSizeMap[entry.mID] = new_body_size ; + mTexturesSizeTotal += new_body_size ; -// llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl; - writeEntryToHeaderImmediately(idx, entry, update_header) ; + // Update Header + update_header = true ; + } + else if (entry.mBodySize != new_body_size) + { + //already in mHeaderIDMap. + mTexturesSizeMap[entry.mID] = new_body_size ; + mTexturesSizeTotal -= entry.mBodySize ; + mTexturesSizeTotal += new_body_size ; + } + entry.mTime = time(NULL); + entry.mImageSize = new_image_size ; + entry.mBodySize = new_body_size ; + + writeEntryToHeaderImmediately(idx, entry, update_header) ; + + if (mTexturesSizeTotal > sCacheMaxTexturesSize) + { + purge = true; + } + + unlockHeaders() ; + + if (purge) + { + mDoPurge = TRUE; } } + + return false ; } U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) @@ -1276,6 +1259,10 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries) { aprfile = openHeaderEntriesFile(false, 0); updatedHeaderEntriesFile() ; + if(!aprfile) + { + return 0; + } aprfile->seek(APR_SET, (S32)sizeof(EntriesInfo)); } for (U32 idx=0; idx<num_entries; idx++) @@ -1317,7 +1304,11 @@ void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries) for (S32 idx=0; idx<num_entries; idx++) { S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry)); - llassert_always(bytes_written == sizeof(Entry)); + if(bytes_written != sizeof(Entry)) + { + clearCorruptedCache() ; //clear the cache. + return ; + } } closeHeaderEntriesFile(); } @@ -1343,7 +1334,11 @@ void LLTextureCache::updatedHeaderEntriesFile() //entriesInfo mHeaderAPRFile->seek(APR_SET, 0); S32 bytes_written = mHeaderAPRFile->write((U8*)&mHeaderEntriesInfo, sizeof(EntriesInfo)) ; - llassert_always(bytes_written == sizeof(EntriesInfo)); + if(bytes_written != sizeof(EntriesInfo)) + { + clearCorruptedCache() ; //clear the cache. + return ; + } //write each updated entry S32 entry_size = (S32)sizeof(Entry) ; @@ -1359,7 +1354,11 @@ void LLTextureCache::updatedHeaderEntriesFile() } bytes_written = mHeaderAPRFile->write((void*)(&iter->second), entry_size); - llassert_always(bytes_written == entry_size); + if(bytes_written != entry_size) + { + clearCorruptedCache() ; //clear the cache. + return ; + } } mUpdatedEntryMap.clear() ; } @@ -1480,6 +1479,29 @@ void LLTextureCache::readHeaderCache() ////////////////////////////////////////////////////////////////////////////// +//the header mutex is locked before calling this. +void LLTextureCache::clearCorruptedCache() +{ + llwarns << "the texture cache is corrupted, need to be cleared." << llendl ; + + closeHeaderEntriesFile();//close possible file handler + purgeAllTextures(false) ; //clear the cache. + + if (!mReadOnly) //regenerate the directory tree if not exists. + { + LLFile::mkdir(mTexturesDirName); + + const char* subdirs = "0123456789abcdef"; + for (S32 i=0; i<16; i++) + { + std::string dirname = mTexturesDirName + gDirUtilp->getDirDelimiter() + subdirs[i]; + LLFile::mkdir(dirname); + } + } + + return ; +} + void LLTextureCache::purgeAllTextures(bool purge_directories) { if (!mReadOnly) @@ -1508,11 +1530,14 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) mTexturesSizeTotal = 0; mFreeList.clear(); mTexturesSizeTotal = 0; + mUpdatedEntryMap.clear(); // Info with 0 entries mHeaderEntriesInfo.mVersion = sHeaderCacheVersion; mHeaderEntriesInfo.mEntries = 0; writeEntriesHeader(); + + llinfos << "The entire texture cache is cleared." << llendl ; } void LLTextureCache::purgeTextures(bool validate) @@ -1658,39 +1683,38 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle) // Called from work thread // Reads imagesize from the header, updates timestamp -S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize) +S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, Entry& entry) { - LLMutexLock lock(&mHeaderMutex); - Entry entry; + LLMutexLock lock(&mHeaderMutex); S32 idx = openAndReadEntry(id, entry, false); if (idx >= 0) - { - imagesize = entry.mImageSize; + { updateEntryTimeStamp(idx, entry); // updates time } return idx; } // Writes imagesize to the header, updates timestamp -S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize) +S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, Entry& entry, S32 imagesize, S32 datasize) { mHeaderMutex.lock(); - llassert_always(imagesize >= 0); - Entry entry; S32 idx = openAndReadEntry(id, entry, true); + mHeaderMutex.unlock(); + if (idx >= 0) { - updateEntry(idx, entry, imagesize, entry.mBodySize); - mHeaderMutex.unlock(); + updateEntry(idx, entry, imagesize, datasize); } - else // retry + + if(idx < 0) // retry { - mHeaderMutex.unlock(); readHeaderCache(); // We couldn't write an entry, so refresh the LRU + mHeaderMutex.lock(); llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries); mHeaderMutex.unlock(); - idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion + + idx = setHeaderCacheEntry(id, entry, imagesize, datasize); // assert above ensures no inf. recursion } return idx; } |