Refactored the handling of use of the osgDB::ObjectCache in the DatabasePager to use a local thread specific ObjectCache to handle new additions and
then have these additions merged with the main Registry ObjectCache during the main loop. git-svn-id: http://svn.openscenegraph.org/osg/OpenSceneGraph/trunk@14474 16af8721-9629-0410-8352-f15c8da7e697
This commit is contained in:
@@ -421,6 +421,7 @@ void DatabasePager::DatabaseRequest::invalidate()
|
||||
_valid = false;
|
||||
_loadedModel = 0;
|
||||
_compileSet = 0;
|
||||
_objectCache = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -772,15 +773,35 @@ void DatabasePager::DatabaseThread::run()
|
||||
frameNumberLastRequest = databaseRequest->_frameNumberLastRequest;
|
||||
}
|
||||
|
||||
|
||||
if (dr_loadOptions->getFileCache()) fileCache = dr_loadOptions->getFileCache();
|
||||
if (dr_loadOptions->getFileLocationCallback()) fileLocationCallback = dr_loadOptions->getFileLocationCallback();
|
||||
|
||||
// disable the FileCache if the fileLocationCallback tells us that it isn't required for this request.
|
||||
if (fileLocationCallback.valid() && !fileLocationCallback->useFileCache()) fileCache = 0;
|
||||
|
||||
|
||||
cacheNodes = (dr_loadOptions->getObjectCacheHint() & osgDB::Options::CACHE_NODES)!=0;
|
||||
if (cacheNodes)
|
||||
{
|
||||
//OSG_NOTICE<<"Checking main ObjectCache"<<std::endl;
|
||||
// check the object cache to see if the file we want has already been loaded.
|
||||
osg::ref_ptr<osg::Object> objectFromCache = osgDB::Registry::instance()->getRefFromObjectCache(fileName);
|
||||
|
||||
// if no object with fileName in ObjectCache then try the filename appropriate for fileCache
|
||||
if (!objectFromCache && (fileCache.valid() && fileCache->isFileAppropriateForFileCache(fileName)))
|
||||
{
|
||||
if (fileCache->existsInCache(fileName))
|
||||
{
|
||||
objectFromCache = osgDB::Registry::instance()->getRefFromObjectCache(fileCache->createCacheFileName(fileName));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
osg::Node* modelFromCache = dynamic_cast<osg::Node*>(objectFromCache.get());
|
||||
if (modelFromCache)
|
||||
{
|
||||
// OSG_NOTICE<<"Found object in cache "<<fileName<<std::endl;
|
||||
//OSG_NOTICE<<"Found object in cache "<<fileName<<std::endl;
|
||||
|
||||
// assign the cached model to the request
|
||||
{
|
||||
@@ -798,18 +819,19 @@ void DatabasePager::DatabaseThread::run()
|
||||
// skip the rest of the do/while loop as we have done all the processing we need to do.
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
//OSG_NOTICE<<"Not Found object in cache "<<fileName<<std::endl;
|
||||
}
|
||||
|
||||
// need to disable any attempt to use the cache when loading as we're handle this ourselves to avoid threading conflicts
|
||||
dr_loadOptions->setObjectCacheHint(static_cast<osgDB::Options::CacheHintOptions>(dr_loadOptions->getObjectCacheHint() & ~osgDB::Options::CACHE_NODES));
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> drLock(_pager->_dr_mutex);
|
||||
databaseRequest->_objectCache = new ObjectCache;
|
||||
dr_loadOptions->setObjectCache(databaseRequest->_objectCache.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (dr_loadOptions->getFileCache()) fileCache = dr_loadOptions->getFileCache();
|
||||
if (dr_loadOptions->getFileLocationCallback()) fileLocationCallback = dr_loadOptions->getFileLocationCallback();
|
||||
|
||||
|
||||
// disable the FileCache if the fileLocationCallback tells us that it isn't required for this request.
|
||||
if (fileLocationCallback.valid() && !fileLocationCallback->useFileCache()) fileCache = 0;
|
||||
|
||||
|
||||
// check if databaseRequest is still relevant
|
||||
if ((_pager->_frameNumber-frameNumberLastRequest)<=1)
|
||||
@@ -915,31 +937,40 @@ void DatabasePager::DatabaseThread::run()
|
||||
{
|
||||
loadedModel->getBound();
|
||||
|
||||
// find all the compileable rendering objects
|
||||
DatabasePager::FindCompileableGLObjectsVisitor stateToCompile(_pager, _pager->getMarkerObject());
|
||||
loadedModel->accept(stateToCompile);
|
||||
|
||||
bool loadedObjectsNeedToBeCompiled = _pager->_doPreCompile &&
|
||||
_pager->_incrementalCompileOperation.valid() &&
|
||||
_pager->_incrementalCompileOperation->requiresCompile(stateToCompile);
|
||||
|
||||
// move the databaseRequest from the front of the fileRequest to the end of
|
||||
// dataToCompile or dataToMerge lists.
|
||||
bool loadedObjectsNeedToBeCompiled = false;
|
||||
osg::ref_ptr<osgUtil::IncrementalCompileOperation::CompileSet> compileSet = 0;
|
||||
if (loadedObjectsNeedToBeCompiled)
|
||||
if (!rr.loadedFromCache())
|
||||
{
|
||||
// OSG_NOTICE<<"Using IncrementalCompileOperation"<<std::endl;
|
||||
// find all the compileable rendering objects
|
||||
DatabasePager::FindCompileableGLObjectsVisitor stateToCompile(_pager, _pager->getMarkerObject());
|
||||
loadedModel->accept(stateToCompile);
|
||||
|
||||
compileSet = new osgUtil::IncrementalCompileOperation::CompileSet(loadedModel.get());
|
||||
compileSet->buildCompileMap(_pager->_incrementalCompileOperation->getContextSet(), stateToCompile);
|
||||
compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(_pager, databaseRequest.get());
|
||||
_pager->_incrementalCompileOperation->add(compileSet.get(), false);
|
||||
loadedObjectsNeedToBeCompiled = _pager->_doPreCompile &&
|
||||
_pager->_incrementalCompileOperation.valid() &&
|
||||
_pager->_incrementalCompileOperation->requiresCompile(stateToCompile);
|
||||
|
||||
// move the databaseRequest from the front of the fileRequest to the end of
|
||||
// dataToCompile or dataToMerge lists.
|
||||
if (loadedObjectsNeedToBeCompiled)
|
||||
{
|
||||
// OSG_NOTICE<<"Using IncrementalCompileOperation"<<std::endl;
|
||||
|
||||
compileSet = new osgUtil::IncrementalCompileOperation::CompileSet(loadedModel.get());
|
||||
compileSet->buildCompileMap(_pager->_incrementalCompileOperation->getContextSet(), stateToCompile);
|
||||
compileSet->_compileCompletedCallback = new DatabasePagerCompileCompletedCallback(_pager, databaseRequest.get());
|
||||
_pager->_incrementalCompileOperation->add(compileSet.get(), false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OSG_NOTICE<<"Loaded from ObjectCache"<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> drLock(_pager->_dr_mutex);
|
||||
databaseRequest->_loadedModel = loadedModel;
|
||||
databaseRequest->_compileSet = compileSet;
|
||||
databaseRequest->_insertLoadedSubgraphIntoObjectCache = cacheNodes;
|
||||
}
|
||||
// Dereference the databaseRequest while the queue is
|
||||
// locked. This prevents the request from being
|
||||
@@ -1451,7 +1482,7 @@ void DatabasePager::requestNodeFile(const std::string& fileName, osg::NodePath&
|
||||
databaseRequest->_group = group;
|
||||
databaseRequest->_terrain = terrain;
|
||||
databaseRequest->_loadOptions = loadOptions;
|
||||
databaseRequest->_insertLoadedSubgraphIntoObjectCache = false;
|
||||
databaseRequest->_objectCache = 0;
|
||||
requeue = true;
|
||||
}
|
||||
|
||||
@@ -1484,7 +1515,7 @@ void DatabasePager::requestNodeFile(const std::string& fileName, osg::NodePath&
|
||||
databaseRequest->_group = group;
|
||||
databaseRequest->_terrain = terrain;
|
||||
databaseRequest->_loadOptions = loadOptions;
|
||||
databaseRequest->_insertLoadedSubgraphIntoObjectCache = false;
|
||||
databaseRequest->_objectCache = 0;
|
||||
|
||||
_fileRequestQueue->addNoLock(databaseRequest.get());
|
||||
}
|
||||
@@ -1663,11 +1694,10 @@ void DatabasePager::addLoadedDataToSceneGraph(const osg::FrameStamp &frameStamp)
|
||||
registerPagedLODs(databaseRequest->_loadedModel.get(), frameNumber);
|
||||
}
|
||||
|
||||
if (databaseRequest->_insertLoadedSubgraphIntoObjectCache)
|
||||
if (databaseRequest->_objectCache.valid() && osgDB::Registry::instance()->getObjectCache())
|
||||
{
|
||||
// insert loaded model into Registry ObjectCache
|
||||
// OSG_NOTICE<<"Inserting loaded Model ("<<databaseRequest->_fileName<<") into ObjectCache"<<std::endl;
|
||||
osgDB::Registry::instance()->addEntryToObjectCache( databaseRequest->_fileName, databaseRequest->_loadedModel.get(), timeStamp);
|
||||
osgDB::Registry::instance()->getObjectCache()->addObjectCache( databaseRequest->_objectCache.get());
|
||||
}
|
||||
|
||||
// OSG_NOTICE<<"merged subgraph"<<databaseRequest->_fileName<<" after "<<databaseRequest->_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<<std::endl;
|
||||
|
||||
@@ -22,14 +22,27 @@ using namespace osgDB;
|
||||
ObjectCache::ObjectCache():
|
||||
osg::Referenced(true)
|
||||
{
|
||||
OSG_NOTICE<<"Constructed ObjectCach"<<std::endl;
|
||||
// OSG_NOTICE<<"Constructed ObjectCach"<<std::endl;
|
||||
}
|
||||
|
||||
ObjectCache::~ObjectCache()
|
||||
{
|
||||
OSG_NOTICE<<"Destructed ObjectCach"<<std::endl;
|
||||
// OSG_NOTICE<<"Destructed ObjectCach"<<std::endl;
|
||||
}
|
||||
|
||||
void ObjectCache::addObjectCache(ObjectCache* objectCache)
|
||||
{
|
||||
// don't allow a cache to be added to itself.
|
||||
if (objectCache==this) return;
|
||||
|
||||
// lock both ObjectCache to prevent their contents from being modified by other threads while we merge.
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock1(_objectCacheMutex);
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock2(objectCache->_objectCacheMutex);
|
||||
|
||||
// OSG_NOTICE<<"Inserting objects to main ObjectCache "<<objectCache->_objectCache.size()<<std::endl;
|
||||
|
||||
_objectCache.insert(objectCache->_objectCache.begin(), objectCache->_objectCache.end());
|
||||
}
|
||||
|
||||
|
||||
void ObjectCache::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp)
|
||||
@@ -50,7 +63,11 @@ osg::ref_ptr<osg::Object> ObjectCache::getRefFromObjectCache(const std::string&
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_objectCacheMutex);
|
||||
ObjectCacheMap::iterator itr = _objectCache.find(fileName);
|
||||
if (itr!=_objectCache.end()) return itr->second.first;
|
||||
if (itr!=_objectCache.end())
|
||||
{
|
||||
// OSG_NOTICE<<"Found "<<fileName<<" in ObjectCache "<<this<<std::endl;
|
||||
return itr->second.first;
|
||||
}
|
||||
else return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ Options::Options(const Options& options,const osg::CopyOp& copyop):
|
||||
_str(options._str),
|
||||
_databasePaths(options._databasePaths),
|
||||
_objectCacheHint(options._objectCacheHint),
|
||||
_objectCache(options._objectCache),
|
||||
_precisionHint(options._precisionHint),
|
||||
_buildKdTreesHint(options._buildKdTreesHint),
|
||||
_pluginData(options._pluginData),
|
||||
|
||||
@@ -1245,43 +1245,46 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun
|
||||
{
|
||||
std::string file(readFunctor._filename);
|
||||
|
||||
bool useObjectCache=false;
|
||||
bool useObjectCache = false;
|
||||
const Options* options = readFunctor._options;
|
||||
ObjectCache* optionsCache = options ? options->getObjectCache() : 0;
|
||||
|
||||
//Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here
|
||||
if (_objectCache.valid() && cacheHint!=Options::CACHE_ARCHIVES)
|
||||
if ((optionsCache || _objectCache.valid()) && cacheHint!=Options::CACHE_ARCHIVES)
|
||||
{
|
||||
const Options* options=readFunctor._options;
|
||||
useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
|
||||
useObjectCache= options ? (options->getObjectCacheHint()&cacheHint)!=0: false;
|
||||
}
|
||||
|
||||
if (useObjectCache)
|
||||
{
|
||||
// search for entry in the object cache.
|
||||
osg::ref_ptr<osg::Object> object = optionsCache ? optionsCache->getRefFromObjectCache(file) : 0;
|
||||
|
||||
if (!object && _objectCache.valid()) object = _objectCache->getRefFromObjectCache(file);
|
||||
|
||||
if (object.valid())
|
||||
{
|
||||
osg::ref_ptr<osg::Object> object = _objectCache->getRefFromObjectCache(file);
|
||||
if (object.valid())
|
||||
{
|
||||
OSG_INFO<<"returning cached instanced of "<<file<<std::endl;
|
||||
if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
|
||||
else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
|
||||
}
|
||||
if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
|
||||
else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
|
||||
}
|
||||
|
||||
ReaderWriter::ReadResult rr = read(readFunctor);
|
||||
if (rr.validObject())
|
||||
{
|
||||
// search AGAIN for entry in the object cache.
|
||||
osg::ref_ptr<osg::Object> object = _objectCache->getRefFromObjectCache(file);
|
||||
object = _objectCache->getRefFromObjectCache(file);
|
||||
if (object.valid())
|
||||
{
|
||||
OSG_INFO << "returning cached instanced of " << file << std::endl;
|
||||
if (readFunctor.isValid(object.get())) return ReaderWriter::ReadResult(object.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE);
|
||||
else return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
|
||||
else
|
||||
{
|
||||
return ReaderWriter::ReadResult("Error file does not contain an osg::Object");
|
||||
}
|
||||
}
|
||||
|
||||
// update cache with new entry.
|
||||
OSG_INFO<<"Adding to object cache "<<file<<std::endl;
|
||||
_objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0);
|
||||
if (optionsCache) optionsCache->addEntryToObjectCache(file, rr.getObject(), 0.0);
|
||||
else if (_objectCache.valid()) _objectCache->addEntryToObjectCache(file, rr.getObject(), 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user