From 459f00ccb80ff9277b1bdf712399d3b428444b61 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Wed, 13 Jul 2011 04:35:38 -0500 Subject: [PATCH] LLVOCache class implemented. --- indra/llcommon/stringize.h | 107 +++++ indra/newview/llappviewer.cpp | 28 +- indra/newview/llappviewer.h | 4 +- indra/newview/llviewerobjectlist.cpp | 83 +++- indra/newview/llviewerobjectlist.h | 4 +- indra/newview/llviewerregion.cpp | 535 +++++++++++---------- indra/newview/llviewerregion.h | 134 +++--- indra/newview/llvocache.cpp | 684 ++++++++++++++++++++++++--- indra/newview/llvocache.h | 92 +++- indra/newview/llvovolume.cpp | 12 +- indra/newview/llworld.cpp | 32 +- 11 files changed, 1316 insertions(+), 399 deletions(-) create mode 100644 indra/llcommon/stringize.h diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h new file mode 100644 index 000000000..72f2e58ce --- /dev/null +++ b/indra/llcommon/stringize.h @@ -0,0 +1,107 @@ +/** + * @file stringize.h + * @author Nat Goodspeed + * @date 2008-12-17 + * @brief stringize(item) template function and STRINGIZE(expression) macro + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * 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. + * + * 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. + * + * 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$ + */ + +#if ! defined(LL_STRINGIZE_H) +#define LL_STRINGIZE_H + +#include +#include + +/** + * stringize(item) encapsulates an idiom we use constantly, using + * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str() + * to render a string expressing some item. + */ +template +std::string stringize(const T& item) +{ + std::ostringstream out; + out << item; + return out.str(); +} + +/** + * stringize_f(functor) + */ +template +std::string stringize_f(Functor const & f) +{ + std::ostringstream out; + f(out); + return out.str(); +} + +/** + * STRINGIZE(item1 << item2 << item3 ...) effectively expands to the + * following: + * @code + * std::ostringstream out; + * out << item1 << item2 << item3 ... ; + * return out.str(); + * @endcode + */ +#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION)) + + +/** + * destringize(str) + * defined for symmetry with stringize + * *NOTE - this has distinct behavior from boost::lexical_cast regarding + * leading/trailing whitespace and handling of bad_lexical_cast exceptions + */ +template +T destringize(std::string const & str) +{ + T val; + std::istringstream in(str); + in >> val; + return val; +} + +/** + * destringize_f(str, functor) + */ +template +void destringize_f(std::string const & str, Functor const & f) +{ + std::istringstream in(str); + f(in); +} + +/** + * DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the + * following: + * @code + * std::istringstream in(str); + * in >> item1 >> item2 >> item3 ... ; + * @endcode + */ +#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION))) + + +#endif /* ! defined(LL_STRINGIZE_H) */ diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index fe0c476d1..cc06d65be 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -80,6 +80,7 @@ #include "llrender.h" #include "llfont.h" #include "llimagej2c.h" +#include "llvocache.h" #include "llweb.h" #include "llsecondlifeurls.h" @@ -1552,6 +1553,8 @@ bool LLAppViewer::cleanup() } #endif + llinfos << "Misc Cleanup" << llendflush; + // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up. // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve delete gStaticVFS; @@ -1566,6 +1569,7 @@ bool LLAppViewer::cleanup() LLWatchdog::getInstance()->cleanup(); + llinfos << "Shutting down message system" << llendflush; end_messaging_system(); llinfos << "Message system deleted." << llendflush; @@ -3041,11 +3045,23 @@ U32 LLAppViewer::getTextureCacheVersion() 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 read_only = mSecondInstance ? TRUE : FALSE; - LLAppViewer::getTextureCache()->setReadOnly(read_only); + LLAppViewer::getTextureCache()->setReadOnly(read_only) ; + LLVOCache::getInstance()->setReadOnly(read_only); bool texture_cache_mismatch = false; if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion()) @@ -3125,6 +3141,8 @@ bool LLAppViewer::initCache() 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("Initializing VFS..."); // Init the VFS @@ -3281,8 +3299,9 @@ bool LLAppViewer::initCache() void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; + 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->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask); } @@ -4245,7 +4264,10 @@ void LLAppViewer::disconnectViewer() // This is where we used to call gObjectList.destroy() and then delete gWorldp. // Now we just ask the LLWorld singleton to cleanly shut down. - LLWorld::getInstance()->destroyClass(); + if(LLWorld::instanceExists()) + { + LLWorld::getInstance()->destroyClass(); + } // call all self-registered classes LLDestroyClassList::instance().fireCallbacks(); diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index d7f99c1bd..a1dde2646 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -96,7 +96,9 @@ public: static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; } static LLTextureFetch* getTextureFetch() { return sTextureFetch; } - static U32 getTextureCacheVersion(); + static U32 getTextureCacheVersion() ; + static U32 getObjectCacheVersion() ; + const std::string& getSerialNumber() { return mSerialNumber; } bool getPurgeCache() const { return mPurgeCache; } diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 36f451f04..31e10ef22 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -167,13 +167,13 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, return (((U64)index) << 32) | (U64)local_id; } -BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) +BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) { - if(object.getRegion()) + if(objectp && objectp->getRegion()) { - U32 local_id = object.mLocalID; - U32 ip = object.getRegion()->getHost().getAddress(); - U32 port = object.getRegion()->getHost().getPort(); + U32 local_id = objectp->mLocalID; + U32 ip = objectp->getRegion()->getHost().getAddress(); + U32 port = objectp->getRegion()->getHost().getPort(); U64 ipport = (((U64)ip) << 32) | (U64)port; U32 index = sIPAndPortToIndex[ipport]; @@ -188,7 +188,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object) } // Found existing entry - if (iter->second == object.getID()) + if (iter->second == objectp->getID()) { // Full UUIDs match, so remove the entry sIndexAndLocalIDToUUID.erase(iter); return TRUE; @@ -364,9 +364,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); // Lookup data packer and add this id to cache miss lists if necessary. - cached_dpp = regionp->getDP(id, crc); + U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; + cached_dpp = regionp->getDP(id, crc, cache_miss_type); if (cached_dpp) { + // Cache Hit. cached_dpp->reset(); cached_dpp->unpackUUID(fullid, "ID"); cached_dpp->unpackU32(local_id, "LocalID"); @@ -374,6 +376,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } else { + // Cache Miss. + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type); + #endif + continue; // no data packer, skip this object } } @@ -465,7 +472,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, // << ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion() // << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); setUUIDAndLocal(fullid, local_id, gMessageSystem->getSenderIP(), @@ -530,6 +537,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, llwarns << "Dead object " << objectp->mID << " in UUID map 1!" << llendl; } + bool bCached = false; if (compressed) { if (update_type != OUT_TERSE_IMPROVED) @@ -539,6 +547,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); if (update_type != OUT_TERSE_IMPROVED) { + bCached = true; objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); } } @@ -557,7 +566,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } objectp->setLastUpdateType(update_type); - objectp->setLastUpdateCached(cached); + objectp->setLastUpdateCached(bCached); } LLVOAvatar::cullAvatarsByPixelArea(); @@ -858,7 +867,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) // << objectp->getRegion()->getHost().getPort() << llendl; //} - removeFromLocalIDTable(*objectp); + removeFromLocalIDTable(objectp); if (objectp->onActiveList()) { @@ -1108,6 +1117,60 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) LLWorld::getInstance()->shiftRegions(offset); } +//debug code +bool LLViewerObjectList::hasMapObjectInRegion(LLViewerRegion* regionp) +{ + for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + + if(objectp->isDead() || objectp->getRegion() == regionp) + { + return true ; + } + } + + return false ; +} + +//make sure the region is cleaned up. +void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp) +{ + std::set dead_object_list ; + std::set region_object_list ; + for (vobj_list_t::iterator iter = mMapObjects.begin(); iter != mMapObjects.end(); ++iter) + { + LLViewerObject* objectp = *iter; + + if(objectp->isDead()) + { + dead_object_list.insert(objectp) ; + } + else if(objectp->getRegion() == regionp) + { + region_object_list.insert(objectp) ; + } + } + + if(dead_object_list.size() > 0) + { + llwarns << "There are " << dead_object_list.size() << " dead objects on the map!" << llendl ; + + for(std::set::iterator iter = dead_object_list.begin(); iter != dead_object_list.end(); ++iter) + { + cleanupReferences(*iter) ; + } + } + if(region_object_list.size() > 0) + { + llwarns << "There are " << region_object_list.size() << " objects not removed from the deleted region!" << llendl ; + + for(std::set::iterator iter = region_object_list.begin(); iter != region_object_list.end(); ++iter) + { + (*iter)->markDead() ; + } + } +} void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) { LLColor4 above_water_color = gColors.getColor( "NetMapOtherOwnAboveWater" ); diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index f2255d22e..ff655f832 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -96,6 +96,8 @@ public: void shiftObjects(const LLVector3 &offset); + bool hasMapObjectInRegion(LLViewerRegion* regionp) ; + void clearAllMapObjectsInRegion(LLViewerRegion* regionp) ; void renderObjectsForMap(LLNetMap &netmap); void renderObjectBounds(const LLVector3 ¢er); @@ -182,7 +184,7 @@ public: const U32 ip, const U32 port); // Requires knowledge of message system info! - static BOOL removeFromLocalIDTable(const LLViewerObject &object); + static BOOL removeFromLocalIDTable(const LLViewerObject* objectp); // Used ONLY by the orphaned object code. static U64 getIndex(const U32 local_id, const U32 ip, const U32 port); diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index fd1e82d1d..a6cbec632 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -58,6 +58,7 @@ #include "llsdutil.h" #include "llstartup.h" #include "lltrans.h" +#include "llurldispatcher.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" #include "llvlmanager.h" @@ -66,16 +67,82 @@ #include "llvoclouds.h" #include "llworld.h" #include "llspatialpartition.h" - -// Viewer object cache version, change if object update -// format changes. JC -const U32 INDRA_OBJECT_CACHE_VERSION = 14; +#include "stringize.h" +#include "llviewercontrol.h" extern BOOL gNoRender; +#ifdef LL_WINDOWS + #pragma warning(disable:4355) +#endif + const F32 WATER_TEXTURE_SCALE = 8.f; // Number of times to repeat the water texture across a region const S16 MAX_MAP_DIST = 10; +typedef std::map CapabilityMap; + +class LLViewerRegionImpl { +public: + LLViewerRegionImpl(LLViewerRegion * region, LLHost const & host) + : mHost(host), + mCompositionp(NULL), + mEventPoll(NULL)//, + // I'd prefer to set the LLCapabilityListener name to match the region + // name -- it's disappointing that's not available at construction time. + // We could instead store an LLCapabilityListener*, making + // setRegionNameAndZone() replace the instance. Would that pose + // consistency problems? Can we even request a capability before calling + // setRegionNameAndZone()? + // For testability -- the new Michael Feathers paradigm -- + // LLCapabilityListener binds all the globals it expects to need at + // construction time. + //mCapabilityListener(host.getString(), gMessageSystem, *region, + //gAgent.getID(), gAgent.getSessionID()) + { + } + + // The surfaces and other layers + LLSurface* mLandp; + + // Region geometry data + LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) + LLVector3d mCenterGlobal; // Location of center in world space (meters) + LLHost mHost; + + // The unique ID for this region. + LLUUID mRegionID; + + // region/estate owner - usually null. + LLUUID mOwnerID; + + // Network statistics for the region's circuit... + LLTimer mLastNetUpdate; + + // Misc + LLVLComposition *mCompositionp; // Composition layer for the surface + + LLVOCacheEntry::vocache_entry_map_t mCacheMap; + // time? + // LRU info? + + // Cache ID is unique per-region, across renames, moving locations, + // etc. + LLUUID mCacheID; + + CapabilityMap mCapabilities; + + LLEventPoll* mEventPoll; + + /// Post an event to this LLCapabilityListener to invoke a capability message on + /// this LLViewerRegion's server + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + //LLCapabilityListener mCapabilityListener; + + //spatial partitions for objects in this region + std::vector mObjectPartition; + + LLHTTPClient::ResponderPtr mHttpResponderPtr ; +}; class BaseCapabilitiesComplete : public LLHTTPClient::Responder { @@ -153,15 +220,12 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, const U32 grids_per_region_edge, const U32 grids_per_patch_edge, const F32 region_width_meters) -: mCenterGlobal(), +: mImpl(new LLViewerRegionImpl(this, host)), mHandle(handle), - mHost( host ), mTimeDilation(1.0f), mName(""), mZoning(""), - mOwnerID(), mIsEstateManager(FALSE), - mCompositionp(NULL), mRegionFlags( REGION_FLAGS_DEFAULT ), mSimAccess( SIM_ACCESS_MIN ), mBillableFactor(1.0), @@ -171,28 +235,32 @@ LLViewerRegion::LLViewerRegion(const U64 &handle, mColoName("unknown"), mProductSKU("unknown"), mProductName("unknown"), + mHttpUrl(""), mCacheLoaded(FALSE), - mCacheEntriesCount(0), - mCacheID(), - mEventPoll(NULL), - mReleaseNotesRequested(FALSE) + mCacheDirty(FALSE), + mReleaseNotesRequested(FALSE), + mCapabilitiesReceived(false) { mWidth = region_width_meters; - mOriginGlobal = from_region_handle(handle); + mImpl->mOriginGlobal = from_region_handle(handle); updateRenderMatrix(); - mLandp = new LLSurface('l', NULL); + mImpl->mLandp = new LLSurface('l', NULL); + if (!gNoRender) { // Create the composition layer for the surface - mCompositionp = new LLVLComposition(mLandp, grids_per_region_edge, region_width_meters/grids_per_region_edge); - mCompositionp->setSurface(mLandp); + mImpl->mCompositionp = + new LLVLComposition(mImpl->mLandp, + grids_per_region_edge, + region_width_meters / grids_per_region_edge); + mImpl->mCompositionp->setSurface(mImpl->mLandp); // Create the surfaces - mLandp->setRegion(this); - mLandp->create(grids_per_region_edge, + mImpl->mLandp->setRegion(this); + mImpl->mLandp->create(grids_per_region_edge, grids_per_patch_edge, - mOriginGlobal, + mImpl->mOriginGlobal, mWidth); } @@ -211,29 +279,26 @@ 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 - mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN - mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER - mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER - mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE - mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE - mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD - mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS - mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME - mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE - mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE - mObjectPartition.push_back(NULL); //PARTITION_NONE - + mImpl->mObjectPartition.push_back(new LLHUDPartition()); //PARTITION_HUD + mImpl->mObjectPartition.push_back(new LLTerrainPartition()); //PARTITION_TERRAIN + mImpl->mObjectPartition.push_back(new LLVoidWaterPartition()); //PARTITION_VOIDWATER + mImpl->mObjectPartition.push_back(new LLWaterPartition()); //PARTITION_WATER + mImpl->mObjectPartition.push_back(new LLTreePartition()); //PARTITION_TREE + mImpl->mObjectPartition.push_back(new LLParticlePartition()); //PARTITION_PARTICLE + mImpl->mObjectPartition.push_back(new LLCloudPartition()); //PARTITION_CLOUD + mImpl->mObjectPartition.push_back(new LLGrassPartition()); //PARTITION_GRASS + mImpl->mObjectPartition.push_back(new LLVolumePartition()); //PARTITION_VOLUME + mImpl->mObjectPartition.push_back(new LLBridgePartition()); //PARTITION_BRIDGE + mImpl->mObjectPartition.push_back(new LLHUDParticlePartition());//PARTITION_HUD_PARTICLE + mImpl->mObjectPartition.push_back(NULL); //PARTITION_NONE } void LLViewerRegion::initStats() { - mLastNetUpdate.reset(); + mImpl->mLastNetUpdate.reset(); mPacketsIn = 0; mBitsIn = 0; mLastBitsIn = 0; @@ -248,9 +313,9 @@ void LLViewerRegion::initStats() LLViewerRegion::~LLViewerRegion() { - if(mHttpResponderPtr) + if(mImpl->mHttpResponderPtr) { - (static_cast(mHttpResponderPtr.get()))->setRegion(NULL) ; + (static_cast(mImpl->mHttpResponderPtr.get()))->setRegion(NULL) ; } gVLManager.cleanupData(this); @@ -262,19 +327,47 @@ LLViewerRegion::~LLViewerRegion() gObjectList.killObjects(this); - delete mCompositionp; + delete mImpl->mCompositionp; delete mParcelOverlay; - delete mLandp; - delete mEventPoll; - LLHTTPSender::clearSender(mHost); + delete mImpl->mLandp; + delete mImpl->mEventPoll; + LLHTTPSender::clearSender(mImpl->mHost); - saveCache(); + saveObjectCache(); - std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer()); + std::for_each(mImpl->mObjectPartition.begin(), mImpl->mObjectPartition.end(), DeletePointer()); + + delete mImpl; + mImpl = NULL; } +/*LLEventPump& LLViewerRegion::getCapAPI() const +{ + return mImpl->mCapabilityListener.getCapAPI(); +}*/ -void LLViewerRegion::loadCache() +/*virtual*/ +const LLHost& LLViewerRegion::getHost() const +{ + return mImpl->mHost; +} + +LLSurface & LLViewerRegion::getLand() const +{ + return *mImpl->mLandp; +} + +const LLUUID& LLViewerRegion::getRegionID() const +{ + return mImpl->mRegionID; +} + +void LLViewerRegion::setRegionID(const LLUUID& region_id) +{ + mImpl->mRegionID = region_id; +} + +void LLViewerRegion::loadObjectCache() { if (mCacheLoaded) { @@ -284,154 +377,46 @@ void LLViewerRegion::loadCache() // Presume success. If it fails, we don't want to try again. mCacheLoaded = TRUE; - LLVOCacheEntry *entry; - - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"") + gDirUtilp->getDirDelimiter() + - llformat("objects_%d_%d.slc",U32(mHandle>>32)/REGION_WIDTH_UNITS, U32(mHandle)/REGION_WIDTH_UNITS ); - - LLFILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - if (!fp) + if(LLVOCache::hasInstance()) { - // might not have a file, which is normal - return; + LLVOCache::getInstance()->readFromCache(mHandle, mImpl->mCacheID, mImpl->mCacheMap) ; } - - 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) - { - // 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; - } - - 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); } -void LLViewerRegion::saveCache() +void LLViewerRegion::saveObjectCache() { if (!mCacheLoaded) { return; } - S32 num_entries = mCacheEntriesCount; - if (0 == num_entries) + if (mImpl->mCacheMap.empty()) { return; } - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"") + gDirUtilp->getDirDelimiter() + - llformat("objects_%d_%d.slc", U32(mHandle>>32)/REGION_WIDTH_UNITS, U32(mHandle)/REGION_WIDTH_UNITS ); - - 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, mImpl->mCacheID, mImpl->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 = mImpl->mCacheMap.begin(); iter != mImpl->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); + mImpl->mCacheMap.clear(); } void LLViewerRegion::sendMessage() { - gMessageSystem->sendMessage(mHost); + gMessageSystem->sendMessage(mImpl->mHost); } void LLViewerRegion::sendReliableMessage() { - gMessageSystem->sendReliable(mHost); + gMessageSystem->sendReliable(mImpl->mHost); } void LLViewerRegion::setFlags(BOOL b, U32 flags) @@ -448,12 +433,12 @@ void LLViewerRegion::setFlags(BOOL b, U32 flags) void LLViewerRegion::setWaterHeight(F32 water_level) { - mLandp->setWaterHeight(water_level); + mImpl->mLandp->setWaterHeight(water_level); } F32 LLViewerRegion::getWaterHeight() const { - return mLandp->getWaterHeight(); + return mImpl->mLandp->getWaterHeight(); } BOOL LLViewerRegion::isVoiceEnabled() const @@ -469,9 +454,9 @@ void LLViewerRegion::setRegionFlags(U32 flags) void LLViewerRegion::setOriginGlobal(const LLVector3d &origin_global) { - mOriginGlobal = origin_global; + mImpl->mOriginGlobal = origin_global; updateRenderMatrix(); - mLandp->setOriginGlobal(origin_global); + mImpl->mLandp->setOriginGlobal(origin_global); mWind.setOriginGlobal(origin_global); mCloudLayer.setOriginGlobal(origin_global); calculateCenterGlobal(); @@ -487,16 +472,34 @@ void LLViewerRegion::setTimeDilation(F32 time_dilation) mTimeDilation = time_dilation; } +const LLVector3d & LLViewerRegion::getOriginGlobal() const +{ + return mImpl->mOriginGlobal; +} LLVector3 LLViewerRegion::getOriginAgent() const { - return gAgent.getPosAgentFromGlobal(mOriginGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mOriginGlobal); } +const LLVector3d & LLViewerRegion::getCenterGlobal() const +{ + return mImpl->mCenterGlobal; +} LLVector3 LLViewerRegion::getCenterAgent() const { - return gAgent.getPosAgentFromGlobal(mCenterGlobal); + return gAgent.getPosAgentFromGlobal(mImpl->mCenterGlobal); +} + +void LLViewerRegion::setOwner(const LLUUID& owner_id) +{ + mImpl->mOwnerID = owner_id; +} + +const LLUUID& LLViewerRegion::getOwner() const +{ + return mImpl->mOwnerID; } void LLViewerRegion::setRegionNameAndZone (const std::string& name_zone) @@ -646,7 +649,10 @@ void LLViewerRegion::processRegionInfo(LLMessageSystem* msg, void**) LLFloaterReporter::processRegionInfo(msg); } - +void LLViewerRegion::setCacheID(const LLUUID& id) +{ + mImpl->mCacheID = id; +} S32 LLViewerRegion::renderPropertyLines() { @@ -673,7 +679,7 @@ void LLViewerRegion::dirtyHeights() BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { // did_update returns TRUE if we did at least one significant update - BOOL did_update = mLandp->idleUpdate(max_update_time); + BOOL did_update = mImpl->mLandp->idleUpdate(max_update_time); if (mParcelOverlay) { @@ -688,7 +694,7 @@ BOOL LLViewerRegion::idleUpdate(F32 max_update_time) // As above, but forcibly do the update. void LLViewerRegion::forceUpdate() { - mLandp->idleUpdate(0.f); + mImpl->mLandp->idleUpdate(0.f); if (mParcelOverlay) { @@ -698,17 +704,21 @@ void LLViewerRegion::forceUpdate() void LLViewerRegion::connectNeighbor(LLViewerRegion *neighborp, U32 direction) { - mLandp->connectNeighbor(neighborp->mLandp, direction); + mImpl->mLandp->connectNeighbor(neighborp->mImpl->mLandp, direction); mCloudLayer.connectNeighbor(&(neighborp->mCloudLayer), direction); } void LLViewerRegion::disconnectAllNeighbors() { - mLandp->disconnectAllNeighbors(); + mImpl->mLandp->disconnectAllNeighbors(); mCloudLayer.disconnectAllNeighbors(); } +LLVLComposition * LLViewerRegion::getComposition() const +{ + return mImpl->mCompositionp; +} F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const { @@ -802,10 +812,10 @@ F32 LLViewerRegion::getCompositionXY(const S32 x, const S32 y) const void LLViewerRegion::calculateCenterGlobal() { - mCenterGlobal = mOriginGlobal; - mCenterGlobal.mdV[VX] += 0.5 * mWidth; - mCenterGlobal.mdV[VY] += 0.5 * mWidth; - mCenterGlobal.mdV[VZ] = 0.5*mLandp->getMinZ() + mLandp->getMaxZ(); + mImpl->mCenterGlobal = mImpl->mOriginGlobal; + mImpl->mCenterGlobal.mdV[VX] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VY] += 0.5 * mWidth; + mImpl->mCenterGlobal.mdV[VZ] = 0.5 * mImpl->mLandp->getMinZ() + mImpl->mLandp->getMaxZ(); } void LLViewerRegion::calculateCameraDistance() @@ -821,8 +831,17 @@ U32 LLViewerRegion::getNetDetailsForLCD() std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) { s << "{ "; - s << region.mHost; + s << region.mImpl->mHost; s << " mOriginGlobal = " << region.getOriginGlobal()<< "\n"; + std::string name(region.getName()), zone(region.getZoning()); + if (! name.empty()) + { + s << " mName = " << name << '\n'; + } + if (! zone.empty()) + { + s << " mZoning = " << zone << '\n'; + } s << "}"; return s; } @@ -832,9 +851,9 @@ std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) void LLViewerRegion::updateNetStats() { - F32 dt = mLastNetUpdate.getElapsedTimeAndResetF32(); + F32 dt = mImpl->mLastNetUpdate.getElapsedTimeAndResetF32(); - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { mAlive = false; @@ -863,10 +882,10 @@ void LLViewerRegion::updateNetStats() U32 LLViewerRegion::getPacketsLost() const { - LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mHost); + LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(mImpl->mHost); if (!cdp) { - llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mHost << llendl; + llinfos << "LLViewerRegion::getPacketsLost couldn't find circuit for " << mImpl->mHost << llendl; return 0; } else @@ -875,6 +894,16 @@ U32 LLViewerRegion::getPacketsLost() const } } +void LLViewerRegion::setHttpResponderPtrNULL() +{ + mImpl->mHttpResponderPtr = NULL; +} + +const LLHTTPClient::ResponderPtr LLViewerRegion::getHttpResponderPtr() const +{ + return mImpl->mHttpResponderPtr; +} + BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const { LLVector3 pos_region = getPosRegionFromGlobal(point_global); @@ -901,7 +930,7 @@ BOOL LLViewerRegion::pointInRegionGlobal(const LLVector3d &point_global) const LLVector3 LLViewerRegion::getPosRegionFromGlobal(const LLVector3d &point_global) const { LLVector3 pos_region; - pos_region.setVec(point_global - mOriginGlobal); + pos_region.setVec(point_global - mImpl->mOriginGlobal); return pos_region; } @@ -909,7 +938,7 @@ LLVector3d LLViewerRegion::getPosGlobalFromRegion(const LLVector3 &pos_region) c { LLVector3d pos_region_d; pos_region_d.setVec(pos_region); - return pos_region_d + mOriginGlobal; + return pos_region_d + mImpl->mOriginGlobal; } LLVector3 LLViewerRegion::getPosAgentFromRegion(const LLVector3 &pos_region) const @@ -926,7 +955,7 @@ LLVector3 LLViewerRegion::getPosRegionFromAgent(const LLVector3 &pos_agent) cons F32 LLViewerRegion::getLandHeightRegion(const LLVector3& region_pos) { - return mLandp->resolveHeightRegion( region_pos ); + return mImpl->mLandp->resolveHeightRegion( region_pos ); } bool LLViewerRegion::isAlive() @@ -1078,7 +1107,7 @@ void LLViewerRegion::updateCoarseLocations(LLMessageSystem* msg) // treat the target specially for the map if(i == target_index) { - LLVector3d global_pos(mOriginGlobal); + LLVector3d global_pos(mImpl->mOriginGlobal); global_pos.mdV[VX] += (F64)(x_pos); global_pos.mdV[VY] += (F64)(y_pos); global_pos.mdV[VZ] += (F64)(z_pos) * 4.0; @@ -1113,12 +1142,12 @@ void LLViewerRegion::getInfo(LLSD& info) info["Region"]["Handle"]["y"] = (LLSD::Integer)y; } -void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) +LLViewerRegion::eCacheUpdateResult LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp) { U32 local_id = objectp->getLocalID(); U32 crc = objectp->getCRC(); - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); if (entry) { @@ -1127,45 +1156,40 @@ void LLViewerRegion::cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinary { // Record a hit entry->recordDupe(); + return CACHE_UPDATE_DUPE; } - else - { - // Update the cache entry - mCacheMap.erase(local_id); - delete entry; - entry = new LLVOCacheEntry(local_id, crc, dp); - mCacheEnd.insert(*entry); - mCacheMap[local_id] = entry; - } - } - else - { - // we haven't seen this object before - // Create new entry and add to map - if (mCacheEntriesCount > MAX_OBJECT_CACHE_ENTRIES) - { - entry = mCacheStart.getNext(); - mCacheMap.erase(entry->getLocalID()); - delete entry; - mCacheEntriesCount--; - } + // Update the cache entry + mImpl->mCacheMap.erase(local_id); + delete entry; entry = new LLVOCacheEntry(local_id, crc, dp); - - mCacheEnd.insert(*entry); - mCacheMap[local_id] = entry; - mCacheEntriesCount++; + mImpl->mCacheMap[local_id] = entry; + return CACHE_UPDATE_CHANGED; } - return ; + + // we haven't seen this object before + + // Create new entry and add to map + eCacheUpdateResult result = CACHE_UPDATE_ADDED; + if (mImpl->mCacheMap.size() > MAX_OBJECT_CACHE_ENTRIES) + { + mImpl->mCacheMap.erase(mImpl->mCacheMap.begin()); + result = CACHE_UPDATE_REPLACED; + + } + entry = new LLVOCacheEntry(local_id, crc, dp); + + mImpl->mCacheMap[local_id] = entry; + return result; } // Get data packer for this object, if we have cached data // AND the CRC matches. JC -LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) +LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc, U8 &cache_miss_type) { - llassert(mCacheLoaded); + //llassert(mCacheLoaded); This assert failes often, changing to early-out -- davep, 2010/10/18 - LLVOCacheEntry* entry = get_if_there(mCacheMap, local_id, (LLVOCacheEntry*)NULL); + LLVOCacheEntry* entry = get_if_there(mImpl->mCacheMap, local_id, (LLVOCacheEntry*)NULL); if (entry) { @@ -1174,19 +1198,23 @@ LLDataPacker *LLViewerRegion::getDP(U32 local_id, U32 crc) { // Record a hit entry->recordHit(); + cache_miss_type = CACHE_MISS_TYPE_NONE; return entry->getDP(crc); } else { // llinfos << "CRC miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_CRC; mCacheMissCRC.put(local_id); } } else { // llinfos << "Cache miss for " << local_id << llendl; + cache_miss_type = CACHE_MISS_TYPE_FULL; mCacheMissFull.put(local_id); } + return NULL; } @@ -1206,9 +1234,6 @@ void LLViewerRegion::requestCacheMisses() S32 blocks = 0; S32 i; - const U8 CACHE_MISS_TYPE_FULL = 0; - const U8 CACHE_MISS_TYPE_CRC = 1; - // Send full cache miss updates. For these, we KNOW we don't // have a viewer object. for (i = 0; i < full_count; i++) @@ -1269,7 +1294,13 @@ void LLViewerRegion::requestCacheMisses() mCacheMissFull.reset(); mCacheMissCRC.reset(); + mCacheDirty = TRUE ; // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; + #if LL_RECORD_VIEWER_STATS + LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); + LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); + #endif } void LLViewerRegion::dumpCache() @@ -1286,9 +1317,10 @@ void LLViewerRegion::dumpCache() } LLVOCacheEntry *entry; - - for (entry = mCacheStart.getNext(); entry && (entry != &mCacheEnd); entry = entry->getNext()) + for(LLVOCacheEntry::vocache_entry_map_t::iterator iter = mImpl->mCacheMap.begin(); iter != mImpl->mCacheMap.end(); ++iter) { + entry = iter->second ; + S32 hits = entry->getHitCount(); S32 changes = entry->getCRCChangeCount(); @@ -1299,7 +1331,7 @@ void LLViewerRegion::dumpCache() change_bin[changes]++; } - llinfos << "Count " << mCacheEntriesCount << llendl; + llinfos << "Count " << mImpl->mCacheMap.size() << llendl; for (i = 0; i < BINS; i++) { llinfos << "Hits " << i << " " << hit_bin[i] << llendl; @@ -1419,7 +1451,7 @@ void LLViewerRegion::unpackRegionHandshake() // Now that we have the name, we can load the cache file // off disk. - loadCache(); + loadObjectCache(); // After loading cache, signal that simulator can start // sending data. @@ -1436,15 +1468,16 @@ void LLViewerRegion::unpackRegionHandshake() void LLViewerRegion::setSeedCapability(const std::string& url) { - if (getCapability("Seed") == url) + if (getCapability("Seed") == url) { - llwarns << "Ignoring duplicate seed capability" << llendl; - return; + // llwarns << "Ignoring duplicate seed capability" << llendl; + return; } - delete mEventPoll; - mEventPoll = NULL; - mCapabilities.clear(); + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + + mImpl->mCapabilities.clear(); setCapability("Seed", url); LLSD capabilityNames = LLSD::emptyArray(); @@ -1460,9 +1493,10 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("FetchInventory"); capabilityNames.append("FetchInventoryDescendents"); } + capabilityNames.append("GetDisplayNames"); capabilityNames.append("GetTexture"); capabilityNames.append("GroupProposalBallot"); - capabilityNames.append("GetDisplayNames"); + capabilityNames.append("HomeLocation"); capabilityNames.append("MapLayer"); capabilityNames.append("MapLayerGod"); @@ -1480,8 +1514,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("SendPostcard"); capabilityNames.append("SendUserReport"); capabilityNames.append("SendUserReportWithScreenshot"); - capabilityNames.append("SetDisplayName"); capabilityNames.append("ServerReleaseNotes"); + capabilityNames.append("SetDisplayName"); capabilityNames.append("StartGroupProposal"); capabilityNames.append("TextureStats"); capabilityNames.append("UntrustedSimulatorMessage"); @@ -1501,25 +1535,29 @@ void LLViewerRegion::setSeedCapability(const std::string& url) llinfos << "posting to seed " << url << llendl; - mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ; - LLHTTPClient::post(url, capabilityNames, mHttpResponderPtr); + mImpl->mHttpResponderPtr = BaseCapabilitiesComplete::build(this) ; + LLHTTPClient::post(url, capabilityNames, mImpl->mHttpResponderPtr); } void LLViewerRegion::setCapability(const std::string& name, const std::string& url) { if(name == "EventQueueGet") { - delete mEventPoll; - mEventPoll = NULL; - mEventPoll = new LLEventPoll(url, getHost()); + delete mImpl->mEventPoll; + mImpl->mEventPoll = NULL; + mImpl->mEventPoll = new LLEventPoll(url, getHost()); } else if(name == "UntrustedSimulatorMessage") { - LLHTTPSender::setSender(mHost, new LLCapHTTPSender(url)); + LLHTTPSender::setSender(mImpl->mHost, new LLCapHTTPSender(url)); } else { - mCapabilities[name] = url; + mImpl->mCapabilities[name] = url; + if(name == "GetTexture") + { + mHttpUrl = url ; + } } } @@ -1530,8 +1568,8 @@ bool LLViewerRegion::isSpecialCapabilityName(const std::string &name) std::string LLViewerRegion::getCapability(const std::string& name) const { - CapabilityMap::const_iterator iter = mCapabilities.find(name); - if(iter == mCapabilities.end()) + CapabilityMap::const_iterator iter = mImpl->mCapabilities.find(name); + if(iter == mImpl->mCapabilities.end()) { return ""; } @@ -1552,7 +1590,7 @@ void LLViewerRegion::logActiveCapabilities() const { int count = 0; CapabilityMap::const_iterator iter; - for (iter = mCapabilities.begin(); iter != mCapabilities.end(); iter++, count++) + for (iter = mImpl->mCapabilities.begin(); iter != mImpl->mCapabilities.end(); ++iter, ++count) { if (!iter->second.empty()) { @@ -1564,9 +1602,9 @@ void LLViewerRegion::logActiveCapabilities() const LLSpatialPartition* LLViewerRegion::getSpatialPartition(U32 type) { - if (type < mObjectPartition.size()) + if (type < mImpl->mObjectPartition.size()) { - return mObjectPartition[type]; + return mImpl->mObjectPartition[type]; } return NULL; } @@ -1585,3 +1623,8 @@ void LLViewerRegion::showReleaseNotes() LLWeb::loadURL(url); mReleaseNotesRequested = FALSE; } + +std::string LLViewerRegion::getDescription() const +{ + return stringize(*this); +} diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 67f0ff496..645c240fc 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -42,18 +42,18 @@ #include "llcloud.h" #include "llstat.h" #include "v3dmath.h" -#include "llhost.h" #include "llstring.h" #include "llregionflags.h" #include "lluuid.h" -#include "lldatapacker.h" -#include "llvocache.h" #include "llweb.h" +#include "llcapabilityprovider.h" +#include "m4math.h" // LLMatrix4 +#include "llhttpclient.h" // Surface id's #define LAND 1 #define WATER 2 -const U32 MAX_OBJECT_CACHE_ENTRIES = 10000; +const U32 MAX_OBJECT_CACHE_ENTRIES = 50000; class LLEventPoll; @@ -66,8 +66,16 @@ class LLSurface; class LLVOCache; class LLVOCacheEntry; class LLSpatialPartition; +class LLEventPump; +//class LLCapabilityListener; +class LLDataPacker; +class LLDataPackerBinaryBuffer; +class LLHost; +class LLBBox; -class LLViewerRegion +class LLViewerRegionImpl; + +class LLViewerRegion: public LLCapabilityProvider // implements this interface { public: //MUST MATCH THE ORDER OF DECLARATION IN CONSTRUCTOR @@ -96,9 +104,8 @@ public: ~LLViewerRegion(); // Call this after you have the region name and handle. - void loadCache(); - - void saveCache(); + void loadObjectCache(); + void saveObjectCache(); void sendMessage(); // Send the current message to this region's simulator void sendReliableMessage(); // Send the current message to this region's simulator @@ -161,19 +168,19 @@ public: F32 getTimeDilation() const { return mTimeDilation; } // Origin height is at zero. - const LLVector3d &getOriginGlobal() const { return mOriginGlobal; } + const LLVector3d &getOriginGlobal() const; LLVector3 getOriginAgent() const; // Center is at the height of the water table. - const LLVector3d &getCenterGlobal() const { return mCenterGlobal; } + const LLVector3d &getCenterGlobal() const; LLVector3 getCenterAgent() const; void setRegionNameAndZone(const std::string& name_and_zone); const std::string& getName() const { return mName; } const std::string& getZoning() const { return mZoning; } - void setOwner(const LLUUID& owner_id) { mOwnerID = owner_id; } - const LLUUID& getOwner() const { return mOwnerID; } + void setOwner(const LLUUID& owner_id); + const LLUUID& getOwner() const; // Is the current agent on the estate manager list for this region? void setIsEstateManager(BOOL b) { mIsEstateManager = b; } @@ -205,7 +212,7 @@ public: // can process the message. static void processRegionInfo(LLMessageSystem* msg, void**); - void setCacheID(const LLUUID& id) { mCacheID = id; } + void setCacheID(const LLUUID& id); F32 getWidth() const { return mWidth; } @@ -221,27 +228,35 @@ public: U32 getPacketsLost() const; - void setHttpResponderPtrNULL() {mHttpResponderPtr = NULL ;} - const LLHTTPClient::ResponderPtr getHttpResponderPtr() const {return mHttpResponderPtr ;} + void setHttpResponderPtrNULL(); + const LLHTTPClient::ResponderPtr getHttpResponderPtr() const; // Get/set named capability URLs for this region. void setSeedCapability(const std::string& url); void setCapability(const std::string& name, const std::string& url); - std::string getCapability(const std::string& name) const; - static bool isSpecialCapabilityName(const std::string &name); - void logActiveCapabilities() const; + // implements LLCapabilityProvider + virtual std::string getCapability(const std::string& name) const; + // has region received its final (not seed) capability list? bool capabilitiesReceived() const; void setCapabilitiesReceived(bool received); - const LLHost &getHost() const { return mHost; } + static bool isSpecialCapabilityName(const std::string &name); + void logActiveCapabilities() const; + + /// Get LLEventPump on which we listen for capability requests + /// (https://wiki.lindenlab.com/wiki/Viewer:Messaging/Messaging_Notes#Capabilities) + // LLEventPump& getCapAPI() const; + + /// implements LLCapabilityProvider + /*virtual*/ const LLHost& getHost() const; const U64 &getHandle() const { return mHandle; } - LLSurface &getLand() const { return *mLandp; } + LLSurface &getLand() const; // set and get the region id - const LLUUID& getRegionID() const { return mRegionID; } - void setRegionID(const LLUUID& region_id) { mRegionID = region_id; } + const LLUUID& getRegionID() const; + void setRegionID(const LLUUID& region_id); BOOL pointInRegionGlobal(const LLVector3d &point_global) const; LLVector3 getPosRegionFromGlobal(const LLVector3d &point_global) const; @@ -249,7 +264,7 @@ public: LLVector3 getPosAgentFromRegion(const LLVector3 ®ion_pos) const; LLVector3d getPosGlobalFromRegion(const LLVector3 &offset) const; - LLVLComposition *getComposition() const { return mCompositionp; } + LLVLComposition *getComposition() const; F32 getCompositionXY(const S32 x, const S32 y) const; BOOL isOwnedSelf(const LLVector3& pos); @@ -263,10 +278,26 @@ public: F32 getLandHeightRegion(const LLVector3& region_pos); void getInfo(LLSD& info); + + + typedef enum + { + CACHE_MISS_TYPE_FULL = 0, + CACHE_MISS_TYPE_CRC, + CACHE_MISS_TYPE_NONE + } eCacheMissType; + + typedef enum + { + CACHE_UPDATE_DUPE = 0, + CACHE_UPDATE_CHANGED, + CACHE_UPDATE_ADDED, + CACHE_UPDATE_REPLACED + } eCacheUpdateResult; // handle a full update message - void cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); - LLDataPacker *getDP(U32 local_id, U32 crc); + eCacheUpdateResult cacheFullUpdate(LLViewerObject* objectp, LLDataPackerBinaryBuffer &dp); + LLDataPacker *getDP(U32 local_id, U32 crc, U8 &cache_miss_type); void requestCacheMisses(); void addCacheMissFull(const U32 local_id); @@ -281,8 +312,14 @@ public: // used by LCD to get details for debug screen U32 getNetDetailsForLCD(); + + /// implements LLCapabilityProvider + virtual std::string getDescription() const; + std::string getHttpUrl() const { return mHttpUrl ;} LLSpatialPartition* getSpatialPartition(U32 type); + + bool objectIsReturnable(const LLVector3& pos, const std::vector& boxes) const; public: struct CompareDistance { @@ -319,34 +356,19 @@ public: LLDynamicArray mMapAvatarIDs; private: - // The surfaces and other layers - LLSurface* mLandp; + LLViewerRegionImpl * mImpl; - // Region geometry data - LLVector3d mOriginGlobal; // Location of southwest corner of region (meters) - LLVector3d mCenterGlobal; // Location of center in world space (meters) F32 mWidth; // Width of region on a side (meters) - U64 mHandle; - LLHost mHost; - - // The unique ID for this region. - LLUUID mRegionID; - F32 mTimeDilation; // time dilation of physics simulation on simulator // simulator name std::string mName; std::string mZoning; - // region/estate owner - usually null. - LLUUID mOwnerID; - // Is this agent on the estate managers list for this region? BOOL mIsEstateManager; - // Network statistics for the region's circuit... - LLTimer mLastNetUpdate; U32 mPacketsIn; U32 mBitsIn; U32 mLastBitsIn; @@ -358,9 +380,6 @@ private: U32 mPingDelay; F32 mDeltaTime; // Time since last measurement of lastPackets, Bits, etc - // Misc - LLVLComposition *mCompositionp; // Composition layer for the surface - U32 mRegionFlags; // includes damage flags U8 mSimAccess; F32 mBillableFactor; @@ -370,43 +389,24 @@ private: // Information for Homestead / CR-53 S32 mClassID; S32 mCPURatio; + std::string mColoName; std::string mProductSKU; std::string mProductName; - + std::string mHttpUrl ; // Maps local ids to cache entries. // Regions can have order 10,000 objects, so assume // a structure of size 2^14 = 16,000 BOOL mCacheLoaded; - typedef std::map cache_map_t; - cache_map_t mCacheMap; - LLVOCacheEntry mCacheStart; - LLVOCacheEntry mCacheEnd; - U32 mCacheEntriesCount; + BOOL mCacheDirty; + LLDynamicArray mCacheMissFull; LLDynamicArray mCacheMissCRC; - // time? - // LRU info? - // Cache ID is unique per-region, across renames, moving locations, - // etc. - LLUUID mCacheID; - - typedef std::map CapabilityMap; - CapabilityMap mCapabilities; - - LLEventPoll* mEventPoll; - -private: bool mAlive; // can become false if circuit disconnects bool mCapabilitiesReceived; - //spatial partitions for objects in this region - std::vector mObjectPartition; - - LLHTTPClient::ResponderPtr mHttpResponderPtr ; - BOOL mReleaseNotesRequested; }; diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 4f4330b17..10e4b869b 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -35,54 +35,74 @@ #include "llvocache.h" #include "llerror.h" +#include "llregionhandle.h" +#include "llviewercontrol.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 //--------------------------------------------------------------------------- LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp) + : + mLocalID(local_id), + mCRC(crc), + mHitCount(0), + mDupeCount(0), + mCRCChangeCount(0) { - mLocalID = local_id; - mCRC = crc; - mHitCount = 0; - mDupeCount = 0; - mCRCChangeCount = 0; mBuffer = new U8[dp.getBufferSize()]; mDP.assignBuffer(mBuffer, dp.getBufferSize()); - mDP = dp; + mDP = dp; //memcpy } LLVOCacheEntry::LLVOCacheEntry() + : + mLocalID(0), + mCRC(0), + mHitCount(0), + mDupeCount(0), + mCRCChangeCount(0), + mBuffer(NULL) { - mLocalID = 0; - mCRC = 0; - mHitCount = 0; - mDupeCount = 0; - mCRCChangeCount = 0; - mBuffer = NULL; mDP.assignBuffer(mBuffer, 0); } - -static inline void checkedRead(LLFILE *fp, void *data, size_t nbytes) +LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) + : mBuffer(NULL) { - if (fread(data, 1, nbytes, fp) != nbytes) + S32 size = -1; + BOOL success; + + mDP.assignBuffer(mBuffer, 0); + success = check_read(apr_file, &mLocalID, sizeof(U32)); + if(success) { - llwarns << "Short read" << llendl; - memset(data, 0, nbytes); + success = check_read(apr_file, &mCRC, sizeof(U32)); } -} - -LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp) -{ - 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)); + if(success) + { + success = check_read(apr_file, &mHitCount, sizeof(S32)); + } + if(success) + { + success = check_read(apr_file, &mDupeCount, sizeof(S32)); + } + if(success) + { + 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,24 +110,40 @@ LLVOCacheEntry::LLVOCacheEntry(LLFILE *fp) // We've got a bogus size, skip reading it. // We won't bother seeking, because the rest of this file // is likely bogus, and will be tossed anyway. - llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl; - mLocalID = 0; - mCRC = 0; - mBuffer = NULL; - return; + llwarns << "Bogus cache entry, size " << size << ", aborting!" << llendl; + success = FALSE; + } + } + if(success && size > 0) + { + mBuffer = new U8[size]; + success = check_read(apr_file, mBuffer, size); + + if(success) + { + mDP.assignBuffer(mBuffer, size); + } + else + { + delete[] mBuffer ; + mBuffer = NULL ; + } } - mBuffer = new U8[size]; - checkedRead(fp, mBuffer, size); - mDP.assignBuffer(mBuffer, size); + if(!success) + { + mLocalID = 0; + mCRC = 0; + mHitCount = 0; + mDupeCount = 0; + mCRCChangeCount = 0; + mBuffer = NULL; + } } LLVOCacheEntry::~LLVOCacheEntry() { - if(mBuffer) - { - delete [] mBuffer; - } + mDP.freeBuffer(); } @@ -157,22 +193,564 @@ void LLVOCacheEntry::dump() const << llendl; } -static inline void checkedWrite(LLFILE *fp, const void *data, size_t nbytes) +BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const { - if (fwrite(data, 1, nbytes, fp) != nbytes) + BOOL success; + success = check_write(apr_file, (void*)&mLocalID, sizeof(U32)); + if(success) { - llwarns << "Short write" << llendl; + 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 MIN_ENTRIES_TO_PURGE = 16 ; +const U32 INVALID_TIME = 0 ; +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 ; } } -void LLVOCacheEntry::writeToFile(LLFILE *fp) const +LLVOCache::LLVOCache(): + mInitialized(FALSE), + mReadOnly(TRUE), + mNumEntries(0), + mCacheSize(1) { - 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); + mEnabled = gSavedSettings.getBOOL("ObjectCacheEnabled"); } + +LLVOCache::~LLVOCache() +{ + if(mEnabled) + { + writeCacheHeader(); + clearCacheInMemory(); + } +} + +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(!mEnabled) + { + llwarns << "Not initializing cache: Cache is currently disabled." << llendl; + return ; + } + + if(mInitialized) + { + llwarns << "Cache already initialized." << llendl; + return ; + } + mInitialized = TRUE ; + + setDirNames(location); + if (!mReadOnly) + { + LLFile::mkdir(mObjectCacheDirName); + } + mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES); + mMetaInfo.mVersion = cache_version; + readCacheHeader(); + + 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) + { + llwarns << "Not removing cache at " << location << ": Cache is currently in read-only mode." << llendl; + return ; + } + + llinfos << "about to remove the object cache due to settings." << llendl ; + + std::string mask = "*"; + std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname); + llinfos << "Removing cache at " << cache_dir << llendl; + gDirUtilp->deleteFilesInDir(cache_dir, mask); //delete all files + LLFile::rmdir(cache_dir); + + clearCacheInMemory(); + mInitialized = FALSE ; +} + +void LLVOCache::removeCache() +{ + llassert_always(mInitialized) ; + if(mReadOnly) + { + llwarns << "Not clearing object cache: Cache is currently in read-only mode." << llendl; + return ; + } + + llinfos << "about to remove the object cache due to some error." << llendl ; + + std::string mask = "*"; + llinfos << "Removing cache at " << mObjectCacheDirName << llendl; + gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); + + clearCacheInMemory() ; + writeCacheHeader(); +} + +void LLVOCache::removeEntry(HeaderEntryInfo* entry) +{ + llassert_always(mInitialized) ; + if(mReadOnly) + { + return ; + } + if(!entry) + { + return ; + } + + header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ; + if(iter != mHeaderEntryQueue.end()) + { + mHandleEntryMap.erase(entry->mHandle) ; + mHeaderEntryQueue.erase(iter) ; + removeFromCache(entry) ; + delete entry ; + + mNumEntries = mHandleEntryMap.size() ; + } +} + +void LLVOCache::removeEntry(U64 handle) +{ + handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + if(iter == mHandleEntryMap.end()) //no cache + { + return ; + } + HeaderEntryInfo* entry = iter->second ; + removeEntry(entry) ; +} + +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) +{ + 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(HeaderEntryInfo* entry) +{ + if(mReadOnly) + { + llwarns << "Not removing cache for handle " << entry->mHandle << ": Cache is currently in read-only mode." << llendl; + return ; + } + + std::string filename; + getObjectCacheFilename(entry->mHandle, filename); + LLAPRFile::remove(filename); + entry->mTime = INVALID_TIME ; + updateEntry(entry) ; //update the head file. +} + +void LLVOCache::readCacheHeader() +{ + if(!mEnabled) + { + llwarns << "Not reading cache header: Cache is currently disabled." << llendl; + return; + } + + //clear stale info. + clearCacheInMemory(); + + bool success = true ; + if (LLAPRFile::isExist(mHeaderFileName)) + { + LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, LLAPRFile::local); + + //read the meta element + success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + + if(success) + { + HeaderEntryInfo* entry = NULL ; + mNumEntries = 0 ; + U32 num_read = 0 ; + while(num_read++ < MAX_NUM_OBJECT_ENTRIES) + { + if(!entry) + { + entry = new HeaderEntryInfo() ; + } + success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo)); + + if(!success) //failed + { + llwarns << "Error reading cache header entry. (entry_index=" << mNumEntries << ")" << llendl; + delete entry ; + entry = NULL ; + break ; + } + else if(entry->mTime == INVALID_TIME) + { + continue ; //an empty entry + } + + entry->mIndex = mNumEntries++ ; + mHeaderEntryQueue.insert(entry) ; + mHandleEntryMap[entry->mHandle] = entry ; + entry = NULL ; + } + if(entry) + { + delete entry ; + } + } + + //--------- + //debug code + //---------- + //std::string name ; + //for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) + //{ + // getObjectCacheFilename((*iter)->mHandle, name) ; + // llinfos << name << llendl ; + //} + //----------- + } + else + { + writeCacheHeader() ; + } + + if(!success) + { + removeCache() ; //failed to read header, clear the cache + } + else if(mNumEntries >= mCacheSize) + { + purgeEntries(mCacheSize) ; + } + + return ; +} + +void LLVOCache::writeCacheHeader() +{ + if (!mEnabled) + { + llwarns << "Not writing cache header: Cache is currently disabled." << llendl; + return; + } + + if(mReadOnly) + { + llwarns << "Not writing cache header: Cache is currently in read-only mode." << llendl; + return; + } + + bool success = true ; + { + LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, LLAPRFile::local); + + //write the meta element + success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ; + + + mNumEntries = 0 ; + for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter) + { + (*iter)->mIndex = mNumEntries++ ; + success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo)); + } + + mNumEntries = mHeaderEntryQueue.size() ; + if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES) + { + HeaderEntryInfo* entry = new HeaderEntryInfo() ; + entry->mTime = INVALID_TIME ; + for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++) + { + //fill the cache with the default entry. + success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ; + + } + delete entry ; + } + } + + if(!success) + { + clearCacheInMemory() ; + mReadOnly = TRUE ; //disable the cache. + } + return ; +} + +BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry) +{ + LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, LLAPRFile::local); + apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ; + + return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ; +} + +void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) +{ + if(!mEnabled) + { + llwarns << "Not reading cache for handle " << handle << "): Cache is currently disabled." << llendl; + return ; + } + llassert_always(mInitialized); + + handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + if(iter == mHandleEntryMap.end()) //no cache + { + llwarns << "No handle map entry for " << handle << llendl; + return ; + } + + bool success = true ; + { + std::string filename; + getObjectCacheFilename(handle, filename); + LLAPRFile apr_file(filename, APR_READ|APR_BINARY, LLAPRFile::local); + + LLUUID cache_id ; + success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ; + + if(success) + { + if(cache_id != id) + { + llinfos << "Cache ID doesn't match for this region, discarding"<< llendl; + success = false ; + } + + if(success) + { + S32 num_entries; + success = check_read(&apr_file, &num_entries, sizeof(S32)) ; + + for (S32 i = 0; success && 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 ; + success = false ; + } + cache_entry_map[entry->getLocalID()] = entry; + } + } + } + } + + if(!success) + { + if(cache_entry_map.empty()) + { + removeEntry(iter->second) ; + } + } + + return ; +} + +void LLVOCache::purgeEntries(U32 size) +{ + while(mHeaderEntryQueue.size() > size) + { + header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; + HeaderEntryInfo* entry = *iter ; + mHandleEntryMap.erase(entry->mHandle); + mHeaderEntryQueue.erase(iter) ; + removeFromCache(entry) ; + delete entry; + } + mNumEntries = mHandleEntryMap.size() ; +} + +void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) +{ + if(!mEnabled) + { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently disabled." << llendl; + return ; + } + llassert_always(mInitialized); + + if(mReadOnly) + { + llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl; + return ; + } + + HeaderEntryInfo* entry; + handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ; + if(iter == mHandleEntryMap.end()) //new entry + { + if(mNumEntries >= mCacheSize - 1) + { + purgeEntries(mCacheSize - 1) ; + } + + entry = new HeaderEntryInfo(); + entry->mHandle = handle ; + entry->mTime = time(NULL) ; + entry->mIndex = mNumEntries++; + mHeaderEntryQueue.insert(entry) ; + mHandleEntryMap[handle] = entry ; + } + else + { + // Update access time. + entry = iter->second ; + + //resort + mHeaderEntryQueue.erase(entry) ; + + entry->mTime = time(NULL) ; + mHeaderEntryQueue.insert(entry) ; + } + + //update cache header + if(!updateEntry(entry)) + { + llwarns << "Failed to update cache header index " << entry->mIndex << ". handle = " << handle << llendl; + return ; //update failed. + } + + if(!dirty_cache) + { + llwarns << "Skipping write to cache for handle " << handle << ": cache not dirty" << llendl; + return ; //nothing changed, no need to update. + } + + //write to cache file + bool success = true ; + { + std::string filename; + getObjectCacheFilename(handle, filename); + LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, LLAPRFile::local); + + success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ; + + + if(success) + { + S32 num_entries = cache_entry_map.size() ; + success = check_write(&apr_file, &num_entries, sizeof(S32)); + + for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter) + { + success = iter->second->writeToFile(&apr_file) ; + } + } + } + + if(!success) + { + removeEntry(entry) ; + + } + + return ; +} + diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index 1970a1e72..6f2fd4571 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -36,17 +36,18 @@ #include "lluuid.h" #include "lldatapacker.h" #include "lldlinked.h" +#include "lldir.h" //--------------------------------------------------------------------------- // Cache entries class LLVOCacheEntry; -class LLVOCacheEntry : public LLDLinked +class LLVOCacheEntry { public: LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp); - LLVOCacheEntry(LLFILE *fp); + LLVOCacheEntry(LLAPRFile* apr_file); LLVOCacheEntry(); ~LLVOCacheEntry(); @@ -56,12 +57,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 vocache_entry_map_t; + protected: U32 mLocalID; U32 mCRC; @@ -72,4 +76,86 @@ 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 + { + if(lhs->mTime == rhs->mTime) + { + return lhs < rhs ; + } + + return lhs->mTime < rhs->mTime ; // older entry in front of queue (set) + } + }; + typedef std::set header_entry_queue_t; + typedef std::map 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 removeEntry(U64 handle) ; + + 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(HeaderEntryInfo* entry); + void readCacheHeader(); + void writeCacheHeader(); + void clearCacheInMemory(); + void removeCache() ; + void removeEntry(HeaderEntryInfo* entry) ; + void purgeEntries(U32 size); + BOOL updateEntry(const HeaderEntryInfo* entry); + +private: + BOOL mEnabled; + BOOL mInitialized ; + BOOL mReadOnly ; + HeaderMetaInfo mMetaInfo; + U32 mCacheSize; + U32 mNumEntries; + std::string mHeaderFileName ; + std::string mObjectCacheDirName; + 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/llvovolume.cpp b/indra/newview/llvovolume.cpp index a7c797f51..00d37f823 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -63,6 +63,8 @@ #include "llworld.h" #include "llselectmgr.h" #include "pipeline.h" +#include "llvocache.h" + // [RLVa:KB] - Checked: 2010-04-04 (RLVa-1.2.0d) #include "rlvhandler.h" // [/RLVa:KB] @@ -235,10 +237,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys, // Well, crap, there's something bogus in the data that we're unpacking. dp->dumpBufferToLog(); llwarns << "Flushing cache files" << llendl; - std::string mask; - mask = gDirUtilp->getDirDelimiter() + "*.slc"; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask); -// llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl; + + if(LLVOCache::hasInstance() && getRegion()) + { + LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ; + } + llwarns << "Bogus TE data in " << getID() << llendl; } else if (res2 & (TEM_CHANGE_TEXTURE|TEM_CHANGE_COLOR)) diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 0c445b65f..fbceaa9cc 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -54,6 +54,7 @@ #include "llviewerstats.h" #include "llvlcomposition.h" #include "llvoavatar.h" +#include "llvocache.h" #include "llvowater.h" #include "message.h" #include "pipeline.h" @@ -129,6 +130,10 @@ void LLWorld::destroyClass() LLViewerRegion* region_to_delete = *region_it++; removeRegion(region_to_delete->getHost()); } + if(LLVOCache::hasInstance()) + { + LLVOCache::getInstance()->destroyClass() ; + } LLViewerPartSim::getInstance()->destroyClass(); } @@ -265,6 +270,7 @@ void LLWorld::removeRegion(const LLHost &host) llwarns << "Disabling region " << regionp->getName() << " that agent is in!" << llendl; LLAppViewer::instance()->forceDisconnect("You have been disconnected from the region you were in."); + regionp->saveObjectCache() ; //force to save objects here in case that the object cache is about to be destroyed. return; } @@ -279,6 +285,10 @@ void LLWorld::removeRegion(const LLHost &host) delete regionp; updateWaterObjects(); + + //double check all objects of this region are removed. + gObjectList.clearAllMapObjectsInRegion(regionp) ; + //llassert_always(!gObjectList.hasMapObjectInRegion(regionp)) ; } @@ -1386,17 +1396,17 @@ void send_agent_resume() LLAppViewer::instance()->resumeMainloopTimeout(); } -static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin) -{ - LLVector3d pos_global(region_origin); - LLVector3d pos_local; - - pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4; - pos_local.mdV[VY] = (compact_local >> 8) & 0xFFU; - pos_local.mdV[VX] = (compact_local >> 16) & 0xFFU; - - pos_global += pos_local; - return pos_global; +static LLVector3d unpackLocalToGlobalPosition(U32 compact_local, const LLVector3d& region_origin) +{ + LLVector3d pos_global(region_origin); + LLVector3d pos_local; + + pos_local.mdV[VZ] = (compact_local & 0xFFU) * 4; + pos_local.mdV[VY] = (compact_local >> 8) & 0xFFU; + pos_local.mdV[VX] = (compact_local >> 16) & 0xFFU; + + pos_global += pos_local; + return pos_global; } void LLWorld::getAvatars(std::vector* avatar_ids, std::vector* positions, const LLVector3d& relative_to, F32 radius) const