From 96b72af169432a0e30f3b730fa8c51c4ceab55ad Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 17 Mar 2003 22:53:46 +0000 Subject: [PATCH] Implemented a object cache in osgDB::Registry. --- include/osgDB/ReadFile | 10 +- include/osgDB/Registry | 43 ++++++-- src/osgDB/ReadFile.cpp | 20 ++-- src/osgDB/Registry.cpp | 233 ++++++++++++++++++++++++++++++++++++----- src/osgText/Font.cpp | 2 +- 5 files changed, 258 insertions(+), 50 deletions(-) diff --git a/include/osgDB/ReadFile b/include/osgDB/ReadFile index dece8399f..42600b11c 100644 --- a/include/osgDB/ReadFile +++ b/include/osgDB/ReadFile @@ -30,7 +30,7 @@ namespace osgDB { * The osgDB::Registry is used to load the appropriate ReaderWriter plugin * for the filename extension, and this plugin then handles the request * to read the specified file.*/ -extern OSGDB_EXPORT osg::Object* readObjectFile(const std::string& filename); +extern OSGDB_EXPORT osg::Object* readObjectFile(const std::string& filename,bool useObjectCache=false); /** Read an osg::Image from file. * Return valid osg::Image on success, @@ -38,7 +38,7 @@ extern OSGDB_EXPORT osg::Object* readObjectFile(const std::string& filename); * The osgDB::Registry is used to load the appropriate ReaderWriter plugin * for the filename extension, and this plugin then handles the request * to read the specified file.*/ -extern OSGDB_EXPORT osg::Image* readImageFile(const std::string& filename); +extern OSGDB_EXPORT osg::Image* readImageFile(const std::string& filename,bool useObjectCache=false); /** Read an osg::Node from file. * Return valid osg::Node on success, @@ -46,15 +46,15 @@ extern OSGDB_EXPORT osg::Image* readImageFile(const std::string& filename); * The osgDB::Registry is used to load the appropriate ReaderWriter plugin * for the filename extension, and this plugin then handles the request * to read the specified file.*/ -extern OSGDB_EXPORT osg::Node* readNodeFile(const std::string& filename); +extern OSGDB_EXPORT osg::Node* readNodeFile(const std::string& filename,bool useObjectCache=false); /** Read an osg::Node subgraph from files, creating a osg::Group to contain the nodes if more * than one subgraph has been loaded.*/ -extern OSGDB_EXPORT osg::Node* readNodeFiles(std::vector& commandLine); +extern OSGDB_EXPORT osg::Node* readNodeFiles(std::vector& commandLine,bool useObjectCache=false); /** Read an osg::Node subgraph from files, creating a osg::Group to contain the nodes if more * than one subgraph has been loaded.*/ -extern OSGDB_EXPORT osg::Node* readNodeFiles(osg::ArgumentParser& parser); +extern OSGDB_EXPORT osg::Node* readNodeFiles(osg::ArgumentParser& parser,bool useObjectCache=false); } diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 9dbc68a32..82f37c092 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -92,13 +92,13 @@ class OSGDB_EXPORT Registry : public osg::Referenced bool writeObject(const osg::Object& obj,Output& fw); - ReaderWriter::ReadResult readObject(const std::string& fileName); + ReaderWriter::ReadResult readObject(const std::string& fileName,bool useObjectCache); ReaderWriter::WriteResult writeObject(const osg::Object& obj, const std::string& fileName); - ReaderWriter::ReadResult readImage(const std::string& fileName); + ReaderWriter::ReadResult readImage(const std::string& fileName,bool useObjectCache); ReaderWriter::WriteResult writeImage(const osg::Image& obj, const std::string& fileName); - ReaderWriter::ReadResult readNode(const std::string& fileName); + ReaderWriter::ReadResult readNode(const std::string& fileName,bool useObjectCache); ReaderWriter::WriteResult writeNode(const osg::Node& node, const std::string& fileName); void setCreateNodeFromImage(bool flag) { _createNodeFromImage = flag; } @@ -149,14 +149,38 @@ class OSGDB_EXPORT Registry : public osg::Referenced static void convertStringPathIntoFilePathList(const std::string& paths,FilePathList& filepath); + /** 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. + * Time value is time in sceonds.*/ + void updateTimeStampOfObjectsInCacheWithExtenalReferences(double currentTime); + + /** 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 updateTimeStampOfObjectsInCacheWithExtenalReferences(currentTime). + * Note, the currentTime is not the expiryTime, one would typically set the expiry time + * to a fixed amount of time before currentTime, such as expiryTime = currentTime-10.0. + * Time value is time in sceonds.*/ + void removeExpiredObjectsInCache(double expiryTime); + + /** Remove all objects in the cache regardless of having external references or expiry times.*/ + void clearObjectCache(); + + protected: virtual ~Registry(); - typedef std::map > DotOsgWrapperMap; - typedef std::vector > ReaderWriterList; - typedef std::vector > DynamicLibraryList; - typedef std::map ExtensionAliasMap; + typedef std::map< std::string, osg::ref_ptr > DotOsgWrapperMap; + typedef std::vector< osg::ref_ptr > ReaderWriterList; + typedef std::vector< osg::ref_ptr > DynamicLibraryList; + typedef std::map< std::string, std::string> ExtensionAliasMap; + + typedef std::pair, double > ObjectTimeStampPair; + typedef std::map ObjectCache; /** constructor is private, as its a singleton, preventing construction other than via the instance() method and @@ -173,6 +197,9 @@ class OSGDB_EXPORT Registry : public osg::Referenced void eraseWrapper(DotOsgWrapperMap& wrappermap,DotOsgWrapper* wrapper); + ReaderWriter::ReadResult readObject(const std::string& fileName); + ReaderWriter::ReadResult readImage(const std::string& fileName); + ReaderWriter::ReadResult readNode(const std::string& fileName); DotOsgWrapperMap _objectWrapperMap; DotOsgWrapperMap _imageWrapperMap; @@ -195,6 +222,8 @@ class OSGDB_EXPORT Registry : public osg::Referenced FilePathList _dataFilePath; FilePathList _libraryFilePath; + + ObjectCache _objectCache; }; diff --git a/src/osgDB/ReadFile.cpp b/src/osgDB/ReadFile.cpp index a97924691..6bad0311d 100644 --- a/src/osgDB/ReadFile.cpp +++ b/src/osgDB/ReadFile.cpp @@ -22,33 +22,33 @@ using namespace osg; using namespace osgDB; -Object* osgDB::readObjectFile(const std::string& filename) +Object* osgDB::readObjectFile(const std::string& filename,bool useObjectCache) { - ReaderWriter::ReadResult rr = Registry::instance()->readObject(filename); + ReaderWriter::ReadResult rr = Registry::instance()->readObject(filename,useObjectCache); if (rr.validObject()) return rr.takeObject(); if (rr.error()) notify(WARN) << rr.message() << std::endl; return NULL; } -Image* osgDB::readImageFile(const std::string& filename) +Image* osgDB::readImageFile(const std::string& filename,bool useObjectCache) { - ReaderWriter::ReadResult rr = Registry::instance()->readImage(filename); + ReaderWriter::ReadResult rr = Registry::instance()->readImage(filename,useObjectCache); if (rr.validImage()) return rr.takeImage(); if (rr.error()) notify(WARN) << rr.message() << std::endl; return NULL; } -Node* osgDB::readNodeFile(const std::string& filename) +Node* osgDB::readNodeFile(const std::string& filename,bool useObjectCache) { - ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename); + ReaderWriter::ReadResult rr = Registry::instance()->readNode(filename,useObjectCache); if (rr.validNode()) return rr.takeNode(); if (rr.error()) notify(WARN) << rr.message() << std::endl; return NULL; } -Node* osgDB::readNodeFiles(std::vector& commandLine) +Node* osgDB::readNodeFiles(std::vector& commandLine,bool useObjectCache) { typedef std::vector NodeList; NodeList nodeList; @@ -62,7 +62,7 @@ Node* osgDB::readNodeFiles(std::vector& commandLine) if ((*itr)[0]!='-') { // not an option so assume string is a filename. - osg::Node *node = osgDB::readNodeFile( *itr ); + osg::Node *node = osgDB::readNodeFile( *itr ,useObjectCache ); if( node != (osg::Node *)0L ) { @@ -97,7 +97,7 @@ Node* osgDB::readNodeFiles(std::vector& commandLine) } -Node* osgDB::readNodeFiles(osg::ArgumentParser& arguments) +Node* osgDB::readNodeFiles(osg::ArgumentParser& arguments,bool useObjectCache) { typedef std::vector NodeList; @@ -110,7 +110,7 @@ Node* osgDB::readNodeFiles(osg::ArgumentParser& arguments) if (!arguments.isOption(pos)) { // not an option so assume string is a filename. - osg::Node *node = osgDB::readNodeFile( arguments[pos] ); + osg::Node *node = osgDB::readNodeFile( arguments[pos], useObjectCache); if(node) { diff --git a/src/osgDB/Registry.cpp b/src/osgDB/Registry.cpp index fb7171a5d..a601630c7 100644 --- a/src/osgDB/Registry.cpp +++ b/src/osgDB/Registry.cpp @@ -893,11 +893,6 @@ bool Registry::writeObject(const osg::Object& obj,Output& fw) // ReaderWriter::ReadResult Registry::readObject(const std::string& fileName) { - std::string file = findDataFile( fileName ); - if (file.empty()) return ReaderWriter::ReadResult("Warning: file \""+fileName+"\" not found."); - - PushAndPopDataPath tmpfile(getFilePath(fileName)); - // record the existing reader writer. std::set rwOriginal; @@ -910,8 +905,8 @@ ReaderWriter::ReadResult Registry::readObject(const std::string& fileName) itr!=_rwList.end(); ++itr) { - rwOriginal.insert(itr->get()); - ReaderWriter::ReadResult rr = (*itr)->readObject(file,_options.get()); + rwOriginal.insert(itr->get());; + ReaderWriter::ReadResult rr = (*itr)->readObject(fileName,_options.get()); if (rr.validObject()) return rr; else if (rr.error()) results.push_back(rr); } @@ -926,7 +921,7 @@ ReaderWriter::ReadResult Registry::readObject(const std::string& fileName) { if (rwOriginal.find(itr->get())==rwOriginal.end()) { - ReaderWriter::ReadResult rr = (*itr)->readObject(file,_options.get()); + ReaderWriter::ReadResult rr = (*itr)->readObject(fileName,_options.get()); if (rr.validObject()) return rr; else if (rr.error()) results.push_back(rr); } @@ -937,10 +932,57 @@ ReaderWriter::ReadResult Registry::readObject(const std::string& fileName) { return ReaderWriter::ReadResult("Warning: Could not find plugin to read objects from file \""+fileName+"\"."); } + return results.front(); } +ReaderWriter::ReadResult Registry::readObject(const std::string& fileName,bool useObjectCache) +{ + std::string file = findDataFile( fileName ); + if (file.empty()) return ReaderWriter::ReadResult("Warning: file \""+fileName+"\" not found."); + + if (useObjectCache) + { + // search for entry in the object cache. + ObjectCache::iterator oitr=_objectCache.find(file); + if (oitr!=_objectCache.end()) + { + notify(INFO)<<"returning cached instanced of "<second.first.get(); + if (object) return object; + else return ReaderWriter::ReadResult("Error file does not contain an osg::Object"); + } + + PushAndPopDataPath tmpfile(getFilePath(file)); + + ReaderWriter::ReadResult rr = readObject(file); + if (rr.validObject()) + { + // update cache with new entry. + notify(INFO)<<"Adding to cache object "< rwOriginal; @@ -1009,8 +1044,8 @@ ReaderWriter::ReadResult Registry::readImage(const std::string& fileName) ++itr) { rwOriginal.insert(itr->get()); - ReaderWriter::ReadResult rr = (*itr)->readImage(file,_options.get()); - if (rr.validImage()) return rr; + ReaderWriter::ReadResult rr = (*itr)->readImage(fileName,_options.get()); + if (rr.validImage()) return rr; else if (rr.error()) results.push_back(rr); } @@ -1024,7 +1059,7 @@ ReaderWriter::ReadResult Registry::readImage(const std::string& fileName) { if (rwOriginal.find(itr->get())==rwOriginal.end()) { - ReaderWriter::ReadResult rr = (*itr)->readImage(file,_options.get()); + ReaderWriter::ReadResult rr = (*itr)->readImage(fileName,_options.get()); if (rr.validImage()) return rr; else if (rr.error()) results.push_back(rr); } @@ -1040,6 +1075,55 @@ ReaderWriter::ReadResult Registry::readImage(const std::string& fileName) } +ReaderWriter::ReadResult Registry::readImage(const std::string& fileName,bool useObjectCache) +{ + std::string file = findDataFile( fileName ); + if (file.empty()) return ReaderWriter::ReadResult("Warning: file \""+fileName+"\" not found."); + + if (useObjectCache) + { + // search for entry in the object cache. + ObjectCache::iterator oitr=_objectCache.find(file); + if (oitr!=_objectCache.end()) + { + notify(INFO)<< "returning cached instanced of "<(oitr->second.first.get()); + if (image) return image; + else return ReaderWriter::ReadResult("Error file not of type osg::Image"); + } + + PushAndPopDataPath tmpfile(getFilePath(file)); + + ReaderWriter::ReadResult rr = readImage(file); + if (rr.validImage()) + { + // update cache with new entry. + notify(INFO)<<"Adding to cache image "< rwOriginal; @@ -1107,8 +1186,8 @@ ReaderWriter::ReadResult Registry::readNode(const std::string& fileName) ++itr) { rwOriginal.insert(itr->get()); - ReaderWriter::ReadResult rr = (*itr)->readNode(file,_options.get()); - if (rr.validNode()) return rr; + ReaderWriter::ReadResult rr = (*itr)->readNode(fileName,_options.get()); + if (rr.validNode()) return rr; else if (rr.error()) results.push_back(rr); } @@ -1123,7 +1202,7 @@ ReaderWriter::ReadResult Registry::readNode(const std::string& fileName) { if (rwOriginal.find(itr->get())==rwOriginal.end()) { - ReaderWriter::ReadResult rr = (*itr)->readNode(file,_options.get()); + ReaderWriter::ReadResult rr = (*itr)->readNode(fileName,_options.get()); if (rr.validNode()) return rr; else if (rr.error()) results.push_back(rr); } @@ -1131,9 +1210,12 @@ ReaderWriter::ReadResult Registry::readNode(const std::string& fileName) } + // need to sort out. + bool useObjectCache=true; + if (_createNodeFromImage) { - ReaderWriter::ReadResult rr = readImage(file); + ReaderWriter::ReadResult rr = readImage(fileName,useObjectCache); if (rr.validImage()) return createGeodeForImage(rr.takeImage()); //else if (rr.error()) results.push_back(rr); } @@ -1146,6 +1228,53 @@ ReaderWriter::ReadResult Registry::readNode(const std::string& fileName) return results.front(); } +ReaderWriter::ReadResult Registry::readNode(const std::string& fileName,bool useObjectCache) +{ + + std::string file = findDataFile( fileName ); + if (file.empty()) return ReaderWriter::ReadResult("Warning: file \""+fileName+"\" not found."); + + if (useObjectCache) + { + // search for entry in the object cache. + ObjectCache::iterator oitr=_objectCache.find(file); + if (oitr!=_objectCache.end()) + { + notify(INFO)<< "returning cached instanced of "<(oitr->second.first.get()); + if (node) return node; + else return ReaderWriter::ReadResult("Error file not of type osg::Node"); + } + + PushAndPopDataPath tmpfile(getFilePath(file)); + + ReaderWriter::ReadResult rr = readNode(file); + if (rr.validNode()) + { + // update cache with new entry. + notify(INFO)<<"Adding to cache node "<second.first->referenceCount()>1) + { + // so update it time stamp. + itr->second.second = currentTime; + } + } +} + +void Registry::removeExpiredObjectsInCache(double expiryTime) +{ + typedef std::vector ObjectsToRemove; + ObjectsToRemove objectsToRemove; + + // first collect all the exprired entries in the ObjectToRemove list. + for(ObjectCache::iterator oitr=_objectCache.begin(); + oitr!=_objectCache.end(); + ++oitr) + { + if (oitr->second.second<=expiryTime) + { + // record the filename of the entry to use as key for deleting + // afterwards/ + objectsToRemove.push_back(oitr->first); + } + } + + // remove the entries from the _objectCaache. + for(ObjectsToRemove::iterator ritr=objectsToRemove.begin(); + ritr!=objectsToRemove.end(); + ++ritr) + { + _objectCache.erase(*ritr); + } + +} + +void Registry::clearObjectCache() +{ + _objectCache.clear(); +} diff --git a/src/osgText/Font.cpp b/src/osgText/Font.cpp index 6a07c2a52..908f3e07a 100644 --- a/src/osgText/Font.cpp +++ b/src/osgText/Font.cpp @@ -63,7 +63,7 @@ osgText::Font* osgText::readFontFile(const std::string& filename) std::string foundFile = findFontFile(filename); if (foundFile.empty()) return 0; - osg::Object* object = osgDB::readObjectFile(foundFile); + osg::Object* object = osgDB::readObjectFile(foundFile,true); // if the object is a font then return it. osgText::Font* font = dynamic_cast(object);