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:
@@ -311,8 +311,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
|
||||
_timestampLastRequest(0.0),
|
||||
_priorityLastRequest(0.0f),
|
||||
_numOfRequests(0),
|
||||
_groupExpired(false),
|
||||
_insertLoadedSubgraphIntoObjectCache(false)
|
||||
_groupExpired(false)
|
||||
{}
|
||||
|
||||
void invalidate();
|
||||
@@ -324,26 +323,25 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl
|
||||
return _valid && (frameNumber - _frameNumberLastRequest <= 1);
|
||||
}
|
||||
|
||||
bool _valid;
|
||||
std::string _fileName;
|
||||
unsigned int _frameNumberFirstRequest;
|
||||
double _timestampFirstRequest;
|
||||
float _priorityFirstRequest;
|
||||
unsigned int _frameNumberLastRequest;
|
||||
double _timestampLastRequest;
|
||||
float _priorityLastRequest;
|
||||
unsigned int _numOfRequests;
|
||||
bool _valid;
|
||||
std::string _fileName;
|
||||
unsigned int _frameNumberFirstRequest;
|
||||
double _timestampFirstRequest;
|
||||
float _priorityFirstRequest;
|
||||
unsigned int _frameNumberLastRequest;
|
||||
double _timestampLastRequest;
|
||||
float _priorityLastRequest;
|
||||
unsigned int _numOfRequests;
|
||||
|
||||
osg::observer_ptr<osg::Node> _terrain;
|
||||
osg::observer_ptr<osg::Group> _group;
|
||||
|
||||
osg::ref_ptr<osg::Node> _loadedModel;
|
||||
osg::ref_ptr<Options> _loadOptions;
|
||||
osg::ref_ptr<ObjectCache> _objectCache;
|
||||
|
||||
osg::observer_ptr<osgUtil::IncrementalCompileOperation::CompileSet> _compileSet;
|
||||
bool _groupExpired; // flag used only in update thread
|
||||
|
||||
bool _insertLoadedSubgraphIntoObjectCache;
|
||||
bool _groupExpired; // flag used only in update thread
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -46,6 +46,9 @@ class OSGDB_EXPORT ObjectCache : public osg::Referenced
|
||||
/** Remove all objects in the cache regardless of having external references or expiry times.*/
|
||||
void clear();
|
||||
|
||||
/** Add contents of specified ObjectCache to this object cache.*/
|
||||
void addObjectCache(ObjectCache* object);
|
||||
|
||||
/** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/
|
||||
void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define OSGDB_OPTIONS 1
|
||||
|
||||
#include <osgDB/Callbacks>
|
||||
#include <osgDB/ObjectCache>
|
||||
#include <osg/ObserverNodePath>
|
||||
|
||||
#include <deque>
|
||||
@@ -138,6 +139,13 @@ class OSGDB_EXPORT Options : public osg::Object
|
||||
/** Get whether the Registry::ObjectCache should be used by default.*/
|
||||
CacheHintOptions getObjectCacheHint() const { return _objectCacheHint; }
|
||||
|
||||
/** Set the ObjectCache that is used to cache previously loaded data.*/
|
||||
void setObjectCache(ObjectCache* objectCache) { _objectCache = objectCache; }
|
||||
|
||||
/** Get the ObjectCache that is used to cache previously loaded data.*/
|
||||
ObjectCache* getObjectCache() const { return _objectCache.get(); }
|
||||
|
||||
|
||||
/** Set which geometry attributes plugins should import at double precision. */
|
||||
void setPrecisionHint(PrecisionHint hint) { _precisionHint = hint; }
|
||||
|
||||
@@ -248,7 +256,10 @@ class OSGDB_EXPORT Options : public osg::Object
|
||||
|
||||
std::string _str;
|
||||
FilePathList _databasePaths;
|
||||
|
||||
CacheHintOptions _objectCacheHint;
|
||||
osg::ref_ptr<ObjectCache> _objectCache;
|
||||
|
||||
PrecisionHint _precisionHint;
|
||||
BuildKdTreesHint _buildKdTreesHint;
|
||||
osg::ref_ptr<AuthenticationMap> _authenticationMap;
|
||||
|
||||
@@ -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