diff --git a/include/osgDB/ObjectCache b/include/osgDB/ObjectCache new file mode 100644 index 000000000..a27aec17f --- /dev/null +++ b/include/osgDB/ObjectCache @@ -0,0 +1,78 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * 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 + * OpenSceneGraph Public License for more details. +*/ + +#ifndef OSGDB_OBJECTCACHE +#define OSGDB_OBJECTCACHE 1 + +#include + +#include +#include + +#include + +namespace osgDB { + +class OSGDB_EXPORT ObjectCache : public osg::Referenced +{ + public: + + ObjectCache(); + + /** For each object in the cache which has an reference count greater than 1 + * (and therefore referenced by elsewhere in the application) set the time stamp + * for that object in the cache to specified time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required. + * The time used should be taken from the FrameStamp::getReferenceTime().*/ + void updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime); + + /** Removed object in the cache which have a time stamp at or before the specified expiry time. + * This would typically be called once per frame by applications which are doing database paging, + * and need to prune objects that are no longer required, and called after the a called + * after the call to updateTimeStampOfObjectsInCacheWithExternalReferences(expirtyTime).*/ + void removeExpiredObjectsInCache(double expiryTime); + + /** Remove all objects in the cache regardless of having external references or expiry times.*/ + void clear(); + + /** Add a filename,object,timestamp triple to the Registry::ObjectCache.*/ + void addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp = 0.0); + + /** Remove Object from cache.*/ + void removeFromObjectCache(const std::string& fileName); + + /** Get an Object from the object cache*/ + osg::Object* getFromObjectCache(const std::string& fileName); + + /** Get an ref_ptr from the object cache*/ + osg::ref_ptr getRefFromObjectCache(const std::string& fileName); + + /** call rleaseGLObjects on all objects attached to the object cache.*/ + void releaseGLObjects(osg::State* state); + + protected: + + virtual ~ObjectCache(); + + typedef std::pair, double > ObjectTimeStampPair; + typedef std::map ObjectCacheMap; + + ObjectCacheMap _objectCache; + OpenThreads::Mutex _objectCacheMutex; + +}; + +} + +#endif diff --git a/include/osgDB/Registry b/include/osgDB/Registry index dbc95cf5f..4b2cd7f44 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -417,6 +418,22 @@ class OSGDB_EXPORT Registry : public osg::Referenced /** get the const library file path which is used when search for library (dso/dll's) files.*/ const FilePathList& getLibraryFilePathList() const { return _libraryFilePath; } + + + /** Set the ObjectCache that is used to manage local storage of files downloaded from the internet.*/ + void setObjectCache(ObjectCache* objectCache) { _objectCache = objectCache; } + + /** Get the ObjectCache that is used to manage local storage of files downloaded from the internet.*/ + ObjectCache* getObjectCache() { return _objectCache.get(); } + + /** Get the const ObjectCache that is used to manage local storage of files downloaded from the internet.*/ + const ObjectCache* getObjectCache() const { return _objectCache.get(); } + + /** set hint to viewer code calling removeExpiredObjectsInCache to specify how long it should give before expiring objects in Registry cache,*/ + void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; } + + double getExpiryDelay() const { return _expiryDelay; } + /** For each object in the cache which has an reference count greater than 1 * (and therefore referenced by elsewhere in the application) set the time stamp * for that object in the cache to specified time. @@ -431,12 +448,6 @@ class OSGDB_EXPORT Registry : public osg::Referenced * after the call to updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp).*/ void removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp); - /** set hint to viewer code calling removeExpiredObjectsInCache to specify how long it should give before expiring objects in Registry cache,*/ - void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; } - - double getExpiryDelay() const { return _expiryDelay; } - - /** Remove all objects in the cache regardless of having external references or expiry times.*/ void clearObjectCache(); @@ -511,8 +522,6 @@ class OSGDB_EXPORT Registry : public osg::Referenced typedef std::vector< osg::ref_ptr > DynamicLibraryList; typedef std::map< std::string, std::string> ExtensionAliasMap; - typedef std::pair, double > ObjectTimeStampPair; - typedef std::map ObjectCache; typedef std::map > ArchiveCache; typedef std::set RegisteredProtocolsSet; @@ -619,9 +628,9 @@ class OSGDB_EXPORT Registry : public osg::Referenced FilePathList _dataFilePath; FilePathList _libraryFilePath; + osg::ref_ptr _objectCache; + double _expiryDelay; - ObjectCache _objectCache; - OpenThreads::Mutex _objectCacheMutex; ArchiveExtensionList _archiveExtList; diff --git a/src/osgDB/CMakeLists.txt b/src/osgDB/CMakeLists.txt index 00f17c945..018a74ba4 100644 --- a/src/osgDB/CMakeLists.txt +++ b/src/osgDB/CMakeLists.txt @@ -68,6 +68,7 @@ SET(TARGET_H ${HEADER_PATH}/ImagePager ${HEADER_PATH}/ImageProcessor ${HEADER_PATH}/Input + ${HEADER_PATH}/ObjectCache ${HEADER_PATH}/Output ${HEADER_PATH}/Options ${HEADER_PATH}/ParameterOutput @@ -107,6 +108,7 @@ SET(TARGET_SRC ImagePager.cpp Input.cpp MimeTypes.cpp + ObjectCache.cpp Output.cpp Options.cpp PluginQuery.cpp diff --git a/src/osgDB/ObjectCache.cpp b/src/osgDB/ObjectCache.cpp new file mode 100644 index 000000000..c19a20d4d --- /dev/null +++ b/src/osgDB/ObjectCache.cpp @@ -0,0 +1,118 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield + * + * This library is open source and may be redistributed and/or modified under + * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or + * (at your option) any later version. The full license is in LICENSE file + * included with this distribution, and on the openscenegraph.org website. + * + * 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 + * OpenSceneGraph Public License for more details. +*/ + +#include + +using namespace osgDB; + +//////////////////////////////////////////////////////////////////////////////////////////// +// +// ObjectCache +// +ObjectCache::ObjectCache(): + osg::Referenced(true) +{ + OSG_NOTICE<<"Constructed ObjectCach"< lock(_objectCacheMutex); + _objectCache[filename]=ObjectTimeStampPair(object,timestamp); +} + +osg::Object* ObjectCache::getFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) return itr->second.first.get(); + else return 0; +} + +osg::ref_ptr ObjectCache::getRefFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) return itr->second.first; + else return 0; +} + +void ObjectCache::updateTimeStampOfObjectsInCacheWithExternalReferences(double referenceTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // look for objects with external references and update their time stamp. + for(ObjectCacheMap::iterator itr=_objectCache.begin(); + itr!=_objectCache.end(); + ++itr) + { + // if ref count is greater the 1 the object has an external reference. + if (itr->second.first->referenceCount()>1) + { + // so update it time stamp. + itr->second.second = referenceTime; + } + } +} + +void ObjectCache::removeExpiredObjectsInCache(double expiryTime) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + // Remove expired entries from object cache + ObjectCacheMap::iterator oitr = _objectCache.begin(); + while(oitr != _objectCache.end()) + { + if (oitr->second.second<=expiryTime) + { + _objectCache.erase(oitr++); + } + else + { + ++oitr; + } + } +} + +void ObjectCache::removeFromObjectCache(const std::string& fileName) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + ObjectCacheMap::iterator itr = _objectCache.find(fileName); + if (itr!=_objectCache.end()) _objectCache.erase(itr); +} + +void ObjectCache::clear() +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + _objectCache.clear(); +} + +void ObjectCache::releaseGLObjects(osg::State* state) +{ + OpenThreads::ScopedLock lock(_objectCacheMutex); + + for(ObjectCacheMap::iterator itr = _objectCache.begin(); + itr != _objectCache.end(); + ++itr) + { + osg::Object* object = itr->second.first.get(); + object->releaseGLObjects(state); + } +} diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index 6e9858c09..45545da31 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -247,6 +247,9 @@ Registry::Registry() _fileCache = new FileCache(fileCachePath); } + // assign ObjectCache. + _objectCache = new ObjectCache; + _createNodeFromImage = false; _openingLibrary = false; @@ -485,6 +488,8 @@ void Registry::destruct() // even some issue with objects be allocated by a plugin that is // maintained after that plugin is deleted... Robert Osfield, Jan 2004. clearObjectCache(); + _fileCache = 0; + clearArchiveCache(); @@ -1241,8 +1246,9 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun std::string file(readFunctor._filename); bool useObjectCache=false; + //Note CACHE_ARCHIVES has a different object that it caches to so it will never be used here - if (cacheHint!=Options::CACHE_ARCHIVES) + if (_objectCache.valid() && cacheHint!=Options::CACHE_ARCHIVES) { const Options* options=readFunctor._options; useObjectCache=options ? (options->getObjectCacheHint()&cacheHint)!=0: false; @@ -1252,12 +1258,11 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun { // search for entry in the object cache. { - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCache::iterator oitr=_objectCache.find(file); - if (oitr!=_objectCache.end()) + osg::ref_ptr object = _objectCache->getRefFromObjectCache(file); + if (object.valid()) { OSG_INFO<<"returning cached instanced of "<second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); + 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"); } } @@ -1266,20 +1271,17 @@ ReaderWriter::ReadResult Registry::readImplementation(const ReadFunctor& readFun if (rr.validObject()) { // search AGAIN for entry in the object cache. + osg::ref_ptr object = _objectCache->getRefFromObjectCache(file); + if (object.valid()) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCache::iterator oitr = _objectCache.find(file); - if (oitr != _objectCache.end()) - { - OSG_INFO << "returning cached instanced of " << file << std::endl; - if (readFunctor.isValid(oitr->second.first.get())) return ReaderWriter::ReadResult(oitr->second.first.get(), ReaderWriter::ReadResult::FILE_LOADED_FROM_CACHE); - else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); - } - // update cache with new entry. - OSG_INFO<<"Adding to object cache "<addEntryToObjectCache(file, rr.getObject(), 0.0); } else { @@ -1661,76 +1663,38 @@ ReaderWriter::WriteResult Registry::writeScriptImplementation(const Script& imag void Registry::addEntryToObjectCache(const std::string& filename, osg::Object* object, double timestamp) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - _objectCache[filename]=ObjectTimeStampPair(object,timestamp); + if (_objectCache.valid()) _objectCache->addEntryToObjectCache(filename, object, timestamp); } -osg::Object* Registry::getFromObjectCache(const std::string& fileName) +osg::Object* Registry::getFromObjectCache(const std::string& filename) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCache::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) return itr->second.first.get(); - else return 0; + return _objectCache.valid() ? _objectCache->getFromObjectCache(filename) : 0; } -osg::ref_ptr Registry::getRefFromObjectCache(const std::string& fileName) +osg::ref_ptr Registry::getRefFromObjectCache(const std::string& filename) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCache::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) return itr->second.first; - else return 0; + return _objectCache.valid() ? _objectCache->getRefFromObjectCache(filename) : 0; } void Registry::updateTimeStampOfObjectsInCacheWithExternalReferences(const osg::FrameStamp& frameStamp) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - - // look for objects with external references and update their time stamp. - for(ObjectCache::iterator itr=_objectCache.begin(); - itr!=_objectCache.end(); - ++itr) - { - // if ref count is greater the 1 the object has an external reference. - if (itr->second.first->referenceCount()>1) - { - // so update it time stamp. - itr->second.second = frameStamp.getReferenceTime(); - } - } + if (_objectCache.valid()) _objectCache->updateTimeStampOfObjectsInCacheWithExternalReferences(frameStamp.getReferenceTime()); } void Registry::removeExpiredObjectsInCache(const osg::FrameStamp& frameStamp) { double expiryTime = frameStamp.getReferenceTime() - _expiryDelay; - - OpenThreads::ScopedLock lock(_objectCacheMutex); - - // Remove expired entries from object cache - ObjectCache::iterator oitr = _objectCache.begin(); - while(oitr != _objectCache.end()) - { - if (oitr->second.second<=expiryTime) - { - _objectCache.erase(oitr++); - } - else - { - ++oitr; - } - } + if (_objectCache.valid()) _objectCache->removeExpiredObjectsInCache(expiryTime); } -void Registry::removeFromObjectCache(const std::string& fileName) +void Registry::removeFromObjectCache(const std::string& filename) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - ObjectCache::iterator itr = _objectCache.find(fileName); - if (itr!=_objectCache.end()) _objectCache.erase(itr); + if (_objectCache.valid()) _objectCache->removeFromObjectCache(filename); } void Registry::clearObjectCache() { - OpenThreads::ScopedLock lock(_objectCacheMutex); - _objectCache.clear(); + if (_objectCache.valid()) _objectCache->clear(); } void Registry::addToArchiveCache(const std::string& fileName, osgDB::Archive* archive) @@ -1774,20 +1738,8 @@ void Registry::clearArchiveCache() void Registry::releaseGLObjects(osg::State* state) { - OpenThreads::ScopedLock lock(_objectCacheMutex); - - for(ObjectCache::iterator itr = _objectCache.begin(); - itr != _objectCache.end(); - ++itr) - { - osg::Object* object = itr->second.first.get(); - object->releaseGLObjects(state); - } - - if (_sharedStateManager.valid()) - { - _sharedStateManager->releaseGLObjects( state ); - } + if (_objectCache.valid()) _objectCache->releaseGLObjects( state ); + if (_sharedStateManager.valid()) _sharedStateManager->releaseGLObjects( state ); } SharedStateManager* Registry::getOrCreateSharedStateManager()