diff options
Diffstat (limited to 'indra')
| -rw-r--r-- | indra/newview/app_settings/settings.xml | 11 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 48 | ||||
| -rw-r--r-- | indra/newview/llappviewer.h | 3 | ||||
| -rw-r--r-- | indra/newview/lltexturecache.cpp | 23 | ||||
| -rw-r--r-- | indra/newview/lltexturecache.h | 2 | ||||
| -rw-r--r-- | indra/newview/llviewerregion.cpp | 164 | ||||
| -rw-r--r-- | indra/newview/llviewerregion.h | 10 | ||||
| -rw-r--r-- | indra/newview/llvocache.cpp | 537 | ||||
| -rw-r--r-- | indra/newview/llvocache.h | 86 | ||||
| -rw-r--r-- | indra/newview/llworld.cpp | 3 | 
10 files changed, 668 insertions, 219 deletions
| diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 07418d1b5e..75e7b33b67 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1147,6 +1147,17 @@        <key>Value</key>        <string />      </map>	 +    <key>CacheNumberOfRegionsForObjects</key> +    <map> +      <key>Comment</key> +      <string>Controls number of regions to be cached for objects, ranges from 16 to 128.</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>U32</string> +      <key>Value</key> +      <integer>128</integer> +    </map>      <key>CacheSize</key>      <map>        <key>Comment</key> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index bfe3e52657..fd6b8b739d 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3025,14 +3025,6 @@ void LLAppViewer::migrateCacheDirectory()  #endif // LL_WINDOWS || LL_DARWIN  } -//static -S32 LLAppViewer::getCacheVersion()  -{ -	static const S32 cache_version = 7; - -	return cache_version ; -} -  void dumpVFSCaches()  {  	llinfos << "======= Static VFS ========" << llendl; @@ -3071,23 +3063,40 @@ void dumpVFSCaches()  	SetCurrentDirectory(w_str);  #endif  } + +//static +U32 LLAppViewer::getTextureCacheVersion()  +{ +	//viewer texture cache version, change if the texture cache format changes. +	const U32 TEXTURE_CACHE_VERSION = 7; + +	return TEXTURE_CACHE_VERSION ; +} + +//static +U32 LLAppViewer::getObjectCacheVersion()  +{ +	// Viewer object cache version, change if object update +	// format changes. JC +	const U32 INDRA_OBJECT_CACHE_VERSION = 14; + +	return INDRA_OBJECT_CACHE_VERSION; +} +  bool LLAppViewer::initCache()  {  	mPurgeCache = false; -	BOOL disable_texture_cache = FALSE ;  	BOOL read_only = mSecondInstance ? TRUE : FALSE;  	LLAppViewer::getTextureCache()->setReadOnly(read_only) ; +	LLVOCache::getInstance()->setReadOnly(read_only); -	if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getCacheVersion())  +	BOOL texture_cache_mismatch = FALSE ; +	if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())   	{ -		if(read_only)  +		texture_cache_mismatch = TRUE ; +		if(!read_only)   		{ -			disable_texture_cache = TRUE ; //if the cache version of this viewer is different from the running one, this viewer can not use the texture cache. -		} -		else -		{ -			mPurgeCache = true; // Purge cache if the version number is different. -			gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getCacheVersion()); +			gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());  		}  	} @@ -3138,9 +3147,11 @@ bool LLAppViewer::initCache()  	const S64 MAX_CACHE_SIZE = 1024*MB;  	cache_size = llmin(cache_size, MAX_CACHE_SIZE);  	S64 texture_cache_size = ((cache_size * 8)/10); -	S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, disable_texture_cache); +	S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);  	texture_cache_size -= extra; +	LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ; +  	LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS"));  	// Init the VFS @@ -3303,6 +3314,7 @@ void LLAppViewer::purgeCache()  {  	LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;  	LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); +	LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);  	std::string mask = gDirUtilp->getDirDelimiter() + "*.*";  	gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);  } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 1fcf38d18a..c5cac6827c 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -94,7 +94,8 @@ public:  	static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }  	static LLTextureFetch* getTextureFetch() { return sTextureFetch; } -	static S32 getCacheVersion() ; +	static U32 getTextureCacheVersion() ; +	static U32 getObjectCacheVersion() ;  	const std::string& getSerialNumber() { return mSerialNumber; } diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index 2fd0a22f80..6a213309a0 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -927,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. @@ -942,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); diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h index 7f1bba56fb..64e3a2658c 100644 --- a/indra/newview/lltexturecache.h +++ b/indra/newview/lltexturecache.h @@ -105,7 +105,7 @@ public:  	void purgeCache(ELLPath location);  	void setReadOnly(BOOL read_only) ; -	S64 initCache(ELLPath location, S64 maxsize, BOOL disable_texture_cache); +	S64 initCache(ELLPath location, S64 maxsize, BOOL texture_cache_mismatch);  	handle_t readFromCache(const std::string& local_filename, const LLUUID& id, U32 priority, S32 offset, S32 size,  						   ReadResponder* responder); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index a86efa215b..98f16757b2 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -69,13 +69,6 @@  	#pragma warning(disable:4355)  #endif -// Viewer object cache version, change if object update -// format changes. JC -const U32 INDRA_OBJECT_CACHE_VERSION = 14; - -// Format string used to construct filename for the object cache -static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; -  extern BOOL gNoRender;  const F32 WATER_TEXTURE_SCALE = 8.f;			//  Number of times to repeat the water texture across a region @@ -214,7 +207,7 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	mProductName("unknown"),  	mHttpUrl(""),  	mCacheLoaded(FALSE), -	mCacheEntriesCount(0), +	mCacheDirty(FALSE),  	mCacheID(),  	mEventPoll(NULL),  	mReleaseNotesRequested(FALSE), @@ -264,8 +257,6 @@ LLViewerRegion::LLViewerRegion(const U64 &handle,  	// Create the object lists  	initStats(); -	mCacheStart.append(mCacheEnd); -	  	//create object partitions  	//MUST MATCH declaration of eObjectPartitions  	mObjectPartition.push_back(new LLHUDPartition());		//PARTITION_HUD @@ -324,19 +315,6 @@ LLViewerRegion::~LLViewerRegion()  	std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer());  } - -const std::string LLViewerRegion::getObjectCacheFilename(U64 mHandle) const -{ -	std::string filename; -	U32 region_x, region_y; - -	grid_from_region_handle(mHandle, ®ion_x, ®ion_y); -	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, -			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y)); - -	return filename; -} -  void LLViewerRegion::loadObjectCache()  {  	if (mCacheLoaded) @@ -347,77 +325,10 @@ void LLViewerRegion::loadObjectCache()  	// Presume success.  If it fails, we don't want to try again.  	mCacheLoaded = TRUE; -	LLVOCacheEntry *entry; - -	std::string filename = getObjectCacheFilename(mHandle); -	LL_DEBUGS("ObjectCache") << filename << LL_ENDL; - -	LLFILE* fp = LLFile::fopen(filename, "rb");		/* Flawfinder: ignore */ -	if (!fp) -	{ -		// might not have a file, which is normal -		return; -	} - -	U32 zero; -	size_t nread; -	nread = fread(&zero, sizeof(U32), 1, fp); -	if (nread != 1 || zero) -	{ -		// a non-zero value here means bad things! -		// skip reading the cached values -		llinfos << "Cache file invalid" << llendl; -		fclose(fp); -		return; -	} - -	U32 version; -	nread = fread(&version, sizeof(U32), 1, fp); -	if (nread != 1 || version != INDRA_OBJECT_CACHE_VERSION) +	if(LLVOCache::hasInstance())  	{ -		// a version mismatch here means we've changed the binary format! -		// skip reading the cached values -		llinfos << "Cache version changed, discarding" << llendl; -		fclose(fp); -		return; -	} - -	LLUUID cache_id; -	nread = fread(&cache_id.mData, 1, UUID_BYTES, fp); -	if (nread != (size_t)UUID_BYTES || mCacheID != cache_id) -	{ -		llinfos << "Cache ID doesn't match for this region, discarding" -			<< llendl; -		fclose(fp); -		return; -	} - -	S32 num_entries; -	nread = fread(&num_entries, sizeof(S32), 1, fp); -	if (nread != 1) -	{ -		llinfos << "Short read, discarding" << llendl; -		fclose(fp); -		return; +		LLVOCache::getInstance()->readFromCache(mHandle, mCacheID, mCacheMap) ;  	} -	 -	S32 i; -	for (i = 0; i < num_entries; i++) -	{ -		entry = new LLVOCacheEntry(fp); -		if (!entry->getLocalID()) -		{ -			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; -			delete entry; -			entry = NULL; -			break; -		} -		mCacheEnd.insert(*entry); -		mCacheMap[entry->getLocalID()] = entry; -		mCacheEntriesCount++; -	} - -	fclose(fp);  } @@ -428,61 +339,22 @@ void LLViewerRegion::saveObjectCache()  		return;  	} -	S32 num_entries = mCacheEntriesCount; -	if (0 == num_entries) +	if (mCacheMap.empty())  	{  		return;  	} -	std::string filename = getObjectCacheFilename(mHandle); -	LL_DEBUGS("ObjectCache") << filename << LL_ENDL; - -	LLFILE* fp = LLFile::fopen(filename, "wb");		/* Flawfinder: ignore */ -	if (!fp) +	if(LLVOCache::hasInstance())  	{ -		llwarns << "Unable to write cache file " << filename << llendl; -		return; +		LLVOCache::getInstance()->writeToCache(mHandle, mCacheID, mCacheMap, mCacheDirty) ; +		mCacheDirty = FALSE;  	} -	// write out zero to indicate a version cache file -	U32 zero = 0; -	if (fwrite(&zero, sizeof(U32), 1, fp) != 1) +	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)  	{ -		llwarns << "Short write" << llendl; +		delete iter->second;  	} - -	// write out version number -	U32 version = INDRA_OBJECT_CACHE_VERSION; -	if (fwrite(&version, sizeof(U32), 1, fp) != 1) -	{ -		llwarns << "Short write" << llendl; -	} - -	// write the cache id for this sim -	if (fwrite(&mCacheID.mData, 1, UUID_BYTES, fp) != (size_t)UUID_BYTES) -	{ -		llwarns << "Short write" << llendl; -	} - -	if (fwrite(&num_entries, sizeof(S32), 1, fp) != 1) -	{ -		llwarns << "Short write" << llendl; -	} - -	LLVOCacheEntry *entry; - -	for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext()) -	{ -		entry->writeToFile(fp); -	} -  	mCacheMap.clear(); -	mCacheEnd.unlink(); -	mCacheEnd.init(); -	mCacheStart.deleteAll(); -	mCacheStart.init(); - -	fclose(fp);  }  void LLViewerRegion::sendMessage() @@ -1175,7 +1047,6 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary  			mCacheMap.erase(local_id);  			delete entry;  			entry = new LLVOCacheEntry(local_id, crc, dp); -			mCacheEnd.insert(*entry);  			mCacheMap[local_id] = entry;  		}  	} @@ -1184,18 +1055,13 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary  		// we haven't seen this object before  		// Create new entry and add to map -		if (mCacheEntriesCount > MAX_OBJECT_CACHE_ENTRIES) +		if (mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES)  		{ -			entry = mCacheStart.getNext(); -			mCacheMap.erase(entry->getLocalID()); -			delete entry; -			mCacheEntriesCount--; +			mCacheMap.erase(mCacheMap.begin());  		}  		entry = new LLVOCacheEntry(local_id, crc, dp); -		mCacheEnd.insert(*entry);  		mCacheMap[local_id] = entry; -		mCacheEntriesCount++;  	}  	return ;  } @@ -1310,6 +1176,7 @@ void LLViewerRegion::requestCacheMisses()  	mCacheMissFull.reset();  	mCacheMissCRC.reset(); +	mCacheDirty = TRUE ;  	// llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl;  } @@ -1327,9 +1194,10 @@ void LLViewerRegion::dumpCache()  	}  	LLVOCacheEntry *entry; - -	for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext()) +	for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mCacheMap.begin(); iter != mCacheMap.end(); ++iter)  	{ +		entry = iter->second ; +  		S32 hits = entry->getHitCount();  		S32 changes = entry->getCRCChangeCount(); @@ -1340,7 +1208,7 @@ void LLViewerRegion::dumpCache()  		change_bin[changes]++;  	} -	llinfos << "Count " << mCacheEntriesCount << llendl; +	llinfos << "Count " << mCacheMap.size() << llendl;  	for (i = 0; i < BINS; i++)  	{  		llinfos << "Hits " << i << " " << hit_bin[i] << llendl; diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 361ae87e1b..038c831e59 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -323,9 +323,6 @@ public:  	LLDynamicArray<LLUUID> mMapAvatarIDs;  private: -	// determine the cache filename for the region from the region handle -	const std::string getObjectCacheFilename(U64 mHandle) const; -  	// The surfaces and other layers  	LLSurface*	mLandp; @@ -387,11 +384,8 @@ private:  	// Regions can have order 10,000 objects, so assume  	// a structure of size 2^14 = 16,000  	BOOL									mCacheLoaded; -	typedef std::map<U32, LLVOCacheEntry *>	cache_map_t; -	cache_map_t			  				 	mCacheMap; -	LLVOCacheEntry							mCacheStart; -	LLVOCacheEntry							mCacheEnd; -	U32										mCacheEntriesCount; +	BOOL                                    mCacheDirty; +	LLVOCacheEntry::vocache_entry_map_t		mCacheMap;  	LLDynamicArray<U32>						mCacheMissFull;  	LLDynamicArray<U32>						mCacheMissCRC;  	// time? diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 4e6d630ed8..ee32bd562e 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -25,10 +25,19 @@   */  #include "llviewerprecompiledheaders.h" -  #include "llvocache.h" -  #include "llerror.h" +#include "llregionhandle.h" + +BOOL check_read(LLAPRFile* apr_file, void* src, S32 n_bytes)  +{ +	return apr_file->read(src, n_bytes) == n_bytes ; +} + +BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes)  +{ +	return apr_file->write(src, n_bytes) == n_bytes ; +}  //---------------------------------------------------------------------------  // LLVOCacheEntry @@ -57,26 +66,31 @@ LLVOCacheEntry::LLVOCacheEntry()  	mDP.assignBuffer(mBuffer, 0);  } +LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) +{ +	S32 size = -1; +	BOOL success; -static inline void checkedRead(LLFILE *fp, void *data, size_t nbytes) +	success = check_read(apr_file, &mLocalID, sizeof(U32)); +	if(success)  { -	if (fread(data, 1, nbytes, fp) != nbytes) +		success = check_read(apr_file, &mCRC, sizeof(U32)); +	} +	if(success)  	{ -		llwarns << "Short read" << llendl; -		memset(data, 0, nbytes); +		success = check_read(apr_file, &mHitCount, sizeof(S32));  	} +	if(success) +	{ +		success = check_read(apr_file, &mDupeCount, sizeof(S32));  } - -LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp) +	if(success)  { -	S32 size; -	checkedRead(fp, &mLocalID, sizeof(U32)); -	checkedRead(fp, &mCRC, sizeof(U32)); -	checkedRead(fp, &mHitCount, sizeof(S32)); -	checkedRead(fp, &mDupeCount, sizeof(S32)); -	checkedRead(fp, &mCRCChangeCount, sizeof(S32)); - -	checkedRead(fp, &size, sizeof(S32)); +		success = check_read(apr_file, &mCRCChangeCount, sizeof(S32)); +	} +	if(success) +	{ +		success = check_read(apr_file, &size, sizeof(S32));  	// Corruption in the cache entries  	if ((size > 10000) || (size < 1)) @@ -90,11 +104,30 @@ LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp)  		mBuffer = NULL;  		return;  	} +	} +	if(success && size > 0) +	{ +		mBuffer = new U8[size]; +		success = check_read(apr_file, mBuffer, size); -	mBuffer = new U8[size]; -	checkedRead(fp, mBuffer, size); +		if(success) +		{  	mDP.assignBuffer(mBuffer, size);  } +		else +		{ +			delete[] mBuffer ; +			mBuffer = NULL ; +		} +	} + +	if(!success) +	{ +		mLocalID = 0; +		mCRC = 0; +		mBuffer = NULL; +	} +}  LLVOCacheEntry::~LLVOCacheEntry()  { @@ -148,22 +181,466 @@ void LLVOCacheEntry::dump() const  		<< llendl;  } -static inline void checkedWrite(LLFILE *fp, const void *data, size_t nbytes) +BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const +{ +	BOOL success; +	success = check_write(apr_file, (void*)&mLocalID, sizeof(U32)); +	if(success) +	{ +		success = check_write(apr_file, (void*)&mCRC, sizeof(U32)); +	} +	if(success) +	{ +		success = check_write(apr_file, (void*)&mHitCount, sizeof(S32)); +	} +	if(success) +	{ +		success = check_write(apr_file, (void*)&mDupeCount, sizeof(S32)); +	} +	if(success) +	{ +		success = check_write(apr_file, (void*)&mCRCChangeCount, sizeof(S32)); +	} +	if(success) +	{ +		S32 size = mDP.getBufferSize(); +		success = check_write(apr_file, (void*)&size, sizeof(S32)); +	 +		if(success) +		{ +			success = check_write(apr_file, (void*)mBuffer, size); +	} +} + +	return success ; +} + +//------------------------------------------------------------------- +//LLVOCache +//------------------------------------------------------------------- +// Format string used to construct filename for the object cache +static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc"; + +const U32 MAX_NUM_OBJECT_ENTRIES = 128 ; +const U32 NUM_ENTRIES_TO_PURGE = 16 ; +const char* object_cache_dirname = "objectcache"; +const char* header_filename = "object.cache"; + +LLVOCache* LLVOCache::sInstance = NULL; + +//static  +LLVOCache* LLVOCache::getInstance()  +{ +	if(!sInstance) +	{ +		sInstance = new LLVOCache() ; +} +	return sInstance ; +} + +//static  +BOOL LLVOCache::hasInstance()  +{ +	return sInstance != NULL ; +} + +//static  +void LLVOCache::destroyClass()  +{ +	if(sInstance) +	{ +		delete sInstance ; +		sInstance = NULL ; +	} +} + +LLVOCache::LLVOCache(): +	mInitialized(FALSE), +	mReadOnly(TRUE), +	mNumEntries(0) +{ +	mLocalAPRFilePoolp = new LLVolatileAPRPool() ; +} + +LLVOCache::~LLVOCache() +{ +	writeCacheHeader(); +	clearCacheInMemory(); +	delete mLocalAPRFilePoolp; +} + +void LLVOCache::setDirNames(ELLPath location) +{ +	std::string delem = gDirUtilp->getDirDelimiter(); + +	mHeaderFileName = gDirUtilp->getExpandedFilename(location, object_cache_dirname, header_filename); +	mObjectCacheDirName = gDirUtilp->getExpandedFilename(location, object_cache_dirname); +} + +void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version) +{ +	if(mInitialized) +	{ +		return ; +	} + +	setDirNames(location); +	if (!mReadOnly) +	{ +		LLFile::mkdir(mObjectCacheDirName); +	}	 +	mCacheSize = llmin(size, MAX_NUM_OBJECT_ENTRIES) ; +	mCacheSize = llmax(mCacheSize, NUM_ENTRIES_TO_PURGE); + +	mMetaInfo.mVersion = cache_version; +	readCacheHeader(); +	mInitialized = TRUE ; + +	if(mMetaInfo.mVersion != cache_version)  +	{ +		mMetaInfo.mVersion = cache_version ; +		if(mReadOnly) //disable cache +		{ +			clearCacheInMemory(); +		} +		else //delete the current cache if the format does not match. +		{			 +			removeCache(); +		} +	}	 +} +	 +void LLVOCache::removeCache(ELLPath location)  +{ +	if(mReadOnly) +	{ +		return ; +	} + +	std::string delem = gDirUtilp->getDirDelimiter(); +	std::string mask = delem + "*"; +	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); +	gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files +	LLFile::rmdir(cache_dir); + +	clearCacheInMemory(); +	mInitialized = FALSE ; +} + +void LLVOCache::removeCache()  +{ +	llassert_always(mInitialized) ; +	if(mReadOnly) +	{ +		return ; +	} + +	std::string delem = gDirUtilp->getDirDelimiter(); +	std::string mask = delem + "*"; +	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask);  + +	clearCacheInMemory() ; +	writeCacheHeader(); +} + +void LLVOCache::clearCacheInMemory() +{ +	if(!mHeaderEntryQueue.empty())  +	{ +		for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin(); iter != mHeaderEntryQueue.end(); ++iter) +		{ +			delete *iter ; +		} +		mHeaderEntryQueue.clear(); +		mHandleEntryMap.clear(); +		mNumEntries = 0 ; +	} +} + +void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)   { -	if (fwrite(data, 1, nbytes, fp) != nbytes) +	U32 region_x, region_y; + +	grid_from_region_handle(handle, ®ion_x, ®ion_y); +	filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, object_cache_dirname, +			   llformat(OBJECT_CACHE_FILENAME, region_x, region_y)); + +	return ; +} + +void LLVOCache::removeFromCache(U64 handle) +{ +	if(mReadOnly) +	{ +		return ; +	} + +	std::string filename; +	getObjectCacheFilename(handle, filename); +	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	 +} + +BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes)  +{ +	if(!check_read(apr_file, src, n_bytes)) +	{ +		delete apr_file ; +		removeCache() ; +		return FALSE ; +	} + +	return TRUE ; +} + +BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes)  +{ +	if(!check_write(apr_file, src, n_bytes))  	{ -		llwarns << "Short write" << llendl; +		delete apr_file ; +		removeCache() ; +		return FALSE ;  	} + +	return TRUE ; +} + +void LLVOCache::readCacheHeader() +{ +	//clear stale info. +	clearCacheInMemory();	 + +	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp)) +	{ +		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		 +		 +		//read the meta element +		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) +		{ +			return ; +		} + +		HeaderEntryInfo* entry ; +		mNumEntries = 0 ; +		while(mNumEntries < MAX_NUM_OBJECT_ENTRIES) +		{ +			entry = new HeaderEntryInfo() ; +			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo))) +			{ +				delete entry ;			 +				return ; +			} +			else if(!entry->mTime) //end of the cache. +			{ +				delete entry ; +				return ; +			} + +			entry->mIndex = mNumEntries++ ; +			mHeaderEntryQueue.insert(entry) ; +			mHandleEntryMap[entry->mHandle] = entry ; +		} + +		delete apr_file ; +	} +	else +	{ +		writeCacheHeader() ; +	} +} + +void LLVOCache::writeCacheHeader() +{ +	if(mReadOnly) +	{ +		return ; +	}	 + +	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); + +	//write the meta element +	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo))) +	{ +		return ; +	} + +	mNumEntries = 0 ; +	for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter) +	{ +		(*iter)->mIndex = mNumEntries++ ; +		if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo))) +		{ +			return ; +		} +	} + +	mNumEntries = mHeaderEntryQueue.size() ; +	if(mNumEntries < MAX_NUM_OBJECT_ENTRIES) +	{ +		HeaderEntryInfo* entry = new HeaderEntryInfo() ; +		for(S32 i = mNumEntries ; i < MAX_NUM_OBJECT_ENTRIES ; i++) +		{ +			//fill the cache with the default entry. +			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo))) +			{ +				mReadOnly = TRUE ; //disable the cache. +				return ; +			} +		} +		delete entry ; +	} +	delete apr_file ; +} + +BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) +{ +	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); +	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; + +	return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;  } -void LLVOCacheEntry::writeToFile(LLFILE *fp) const +void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map)   { -	checkedWrite(fp, &mLocalID, sizeof(U32)); -	checkedWrite(fp, &mCRC, sizeof(U32)); -	checkedWrite(fp, &mHitCount, sizeof(S32)); -	checkedWrite(fp, &mDupeCount, sizeof(S32)); -	checkedWrite(fp, &mCRCChangeCount, sizeof(S32)); -	S32 size = mDP.getBufferSize(); -	checkedWrite(fp, &size, sizeof(S32)); -	checkedWrite(fp, mBuffer, size); +	llassert_always(mInitialized); + +	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; +	if(iter == mHandleEntryMap.end()) //no cache +	{ +		return ; +	} + +	std::string filename; +	getObjectCacheFilename(handle, filename); +	LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp); + +	LLUUID cache_id ; +	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES)) +	{ +		return ; +	} +	if(cache_id != id) +	{ +		llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; + +		delete apr_file ; +		return ; +	} + +	S32 num_entries; +	if(!checkRead(apr_file, &num_entries, sizeof(S32))) +	{ +		return ; +	} +	 +	for (S32 i = 0; i < num_entries; i++) +	{ +		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file); +		if (!entry->getLocalID()) +		{ +			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl; +			delete entry ; +			break; +		} +		cache_entry_map[entry->getLocalID()] = entry; +	} +	num_entries = cache_entry_map.size() ; + +	delete apr_file ; +	return ; +} +	 +void LLVOCache::purgeEntries() +{ +	U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ; +	while(mHeaderEntryQueue.size() > limit) +	{ +		header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; +		HeaderEntryInfo* entry = *iter ; +		 +		removeFromCache(entry->mHandle) ; +		mHandleEntryMap.erase(entry->mHandle) ;		 +		mHeaderEntryQueue.erase(iter) ; +		delete entry ; +	} + +	writeCacheHeader() ; +	readCacheHeader() ; +	mNumEntries = mHandleEntryMap.size() ;  } + +void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache)  +{ +	llassert_always(mInitialized); + +	if(mReadOnly) +	{ +		return ; +	} + +	HeaderEntryInfo* entry; +	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; +	if(iter == mHandleEntryMap.end()) //new entry +	{		 +		if(mNumEntries >= mCacheSize) +		{ +			purgeEntries() ; +		} +		 +		entry = new HeaderEntryInfo(); +		entry->mHandle = handle ; +		entry->mTime = time(NULL) ; +		entry->mIndex = mNumEntries++ ; +		mHeaderEntryQueue.insert(entry) ; +		mHandleEntryMap[handle] = entry ; +	} +	else +	{ +		entry = iter->second ; +		entry->mTime = time(NULL) ; + +		//resort +		mHeaderEntryQueue.erase(entry) ; +		mHeaderEntryQueue.insert(entry) ; +	} + +	//update cache header +	if(!updateEntry(entry)) +	{ +		return ; //update failed. +	} + +	if(!dirty_cache) +	{ +		return ; //nothing changed, no need to update. +	} + +	//write to cache file +	std::string filename; +	getObjectCacheFilename(handle, filename); +	LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp); +	 +	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES)) +	{ +		return ; +	} + +	S32 num_entries = cache_entry_map.size() ; +	if(!checkWrite(apr_file, &num_entries, sizeof(S32))) +	{ +		return ; +	} + +	for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter) +	{ +		if(!iter->second->writeToFile(apr_file)) +		{ +			//failed +			delete apr_file ; +			removeCache() ; +			return ; +		} +	} + +	delete apr_file ; +	return ; +}
\ No newline at end of file diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 7a4572b399..56b48ef705 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -36,11 +36,11 @@  // Cache entries  class LLVOCacheEntry; -class LLVOCacheEntry : public LLDLinked<LLVOCacheEntry> +class LLVOCacheEntry  {  public:  	LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp); -	LLVOCacheEntry(LLFILE *fp); +	LLVOCacheEntry(LLAPRFile* apr_file);  	LLVOCacheEntry();  	~LLVOCacheEntry(); @@ -50,12 +50,15 @@ public:  	S32 getCRCChangeCount() const	{ return mCRCChangeCount; }  	void dump() const; -	void writeToFile(LLFILE *fp) const; +	BOOL writeToFile(LLAPRFile* apr_file) const;  	void assignCRC(U32 crc, LLDataPackerBinaryBuffer &dp);  	LLDataPackerBinaryBuffer *getDP(U32 crc);  	void recordHit();  	void recordDupe() { mDupeCount++; } +public: +	typedef std::map<U32, LLVOCacheEntry*>	vocache_entry_map_t; +  protected:  	U32							mLocalID;  	U32							mCRC; @@ -66,4 +69,81 @@ protected:  	U8							*mBuffer;  }; +// +//Note: LLVOCache is not thread-safe +// +class LLVOCache +{ +private: +	struct HeaderEntryInfo +	{ +		HeaderEntryInfo() : mIndex(0), mHandle(0), mTime(0) {} +		S32 mIndex; +		U64 mHandle ; +		U32 mTime ; +	}; + +	struct HeaderMetaInfo +	{ +		HeaderMetaInfo() : mVersion(0){} + +		U32 mVersion; +	}; + +	struct header_entry_less +	{ +		bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const +		{ +			return lhs->mTime < rhs->mTime; // older entry in front of queue (set) +		} +	}; +	typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t; +	typedef std::map<U64, HeaderEntryInfo*> handle_entry_map_t; +private: +	LLVOCache() ; + +public: +	~LLVOCache() ; + +	void initCache(ELLPath location, U32 size, U32 cache_version) ; +	void removeCache(ELLPath location) ; + +	void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ; +	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ; + +	void setReadOnly(BOOL read_only) {mReadOnly = read_only;}  + +private: +	void setDirNames(ELLPath location);	 +	// determine the cache filename for the region from the region handle	 +	void getObjectCacheFilename(U64 handle, std::string& filename); +	void removeFromCache(U64 handle); +	void readCacheHeader(); +	void writeCacheHeader(); +	void clearCacheInMemory(); +	void removeCache() ; +	void purgeEntries(); +	BOOL updateEntry(const HeaderEntryInfo* entry); +	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ; +	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ; +	 +private: +	BOOL                 mInitialized ; +	BOOL                 mReadOnly ; +	HeaderMetaInfo       mMetaInfo; +	U32                  mCacheSize; +	U32                  mNumEntries; +	std::string          mHeaderFileName ; +	std::string          mObjectCacheDirName; +	LLVolatileAPRPool*   mLocalAPRFilePoolp ; 	 +	header_entry_queue_t mHeaderEntryQueue; +	handle_entry_map_t   mHandleEntryMap;	 + +	static LLVOCache* sInstance ; +public: +	static LLVOCache* getInstance() ; +	static BOOL       hasInstance() ; +	static void       destroyClass() ; +}; +  #endif diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 2ad43ff394..5760d04a08 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -121,6 +121,7 @@ void LLWorld::destroyClass()  		LLViewerRegion* region_to_delete = *region_it++;  		removeRegion(region_to_delete->getHost());  	} +	LLVOCache::getInstance()->destroyClass() ;  	LLViewerPartSim::getInstance()->destroyClass();  } @@ -256,6 +257,8 @@ void LLWorld::removeRegion(const LLHost &host)  		llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl;  		LLAppViewer::instance()->forceDisconnect(LLTrans::getString("YouHaveBeenDisconnected")); + +		regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed.  		return;  	} | 
