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:
Robert Osfield
2014-11-13 09:40:11 +00:00
parent ed28ec97c7
commit 25cfb81a09
7 changed files with 127 additions and 64 deletions

View File

@@ -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
};

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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),

View File

@@ -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
{