From 7b003b24eaecc090e52b8b61091921c07468420e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 21 May 2008 21:09:45 +0000 Subject: [PATCH] Refactored DatabasePager and related classes to introduce support for multi-threaded paging, where the Pager manages threads of reading local and http files via seperate threads. This makes it possible to smoothly browse large databases where parts of the data are locally cached while others are on a remote server. Previously with this type of dataset the pager would stall all paging while http requests were being served, even when parts of the models are still loadable virtue of being in the local cache. Also as part of the refactoring the DatabaseRequest are now stored in the ProxyNode/PagedLOD nodes to facilitate quite updating in the cull traversal, with the new code avoiding mutex locks and searches. Previous on big databases the overhead involved in make database requests could accumulate to a point where it'd cause the cull traversal to break frame. The overhead now is negligable. Finally OSG_FILE_CACHE support has been moved from the curl plugin into the DatabasePager. Eventually this functionality will be moved out into osgDB for more general usage. --- include/osg/NodeVisitor | 2 +- include/osg/PagedLOD | 19 +- include/osg/ProxyNode | 31 +- include/osgDB/DatabasePager | 126 +- include/osgDB/ReaderWriter | 25 +- src/osg/PagedLOD.cpp | 8 +- src/osg/ProxyNode.cpp | 2 +- src/osgDB/DatabasePager.cpp | 1431 +++++++++++++--------- src/osgDB/Registry.cpp | 4 + src/osgPlugins/curl/CMakeLists.txt | 8 +- src/osgPlugins/curl/ReaderWriterCURL.cpp | 585 ++++----- src/osgPlugins/osg/PagedLOD.cpp | 28 +- src/osgPlugins/txp/TXPPagedLOD.cpp | 2 +- src/osgViewer/CompositeViewer.cpp | 13 +- src/osgViewer/Viewer.cpp | 18 +- src/osgViewer/ViewerBase.cpp | 9 +- src/osgWrappers/osg/NodeVisitor.cpp | 44 +- src/osgWrappers/osg/PagedLOD.cpp | 12 + src/osgWrappers/osg/ProxyNode.cpp | 13 +- src/osgWrappers/osgDB/DatabasePager.cpp | 101 +- src/osgWrappers/osgDB/ReaderWriter.cpp | 13 - 21 files changed, 1477 insertions(+), 1017 deletions(-) diff --git a/include/osg/NodeVisitor b/include/osg/NodeVisitor index b78d20a83..256ecd9df 100644 --- a/include/osg/NodeVisitor +++ b/include/osg/NodeVisitor @@ -268,7 +268,7 @@ class OSG_EXPORT NodeVisitor : public virtual Referenced DatabaseRequestHandler(): Referenced(true) {} - virtual void requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const FrameStamp* framestamp) = 0; + virtual void requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const FrameStamp* framestamp, osg::ref_ptr& databaseRequest) = 0; protected: virtual ~DatabaseRequestHandler() {} diff --git a/include/osg/PagedLOD b/include/osg/PagedLOD index 70fd80727..310d97296 100644 --- a/include/osg/PagedLOD +++ b/include/osg/PagedLOD @@ -58,10 +58,11 @@ class OSG_EXPORT PagedLOD : public LOD PerRangeData(const PerRangeData& prd); PerRangeData& operator = (const PerRangeData& prd); - std::string _filename; - float _priorityOffset; - float _priorityScale; - double _timeStamp; + std::string _filename; + float _priorityOffset; + float _priorityScale; + double _timeStamp; + osg::ref_ptr _databaseRequest; }; typedef std::vector PerRangeDataList; @@ -85,6 +86,16 @@ class OSG_EXPORT PagedLOD : public LOD unsigned int getNumTimeStamps() const { return _perRangeDataList.size(); } + /** Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests + * being carried on behalf of the DatabasePager. + * Note, in normal OSG usage you should not set this value yourself, as this will be managed by + * the osgDB::DatabasePager.*/ + osg::ref_ptr& getDatabaseRequest(unsigned int childNo) { return _perRangeDataList[childNo]._databaseRequest; } + + /** Return the const DatabaseRequest object.*/ + const osg::ref_ptr& getDatabaseRequest(unsigned int childNo) const { return _perRangeDataList[childNo]._databaseRequest; } + + /** Set the frame number of the last time that this PageLOD node was traversed. * Note, this frame number is automatically set by the traverse() method for all traversals (update, cull etc.). */ diff --git a/include/osg/ProxyNode b/include/osg/ProxyNode index 9db9fb095..372702236 100644 --- a/include/osg/ProxyNode +++ b/include/osg/ProxyNode @@ -46,12 +46,20 @@ class OSG_EXPORT ProxyNode : public Group /** Get the database path used to prepend to children's filenames.*/ inline const std::string& getDatabasePath() const { return _databasePath; } - typedef std::vector FileNameList; - - void setFileName(unsigned int childNo, const std::string& filename) { expandFileNameListTo(childNo); _filenameList[childNo]=filename; } - const std::string& getFileName(unsigned int childNo) const { return _filenameList[childNo]; } + void setFileName(unsigned int childNo, const std::string& filename) { expandFileNameListTo(childNo); _filenameList[childNo].first=filename; } + const std::string& getFileName(unsigned int childNo) const { return _filenameList[childNo].first; } unsigned int getNumFileNames() const { return _filenameList.size(); } + /** Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests + * being carried on behalf of the DatabasePager. + * Note, in normal OSG usage you should not set this value yourself, as this will be managed by + * the osgDB::DatabasePager.*/ + osg::ref_ptr& getDatabaseRequest(unsigned int childNo) { return _filenameList[childNo].second; } + + /** Return the const DatabaseRequest object.*/ + const osg::ref_ptr& getDatabaseRequest(unsigned int childNo) const { return _filenameList[childNo].second; } + + /** Modes which control how the center of object should be determined when computed which child is active.*/ enum CenterMode { @@ -102,14 +110,17 @@ class OSG_EXPORT ProxyNode : public Group void expandFileNameListTo(unsigned int pos); - FileNameList _filenameList; - std::string _databasePath; + typedef std::pair< std::string, osg::ref_ptr > FileNameDatabaseRequestPair; + typedef std::vector FileNameDatabaseRequestList; + + FileNameDatabaseRequestList _filenameList; + std::string _databasePath; - LoadingExternalReferenceMode _loadingExtReference; + LoadingExternalReferenceMode _loadingExtReference; - CenterMode _centerMode; - vec_type _userDefinedCenter; - value_type _radius; + CenterMode _centerMode; + vec_type _userDefinedCenter; + value_type _radius; }; diff --git a/include/osgDB/DatabasePager b/include/osgDB/DatabasePager index 3aa00e76c..723871698 100644 --- a/include/osgDB/DatabasePager +++ b/include/osgDB/DatabasePager @@ -37,9 +37,10 @@ namespace osgDB { + /** Database paging class which manages the loading of files in a background thread, * and synchronizing of loaded models with the main scene graph.*/ -class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler, public OpenThreads::Thread +class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler { public : @@ -62,21 +63,63 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl /** Add a request to load a node file to end the the database request list.*/ virtual void requestNodeFile(const std::string& fileName,osg::Group* group, - float priority, const osg::FrameStamp* framestamp); + float priority, const osg::FrameStamp* framestamp, + osg::ref_ptr& databaseRequest); virtual void requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const osg::FrameStamp* framestamp, + osg::ref_ptr& databaseRequest, ReaderWriter::Options* loadOptions); - /** Run does the database paging.*/ - virtual void run(); - - /** Cancel the database pager thread.*/ + /** Set the priority of the database pager thread(s).*/ + int setSchedulePriority(OpenThreads::Thread::ThreadPriority priority); + + /** Cancel the database pager thread(s).*/ virtual int cancel(); + virtual bool isRunning() const; + /** Clear all internally cached structures.*/ virtual void clear(); + class DatabaseThread : public osg::Referenced, public OpenThreads::Thread + { + public: + + enum Mode + { + HANDLE_ALL_REQUESTS, + HANDLE_NON_HTTP, + HANDLE_ONLY_HTTP + }; + + DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name); + + DatabaseThread(const DatabaseThread& dt, DatabasePager* pager); + + void setDone(bool done) { _done = done; } + bool getDone() const { return _done; } + + virtual int cancel(); + + virtual void run(); + + protected: + + virtual ~DatabaseThread(); + + bool _done; + DatabasePager* _pager; + Mode _mode; + std::string _name; + }; + + DatabaseThread* getDatabaseThread(unsigned int i) { return _databaseThreads[i].get(); } + + const DatabaseThread* getDatabaseThread(unsigned int i) const { return _databaseThreads[i].get(); } + + unsigned int getNumDatabaseThreads() const { return _databaseThreads.size(); } + /** Set whether the database pager thread should be paused or not.*/ void setDatabasePagerThreadPause(bool pause); @@ -232,7 +275,7 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl virtual void compileAllGLObjects(osg::State& state); /** Report how many items are in the _fileRequestList queue */ - unsigned int getFileRequestListSize() const { return _fileRequestList.size(); } + unsigned int getFileRequestListSize() const { return _fileRequestQueue._requestList.size() + _httpRequestQueue._requestList.size(); } /** Report how many items are in the _dataToCompileList queue */ unsigned int getDataToCompileListSize() const { return _dataToCompileList.size(); } @@ -263,12 +306,21 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl virtual ~DatabasePager(); + friend class DatabaseThread; + friend struct DatabaseRequest; struct DatabaseRequest : public osg::Referenced { DatabaseRequest(): + osg::Referenced(true), + _frameNumberFirstRequest(0), + _timestampFirstRequest(0.0), + _priorityFirstRequest(0.f), + _frameNumberLastRequest(0), + _timestampLastRequest(0.0), + _priorityLastRequest(0.0f), _numOfRequests(0) {} @@ -290,10 +342,43 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl return frameNumber - _frameNumberLastRequest <= 1; } }; - - typedef std::vector< osg::ref_ptr > DatabaseRequestList; + + typedef std::vector< osg::ref_ptr > DatabaseThreadList; + typedef std::list< osg::ref_ptr > DatabaseRequestList; typedef std::vector< osg::ref_ptr > ObjectList; + struct RequestQueue : public osg::Referenced + { + RequestQueue(DatabasePager* pager, const std::string& name); + + void block() { _block->block(); } + + void release() { _block->release(); } + + void updateBlock() + { + _block->set((!_requestList.empty() || !_childrenToDeleteList.empty()) && + !_pager->_databasePagerThreadPaused); + } + + void clear(); + + void add(DatabaseRequest* databaseRequest); + + void takeFirst(osg::ref_ptr& databaseRequest); + + osg::ref_ptr _block; + + DatabasePager* _pager; + std::string _name; + + OpenThreads::Mutex _requestMutex; + DatabaseRequestList _requestList; + + OpenThreads::Mutex _childrenToDeleteListMutex; + ObjectList _childrenToDeleteList; + }; + // forward declare inner helper classes class FindCompileableGLObjectsVisitor; friend class FindCompileableGLObjectsVisitor; @@ -310,15 +395,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl OpenThreads::Mutex _run_mutex; bool _startThreadCalled; - - osg::ref_ptr _databasePagerThreadBlock; - - inline void updateDatabasePagerThreadBlock() - { - _databasePagerThreadBlock->set( - (!_fileRequestList.empty() || !_childrenToDeleteList.empty()) && !_databasePagerThreadPaused); - } - // Helper functions for determining if objects need to be // compiled. inline static bool isCompiled(const osg::Texture* texture, @@ -410,12 +486,17 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl bool _acceptNewRequests; bool _databasePagerThreadPaused; + DatabaseThreadList _databaseThreads; + int _numFramesActive; mutable OpenThreads::Mutex _numFramesActiveMutex; int _frameNumber; - DatabaseRequestList _fileRequestList; - mutable OpenThreads::Mutex _fileRequestListMutex; + RequestQueue _fileRequestQueue; + RequestQueue _httpRequestQueue; + + //DatabaseRequestList _fileRequestList; + //mutable OpenThreads::Mutex _fileRequestListMutex; DatabaseRequestList _dataToCompileList; mutable OpenThreads::Mutex _dataToCompileListMutex; @@ -428,8 +509,8 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl float _valueAnisotropy; bool _deleteRemovedSubgraphsInDatabaseThread; - ObjectList _childrenToDeleteList; - mutable OpenThreads::Mutex _childrenToDeleteListMutex; + //ObjectList _childrenToDeleteList; + //mutable OpenThreads::Mutex _childrenToDeleteListMutex; DatabaseRequestList _dataToMergeList; mutable OpenThreads::Mutex _dataToMergeListMutex; @@ -451,7 +532,6 @@ class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandl double _totalTimeToMergeTiles; unsigned int _numTilesMerges; - struct CompileOperation : public osg::GraphicsOperation { CompileOperation(DatabasePager* databasePager); diff --git a/include/osgDB/ReaderWriter b/include/osgDB/ReaderWriter index 5a48b491c..4b156d757 100644 --- a/include/osgDB/ReaderWriter +++ b/include/osgDB/ReaderWriter @@ -90,21 +90,18 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object Options(): osg::Object(true), - _objectCacheHint(CACHE_ARCHIVES), - _asynchronousFileReadHint(false) {} + _objectCacheHint(CACHE_ARCHIVES) {} Options(const std::string& str): osg::Object(true), _str(str), - _objectCacheHint(CACHE_ARCHIVES), - _asynchronousFileReadHint(false) {} + _objectCacheHint(CACHE_ARCHIVES) {} Options(const Options& options,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): osg::Object(options,copyop), _str(options._str), _databasePaths(options._databasePaths), - _objectCacheHint(options._objectCacheHint), - _asynchronousFileReadHint(options._asynchronousFileReadHint) {} + _objectCacheHint(options._objectCacheHint) {} META_Object(osgDB,Options); @@ -131,21 +128,6 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object CacheHintOptions getObjectCacheHint() const { return _objectCacheHint; } - /** Set Asynchrnous file read hint. - * This hint is used by plugins like the libcurl http reader plugin to inform them that - * they should make an internal file read requests to their background threads to load files, - * with the plugin returning immediately with a ReadResult::FILE_REQUESTED status. It is - * assumed that calls will continue to be made to the plugin until the background threads - * have read or failed to read the request file, at which point the return status which change - * to FILE_LOADED and the objects will be returned. - * Note, this facility is particular useful when using DatabasePager in conjunction with - * internet based databases where file load latency is relatively high.*/ - void setAsynchronousFileReadHint(bool flag) { _asynchronousFileReadHint = flag; } - - /** Get Asynchrnous file read hint. */ - bool getAsynchronousFileReadHint() const { return _asynchronousFileReadHint; } - - /** Sets a plugindata value PluginData with a string */ void setPluginData(const std::string& s, void* v) const { _pluginData[s] = v; } @@ -169,7 +151,6 @@ class OSGDB_EXPORT ReaderWriter : public osg::Object std::string _str; FilePathList _databasePaths; CacheHintOptions _objectCacheHint; - bool _asynchronousFileReadHint; typedef std::map PluginDataMap; mutable PluginDataMap _pluginData; diff --git a/src/osg/PagedLOD.cpp b/src/osg/PagedLOD.cpp index a60c0cb56..92fcd0227 100644 --- a/src/osg/PagedLOD.cpp +++ b/src/osg/PagedLOD.cpp @@ -28,7 +28,8 @@ PagedLOD::PerRangeData::PerRangeData(const PerRangeData& prd): _filename(prd._filename), _priorityOffset(prd._priorityOffset), _priorityScale(prd._priorityScale), - _timeStamp(prd._timeStamp) {} + _timeStamp(prd._timeStamp), + _databaseRequest(prd._databaseRequest) {} PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData& prd) { @@ -37,6 +38,7 @@ PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData& _priorityOffset = prd._priorityOffset; _priorityScale = prd._priorityScale; _timeStamp = prd._timeStamp; + _databaseRequest = prd._databaseRequest; return *this; } @@ -188,12 +190,12 @@ void PagedLOD::traverse(NodeVisitor& nv) if (_databasePath.empty()) { - nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); + nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest); } else { // prepend the databasePath to the child's filename. - nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); + nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest); } } diff --git a/src/osg/ProxyNode.cpp b/src/osg/ProxyNode.cpp index 3a074a008..477c33174 100644 --- a/src/osg/ProxyNode.cpp +++ b/src/osg/ProxyNode.cpp @@ -62,7 +62,7 @@ void ProxyNode::traverse(NodeVisitor& nv) { for(unsigned int i=_children.size(); i<_filenameList.size(); ++i) { - nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_filenameList[i], this, 1.0f, nv.getFrameStamp()); + nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_filenameList[i].first, this, 1.0f, nv.getFrameStamp(), _filenameList[i].second); } } else diff --git a/src/osgDB/DatabasePager.cpp b/src/osgDB/DatabasePager.cpp index 7130051a4..526eae3f4 100644 --- a/src/osgDB/DatabasePager.cpp +++ b/src/osgDB/DatabasePager.cpp @@ -1,11 +1,14 @@ #include #include +#include #include +#include #include #include #include #include +#include #include #include @@ -80,398 +83,24 @@ RefPtrAdapter refPtrAdapt(const FuncObj& func) } } -DatabasePager::DatabasePager() +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// SortFileRequestFunctor +// +struct DatabasePager::SortFileRequestFunctor { - //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<& lhs,const osg::ref_ptr& rhs) const { - if (strcmp(str,"DEFAULT")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_DEFAULT); - } - else if (strcmp(str,"MIN")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MIN); - } - else if (strcmp(str,"LOW")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); - } - else if (strcmp(str,"NOMINAL")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_NOMINAL); - } - else if (strcmp(str,"HIGH")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_HIGH); - } - else if (strcmp(str,"MAX")==0) - { - setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MAX); - } + if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; + else if (lhs->_timestampLastRequest_timestampLastRequest) return false; + else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); } +}; -#if __APPLE__ - // OSX really doesn't like compiling display lists, and performs poorly when they are used, - // so apply this hack to make up for its short comings. - _drawablePolicy = USE_VERTEX_ARRAYS; -#else - _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS; -#endif - - str = getenv("OSG_DATABASE_PAGER_GEOMETRY"); - if (!str) str = getenv("OSG_DATABASE_PAGER_DRAWABLE"); - if (str) - { - if (strcmp(str,"DoNotModify")==0) - { - _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS; - } - else if (strcmp(str,"DisplayList")==0 || strcmp(str,"DL")==0) - { - _drawablePolicy = USE_DISPLAY_LISTS; - } - else if (strcmp(str,"VBO")==0) - { - _drawablePolicy = USE_VERTEX_BUFFER_OBJECTS; - } - else if (strcmp(str,"VertexArrays")==0 || strcmp(str,"VA")==0 ) - { - _drawablePolicy = USE_VERTEX_ARRAYS; - } - } - - _changeAutoUnRef = true; - _valueAutoUnRef = true; - _changeAnisotropy = false; - _valueAnisotropy = 1.0f; - - - - const char* ptr=0; - - _deleteRemovedSubgraphsInDatabaseThread = true; - if( (ptr = getenv("OSG_DELETE_IN_DATABASE_THREAD")) != 0) - { - _deleteRemovedSubgraphsInDatabaseThread = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 || - strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0; - - } - - _expiryDelay = 10.0; - if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0) - { - _expiryDelay = atof(ptr); - osg::notify(osg::NOTICE)<<"Expiry delay = "<<_expiryDelay<getOrCreateSharedStateManager(); - - //if (osgDB::Registry::instance()->getSharedStateManager()) - //osgDB::Registry::instance()->setUseObjectCacheHint(true); -} - -DatabasePager::DatabasePager(const DatabasePager& rhs) -{ - //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<& DatabasePager::prototype() -{ - static osg::ref_ptr s_DatabasePager = new DatabasePager; - return s_DatabasePager; -} - -DatabasePager* DatabasePager::create() -{ - return DatabasePager::prototype().valid() ? - DatabasePager::prototype()->clone() : - new DatabasePager; -} - - -int DatabasePager::cancel() -{ - int result = 0; - if( isRunning() ) - { - - _done = true; - - // cancel the thread.. - // result = Thread::cancel(); - //join(); - - // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. - _databasePagerThreadBlock->release(); - - // then wait for the the thread to stop running. - while(isRunning()) - { - // commenting out debug info as it was cashing crash on exit, presumable - // due to osg::notify or std::cout destructing earlier than this destructor. - // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"< lock(_fileRequestListMutex); - _fileRequestList.clear(); - } - - { - OpenThreads::ScopedLock lock(_dataToCompileListMutex); - _dataToCompileList.clear(); - } - - { - OpenThreads::ScopedLock lock(_childrenToDeleteListMutex); - _childrenToDeleteList.clear(); - } - - { - OpenThreads::ScopedLock lock(_dataToMergeListMutex); - _dataToMergeList.clear(); - } - - // note, no need to use a mutex as the list is only accessed from the update thread. - _pagedLODList.clear(); - - // ?? - // _activeGraphicsContexts -} - -void DatabasePager::resetStats() -{ - // initialize the stats variables - _minimumTimeToMergeTile = DBL_MAX; - _maximumTimeToMergeTile = -DBL_MAX; - _totalTimeToMergeTiles = 0.0; - _numTilesMerges = 0; -} - -void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, - float priority, const osg::FrameStamp* framestamp) -{ - requestNodeFile(fileName,group,priority,framestamp,Registry::instance()->getOptions()); -} - -void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, - float priority, const osg::FrameStamp* framestamp, - ReaderWriter::Options* loadOptions) -{ - if (!_acceptNewRequests) return; - - double timestamp = framestamp?framestamp->getReferenceTime():0.0; - int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber; - - // search to see if filename already exist in the file loaded list. - bool foundEntry = false; - - { - OpenThreads::ScopedLock lock(_dataToCompileListMutex); - - for(DatabaseRequestList::iterator litr = _dataToCompileList.begin(); - litr != _dataToCompileList.end() && !foundEntry; - ++litr) - { - if ((*litr)->_fileName==fileName) - { - foundEntry = true; - (*litr)->_frameNumberLastRequest = frameNumber; - (*litr)->_timestampLastRequest = timestamp; - (*litr)->_priorityLastRequest = priority; - ++((*litr)->_numOfRequests); - } - } - - } - - if (!foundEntry) - { - OpenThreads::ScopedLock lock(_dataToMergeListMutex); - - for(DatabaseRequestList::iterator litr = _dataToMergeList.begin(); - litr != _dataToMergeList.end() && !foundEntry; - ++litr) - { - if ((*litr)->_fileName==fileName) - { - foundEntry = true; - (*litr)->_frameNumberLastRequest = frameNumber; - (*litr)->_timestampLastRequest = timestamp; - (*litr)->_priorityLastRequest = priority; - ++((*litr)->_numOfRequests); - } - } - } - - if (!foundEntry) - { - - OpenThreads::ScopedLock lock(_fileRequestListMutex); - - // search to see if entry already in file request list. - bool foundEntry = false; - for(DatabaseRequestList::iterator ritr = _fileRequestList.begin(); - ritr != _fileRequestList.end() && !foundEntry; - ++ritr) - { - if ((*ritr)->_fileName==fileName) - { - foundEntry = true; - (*ritr)->_timestampLastRequest = timestamp; - (*ritr)->_priorityLastRequest = priority; - (*ritr)->_frameNumberLastRequest = frameNumber; - ++((*ritr)->_numOfRequests); - } - } - - if (!foundEntry) - { - osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("< databaseRequest = new DatabaseRequest; - - databaseRequest->_fileName = fileName; - databaseRequest->_frameNumberFirstRequest = frameNumber; - databaseRequest->_timestampFirstRequest = timestamp; - databaseRequest->_priorityFirstRequest = priority; - databaseRequest->_frameNumberLastRequest = frameNumber; - databaseRequest->_timestampLastRequest = timestamp; - databaseRequest->_priorityLastRequest = priority; - databaseRequest->_groupForAddingLoadedSubgraph = group; - - if ((Registry::instance()->getOptions()==loadOptions) && - (loadOptions ? !loadOptions->getAsynchronousFileReadHint() : true) && - osgDB::containsServerAddress(fileName)) - { - // we need to enable asynchronous file reading. - databaseRequest->_loadOptions = loadOptions ? - dynamic_cast(loadOptions->clone(osg::CopyOp::SHALLOW_COPY)) : - new osgDB::ReaderWriter::Options; - - databaseRequest->_loadOptions->setAsynchronousFileReadHint(true); - } - else - { - databaseRequest->_loadOptions = loadOptions; - } - - _fileRequestList.push_back(databaseRequest); - - updateDatabasePagerThreadBlock(); - } - } - - if (!isRunning()) - { - OpenThreads::ScopedLock lock(_run_mutex); - - if (!_startThreadCalled) - { - _startThreadCalled = true; - _done = false; - osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber(); - - } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<& lhs,const osg::ref_ptr& rhs) const - { - if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; - else if (lhs->_timestampLastRequest_timestampLastRequest) return false; - else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); - } -}; - - -void DatabasePager::setDatabasePagerThreadPause(bool pause) -{ - _databasePagerThreadPaused = pause; - updateDatabasePagerThreadBlock(); + _block = new osg::RefBlock; } -void DatabasePager::run() +void DatabasePager::RequestQueue::clear() { - osg::notify(osg::INFO)<<"DatabasePager::run()"< lock(_requestMutex); + _requestList.clear(); + updateBlock(); +} + +void DatabasePager::RequestQueue::add(DatabasePager::DatabaseRequest* databaseRequest) +{ + OpenThreads::ScopedLock lock(_requestMutex); + _requestList.push_back(databaseRequest); + + updateBlock(); +} + +void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr& databaseRequest) +{ + OpenThreads::ScopedLock lock(_requestMutex); + + if (!_requestList.empty()) + { + _requestList.sort(SortFileRequestFunctor()); + databaseRequest = _requestList.front(); + _requestList.erase(_requestList.begin()); + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// DatabaseThread +// +DatabasePager::DatabaseThread::DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name): + _done(false), + _pager(pager), + _mode(mode), + _name(name) +{ +} + +DatabasePager::DatabaseThread::DatabaseThread(const DatabaseThread& dt, DatabasePager* pager): + _done(false), + _pager(pager), + _mode(dt._mode), + _name(dt._name) +{ + +} + +DatabasePager::DatabaseThread::~DatabaseThread() +{ + cancel(); +} + +int DatabasePager::DatabaseThread::cancel() +{ + int result = 0; + + if( isRunning() ) + { + + _done = true; + + // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. + // _databasePagerThreadBlock->release(); + + // then wait for the the thread to stop running. + while(isRunning()) + { + // commenting out debug info as it was cashing crash on exit, presumable + // due to osg::notify or std::cout destructing earlier than this destructor. + // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<_fileRequestQueue); + break; + case(HANDLE_NON_HTTP): + read_queue = &(_pager->_fileRequestQueue); + out_queue = &(_pager->_httpRequestQueue); + break; + case(HANDLE_ONLY_HTTP): + read_queue = &(_pager->_httpRequestQueue); + break; + } + + //Getting CURL Environment Variables (If found rewrite OSG Options) + std::string cacheFilePath; + const char* fileCachePath = getenv("OSG_FILE_CACHE"); + if (fileCachePath) //Env Cache Directory + cacheFilePath = std::string(fileCachePath); + + do { - _databasePagerThreadBlock->block(); + read_queue->block(); + + osg::notify(osg::INFO)<<_name<<": _pager->_requestList.size()= "<_requestList.size()<<" to delete = "<_childrenToDeleteList.size()<_deleteRemovedSubgraphsInDatabaseThread) { - osg::ref_ptr obj = 0; + ObjectList deleteList; + { - OpenThreads::ScopedLock lock(_childrenToDeleteListMutex); - if (!_childrenToDeleteList.empty()) - { - //osg::notify(osg::NOTICE)<<"In DatabasePager thread deleting "<<_childrenToDeleteList.size()<<" objects"<tick(); - obj = _childrenToDeleteList.back(); - _childrenToDeleteList.pop_back(); - //osg::notify(osg::NOTICE)<<"Done DatabasePager thread deleted in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<<" objects"< lock(read_queue->_childrenToDeleteListMutex); + deleteList.swap(read_queue->_childrenToDeleteList); + read_queue->updateBlock(); } } @@ -675,187 +399,284 @@ void DatabasePager::run() // load any subgraphs that are required. // osg::ref_ptr databaseRequest; - - // get the front of the file request list. - { - OpenThreads::ScopedLock lock(_fileRequestListMutex); - if (!_fileRequestList.empty()) - { - std::sort(_fileRequestList.begin(),_fileRequestList.end(),SortFileRequestFunctor()); - databaseRequest = _fileRequestList.front(); - } - } + read_queue->takeFirst(databaseRequest); if (databaseRequest.valid()) { // check if databaseRequest is still relevant - if (_frameNumber-databaseRequest->_frameNumberLastRequest<=1) + if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)<=1) { - - // load the data, note safe to write to the databaseRequest since once - // it is created this thread is the only one to write to the _loadedModel pointer. - //osg::notify(osg::NOTICE)<<"In DatabasePager thread readNodeFile("<_fileName<<")"<tick(); - - - bool serialize_readNodeFile = true; - if (serialize_readNodeFile) + + // now check to see if this request is appropriate for this thread + switch(_mode) { - // do *not* assume that we only have one DatabasePager, or that reaNodeFile is thread safe... - static OpenThreads::Mutex s_serialize_readNodeFile_mutex; - OpenThreads::ScopedLock lock(s_serialize_readNodeFile_mutex); - databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, - databaseRequest->_loadOptions.get()); - } - else - { - // assume that we only have one DatabasePager, or that readNodeFile is thread safe... - databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, - databaseRequest->_loadOptions.get()); - } - - //osg::notify(osg::NOTICE)<<" node read in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<_loadedModel.valid() && !_activeGraphicsContexts.empty()) - { - // force a compute of the loaded model's bounding volume, so that when the subgraph - // merged with the main scene graph and large computeBound() isn't incurred. - databaseRequest->_loadedModel->getBound(); - - - ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin(); - - DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr]; - ++itr; - - // find all the compileable rendering objects - FindCompileableGLObjectsVisitor frov(dtc, - _changeAutoUnRef, _valueAutoUnRef, - _changeAnisotropy, _valueAnisotropy, - _drawablePolicy, this); - - // push the soon to be parent on the nodepath of the NodeVisitor so that - // during traversal one can test for where it'll be in the overall scene graph - osg::NodePathList nodePathList = databaseRequest->_groupForAddingLoadedSubgraph->getParentalNodePaths(); - if (!nodePathList.empty()) - { - osg::NodePath& nodePath = nodePathList.front(); - for(osg::NodePath::iterator nitr = nodePath.begin(); - nitr != nodePath.end(); - ++nitr) + case(HANDLE_ALL_REQUESTS): + // do nothing as this thread can handle the load + if (osgDB::containsServerAddress(databaseRequest->_fileName)) { - frov.pushOntoNodePath(*nitr); - } - } - - frov.pushOntoNodePath(databaseRequest->_groupForAddingLoadedSubgraph.get()); - - databaseRequest->_loadedModel->accept(frov); - - if (!dtc.first.empty() || !dtc.second.empty()) - { - loadedObjectsNeedToBeCompiled = true; - - // copy the objects from the compile list to the other graphics context list. - for(; - itr != _activeGraphicsContexts.end(); - ++itr) - { - databaseRequest->_dataToCompileMap[*itr] = dtc; - } - } - } - - // move the databaseRequest from the front of the fileRequest to the end of - // dataToCompile or dataToMerge lists. - { - OpenThreads::ScopedLock lock(_fileRequestListMutex); - - DatabaseRequestList::iterator itr = std::find(_fileRequestList.begin(),_fileRequestList.end(),databaseRequest); - if (itr != _fileRequestList.end()) - { - if (databaseRequest->_loadedModel.valid()) - { - if (loadedObjectsNeedToBeCompiled) + std::string cacheFileName; + if (!cacheFilePath.empty()) { - OpenThreads::ScopedLock lock(_dataToCompileListMutex); - _dataToCompileList.push_back(databaseRequest); + cacheFileName = cacheFilePath + "/" + + osgDB::getServerAddress(databaseRequest->_fileName) + "/" + + osgDB::getServerFileName(databaseRequest->_fileName); + + std::string path = osgDB::getFilePath(cacheFileName); + + if (!osgDB::fileExists(path)) + { + cacheFileName.clear(); + } + } + + if (!cacheFilePath.empty() && osgDB::fileExists(cacheFileName)) + { + osg::notify(osg::INFO)<<_name<<": Reading cache file " << cacheFileName <<", previous path "<_fileName)<_fileName = cacheFileName; + } + } + + break; + + case(HANDLE_NON_HTTP): + // check the cache first + if (osgDB::containsServerAddress(databaseRequest->_fileName)) + { + std::string cacheFileName; + if (!cacheFilePath.empty()) + { + cacheFileName = cacheFilePath + "/" + + osgDB::getServerAddress(databaseRequest->_fileName) + "/" + + osgDB::getServerFileName(databaseRequest->_fileName); + + std::string path = osgDB::getFilePath(cacheFileName); + + if (!osgDB::fileExists(path)) + { + cacheFileName.clear(); + } + } + + if (!cacheFilePath.empty() && osgDB::fileExists(cacheFileName)) + { + osg::notify(osg::INFO)<<_name<<": Reading cache file " << cacheFileName <<", previous path "<_fileName)<_fileName = cacheFileName; } else { - OpenThreads::ScopedLock lock(_dataToMergeListMutex); - _dataToMergeList.push_back(databaseRequest); - } - } - - _fileRequestList.erase(itr); - } - - updateDatabasePagerThreadBlock(); - } - // Prepare and prune the to-be-compiled list here in - // the pager thread rather than in the draw or - // graphics context thread(s). - if (loadedObjectsNeedToBeCompiled) - { - OpenThreads::ScopedLock lock(_dataToCompileListMutex); - std::sort(_dataToCompileList.begin(), - _dataToCompileList.end(), SortFileRequestFunctor()); - // Prune all the old entries. - DatabaseRequestList::iterator tooOld - = std::find_if(_dataToCompileList.begin(), - _dataToCompileList.end(), - refPtrAdapt(std::not1(std::bind2nd(std::mem_fun(&DatabaseRequest - ::isRequestCurrent), - _frameNumber)))); - // This is the database thread, so just delete - _dataToCompileList.erase(tooOld, _dataToCompileList.end()); - - if (!_dataToCompileList.empty()) - { - for(ActiveGraphicsContexts::iterator itr = _activeGraphicsContexts.begin(); - itr != _activeGraphicsContexts.end(); - ++itr) - { - osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr); - if (gc) - { - osg::GraphicsThread* gt = gc->getGraphicsThread(); - if (gt) - { - gt->add(new DatabasePager::CompileOperation(this)); - } - else - { - gc->makeCurrent(); - - compileAllGLObjects(*(gc->getState())); - - gc->releaseContext(); - } + osg::notify(osg::INFO)<<_name<<": Passing http requests over "<_fileName<<" cacheFileName="<add(databaseRequest.get()); + databaseRequest = 0; } } - - // osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<_fileName)) + { + osg::notify(osg::NOTICE)<<_name<<": Help we have request we shouldn't have "<_fileName<_fileName<<")"<tick(); + + + bool serialize_readNodeFile = false; + if (serialize_readNodeFile) + { + // do *not* assume that we only have one DatabasePager, or that reaNodeFile is thread safe... + static OpenThreads::Mutex s_serialize_readNodeFile_mutex; + OpenThreads::ScopedLock lock(s_serialize_readNodeFile_mutex); + databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, + databaseRequest->_loadOptions.get()); } else { - //std::cout<<"frame number delta for "<_fileName<<" "<<_frameNumber-databaseRequest->_frameNumberLastRequest< lock(_fileRequestListMutex); + // assume that we only have one DatabasePager, or that readNodeFile is thread safe... + databaseRequest->_loadedModel = osgDB::readRefNodeFile(databaseRequest->_fileName, + databaseRequest->_loadOptions.get()); + } - if (!_fileRequestList.empty()) _fileRequestList.erase(_fileRequestList.begin()); + if (databaseRequest->_loadedModel.valid() && + osgDB::containsServerAddress(databaseRequest->_fileName) && + !cacheFilePath.empty()) + { + std::string cacheFileName = cacheFilePath + "/" + + osgDB::getServerAddress(databaseRequest->_fileName) + "/" + + osgDB::getServerFileName(databaseRequest->_fileName); - updateDatabasePagerThreadBlock(); + std::string path = osgDB::getFilePath(cacheFileName); + if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) + { + cacheFileName.clear(); + } + + if (!cacheFileName.empty() && osgDB::fileExists(cacheFileName)) + { + osg::notify(osg::NOTICE)<<_name<<": Warning, file already in cache file, shouldn't have needed to be reloaded. cache file=" << cacheFileName <<", previous path "<_fileName)<_loadedModel), cacheFileName, databaseRequest->_loadOptions.get()); + } + } + + if ((_pager->_frameNumber-databaseRequest->_frameNumberLastRequest)>1) + { + osg::notify(osg::INFO)<<_name<<": Warning DatabaseRquest no longer required."<_loadedModel = 0; + } + + //osg::notify(osg::NOTICE)<<" node read in "<delta_m(before,osg::Timer::instance()->tick())<<" ms"<_doPreCompile && databaseRequest->_loadedModel.valid() && !_pager->_activeGraphicsContexts.empty()) + { + // force a compute of the loaded model's bounding volume, so that when the subgraph + // merged with the main scene graph and large computeBound() isn't incurred. + databaseRequest->_loadedModel->getBound(); + + + ActiveGraphicsContexts::iterator itr = _pager->_activeGraphicsContexts.begin(); + + DataToCompile& dtc = databaseRequest->_dataToCompileMap[*itr]; + ++itr; + + // find all the compileable rendering objects + DatabasePager::FindCompileableGLObjectsVisitor frov(dtc, + _pager->_changeAutoUnRef, _pager->_valueAutoUnRef, + _pager->_changeAnisotropy, _pager->_valueAnisotropy, + _pager->_drawablePolicy, _pager); + + // push the soon to be parent on the nodepath of the NodeVisitor so that + // during traversal one can test for where it'll be in the overall scene graph + osg::NodePathList nodePathList = databaseRequest->_groupForAddingLoadedSubgraph->getParentalNodePaths(); + if (!nodePathList.empty()) + { + osg::NodePath& nodePath = nodePathList.front(); + for(osg::NodePath::iterator nitr = nodePath.begin(); + nitr != nodePath.end(); + ++nitr) + { + frov.pushOntoNodePath(*nitr); + } + } + + frov.pushOntoNodePath(databaseRequest->_groupForAddingLoadedSubgraph.get()); + + databaseRequest->_loadedModel->accept(frov); + + if (!dtc.first.empty() || !dtc.second.empty()) + { + loadedObjectsNeedToBeCompiled = true; + + // copy the objects from the compile list to the other graphics context list. + for(; + itr != _pager->_activeGraphicsContexts.end(); + ++itr) + { + databaseRequest->_dataToCompileMap[*itr] = dtc; + } + } + } + + // move the databaseRequest from the front of the fileRequest to the end of + // dataToCompile or dataToMerge lists. + if (databaseRequest->_loadedModel.valid()) + { + if (loadedObjectsNeedToBeCompiled) + { + OpenThreads::ScopedLock lock(_pager->_dataToCompileListMutex); + _pager->_dataToCompileList.push_back(databaseRequest); + } + else + { + OpenThreads::ScopedLock lock(_pager->_dataToMergeListMutex); + _pager->_dataToMergeList.push_back(databaseRequest); + } + } + + // Prepare and prune the to-be-compiled list here in + // the pager thread rather than in the draw or + // graphics context thread(s). + if (loadedObjectsNeedToBeCompiled) + { + OpenThreads::ScopedLock lock(_pager->_dataToCompileListMutex); + _pager->_dataToCompileList.sort(SortFileRequestFunctor()); + + // Prune all the old entries. + DatabaseRequestList::iterator tooOld + = std::find_if(_pager->_dataToCompileList.begin(), + _pager->_dataToCompileList.end(), + refPtrAdapt(std::not1(std::bind2nd(std::mem_fun(&DatabaseRequest::isRequestCurrent), + _pager->_frameNumber)))); + + // This is the database thread, so just delete + for(DatabaseRequestList::iterator citr = tooOld; + citr != _pager->_dataToCompileList.end(); + ++citr) + { + osg::notify(osg::INFO)<<_name<<": pruning from compile list"<_loadedModel = 0; + } + + _pager->_dataToCompileList.erase(tooOld, _pager->_dataToCompileList.end()); + + loadedObjectsNeedToBeCompiled = !_pager->_dataToCompileList.empty(); + } + + if (loadedObjectsNeedToBeCompiled && !_pager->_activeGraphicsContexts.empty()) + { + for(ActiveGraphicsContexts::iterator itr = _pager->_activeGraphicsContexts.begin(); + itr != _pager->_activeGraphicsContexts.end(); + ++itr) + { + osg::GraphicsContext* gc = osg::GraphicsContext::getCompileContext(*itr); + if (gc) + { + osg::GraphicsThread* gt = gc->getGraphicsThread(); + if (gt) + { + gt->add(new DatabasePager::CompileOperation(_pager)); + } + else + { + gc->makeCurrent(); + + _pager->compileAllGLObjects(*(gc->getState())); + + gc->releaseContext(); + } + } + } + + // osg::notify(osg::NOTICE)<<"Done compiling in paging thread"<getOrCreateSharedStateManager(); + + //if (osgDB::Registry::instance()->getSharedStateManager()) + //osgDB::Registry::instance()->setUseObjectCacheHint(true); + +#if 0 + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_ALL_REQUESTS,"HANDLE_ALL_REQUESTS")); +#else + + #if 1 + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_NON_HTTP, "HANDLE_NON_HTTP 0")); + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_ONLY_HTTP, "HANDLE_ONLY_HTTP 1")); + #else + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_NON_HTTP, "HANDLE_NON_HTTP 0")); + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_NON_HTTP, "HANDLE_NON_HTTP 1")); + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_ONLY_HTTP, "HANDLE_ONLY_HTTP 2")); + _databaseThreads.push_back(new DatabaseThread(this, DatabaseThread::HANDLE_ONLY_HTTP, "HANDLE_ONLY_HTTP 3")); + #endif +#endif +} + +DatabasePager::DatabasePager(const DatabasePager& rhs): + _fileRequestQueue(this,"fileRequestQueue"), + _httpRequestQueue(this,"httpRequestQueue") +{ + //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<& DatabasePager::prototype() +{ + static osg::ref_ptr s_DatabasePager = new DatabasePager; + return s_DatabasePager; +} + +DatabasePager* DatabasePager::create() +{ + return DatabasePager::prototype().valid() ? + DatabasePager::prototype()->clone() : + new DatabasePager; +} + +int DatabasePager::setSchedulePriority(OpenThreads::Thread::ThreadPriority priority) +{ + for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); + dt_itr != _databaseThreads.end(); + ++dt_itr) + { + (*dt_itr)->setSchedulePriority(priority); + } +} + +bool DatabasePager::isRunning() const +{ + for(DatabaseThreadList::const_iterator dt_itr = _databaseThreads.begin(); + dt_itr != _databaseThreads.end(); + ++dt_itr) + { + if ((*dt_itr)->isRunning()) return true; + } + + return false; +} + +int DatabasePager::cancel() +{ + int result = 0; + + for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); + dt_itr != _databaseThreads.end(); + ++dt_itr) + { + (*dt_itr)->setDone(true); + } + + // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. + _fileRequestQueue.release(); + _httpRequestQueue.release(); + + for(DatabaseThreadList::iterator dt_itr = _databaseThreads.begin(); + dt_itr != _databaseThreads.end(); + ++dt_itr) + { + (*dt_itr)->cancel(); + } + + _done = true; + _startThreadCalled = false; + + //std::cout<<"DatabasePager::~DatabasePager() stopped running"< lock(_dataToCompileListMutex); + _dataToCompileList.clear(); + } + + { + OpenThreads::ScopedLock lock(_dataToMergeListMutex); + _dataToMergeList.clear(); + } + + // note, no need to use a mutex as the list is only accessed from the update thread. + _pagedLODList.clear(); + + // ?? + // _activeGraphicsContexts +} + +void DatabasePager::resetStats() +{ + // initialize the stats variables + _minimumTimeToMergeTile = DBL_MAX; + _maximumTimeToMergeTile = -DBL_MAX; + _totalTimeToMergeTiles = 0.0; + _numTilesMerges = 0; +} + +void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, + float priority, const osg::FrameStamp* framestamp, + osg::ref_ptr& databaseRequest) +{ + requestNodeFile(fileName,group,priority,framestamp,databaseRequest,Registry::instance()->getOptions()); +} + +void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, + float priority, const osg::FrameStamp* framestamp, + osg::ref_ptr& databaseRequestRef, + ReaderWriter::Options* loadOptions) +{ + if (!_acceptNewRequests) return; + + osg::Timer_t start_tick = osg::Timer::instance()->tick(); + + double timestamp = framestamp?framestamp->getReferenceTime():0.0; + int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber; + + static int previousFrame = -1; + static double totalTime = 0.0; + + + if (previousFrame!=frameNumber) + { + // osg::notify(osg::NOTICE)<<"requestNodeFiles for "<_frameNumberLastRequest = frameNumber; + databaseRequest->_timestampLastRequest = timestamp; + databaseRequest->_priorityLastRequest = priority; + ++(databaseRequest->_numOfRequests); + + foundEntry = true; + + if (databaseRequestRef->referenceCount()==1) + { + osg::notify(osg::INFO)<<"DatabasePager::fileRquest("<_frameNumberFirstRequest = frameNumber; + databaseRequest->_timestampFirstRequest = timestamp; + databaseRequest->_priorityFirstRequest = priority; + databaseRequest->_frameNumberLastRequest = frameNumber; + databaseRequest->_timestampLastRequest = timestamp; + databaseRequest->_priorityLastRequest = priority; + databaseRequest->_groupForAddingLoadedSubgraph = group; + databaseRequest->_loadOptions = loadOptions; + + _fileRequestQueue.add(databaseRequest); + } + + } + } + + if (!foundEntry) + { + osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("< lock(_fileRequestQueue._requestMutex); + + if (!databaseRequestRef.valid() || databaseRequestRef->referenceCount()==1) + { + osg::ref_ptr databaseRequest = new DatabaseRequest; + + databaseRequestRef = databaseRequest.get(); + + databaseRequest->_fileName = fileName; + databaseRequest->_frameNumberFirstRequest = frameNumber; + databaseRequest->_timestampFirstRequest = timestamp; + databaseRequest->_priorityFirstRequest = priority; + databaseRequest->_frameNumberLastRequest = frameNumber; + databaseRequest->_timestampLastRequest = timestamp; + databaseRequest->_priorityLastRequest = priority; + databaseRequest->_groupForAddingLoadedSubgraph = group; + databaseRequest->_loadOptions = loadOptions; + + _fileRequestQueue._requestList.push_back(databaseRequest.get()); + + _fileRequestQueue.updateBlock(); + } + + } + + if (!_startThreadCalled) + { + OpenThreads::ScopedLock lock(_run_mutex); + + if (!_startThreadCalled) + { + _startThreadCalled = true; + _done = false; + osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<startThread(); + } + } + } + + totalTime += osg::Timer::instance()->delta_m(start_tick, osg::Timer::instance()->tick()); +} + +void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp) +{ + if (framestamp) + { + //osg::notify(osg::INFO) << "signalBeginFrame "<getFrameNumber()<<">>>>>>>>>>>>>>>>"<getFrameNumber(); + + } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<_loadedModel.get()); osg::Group* group = databaseRequest->_groupForAddingLoadedSubgraph.get(); + osg::PagedLOD* plod = dynamic_cast(group); if (plod) { plod->setTimeStamp(plod->getNumChildren(),timeStamp); - } + plod->getDatabaseRequest(plod->getNumChildren()) = 0; + } + else + { + osg::ProxyNode* proxyNode = dynamic_cast(group); + if (proxyNode) + { + proxyNode->getDatabaseRequest(proxyNode->getNumChildren()) = 0; + } + } + group->addChild(databaseRequest->_loadedModel.get()); osg::notify(osg::INFO)<<"merged subgraph"<_fileName<<" after "<_numOfRequests<<" requests and time="<<(timeStamp-databaseRequest->_timestampFirstRequest)*1000.0<_loadedModel = 0; // osg::notify(osg::NOTICE)<<"curr = "<delta_m(before,osg::Timer::instance()->tick())<<" ms "< #include #include #include -#include #include #include @@ -23,353 +23,298 @@ #include #include -class EasyCurl : public osg::Referenced +#include "ReaderWriterCURL.h" + +using namespace osg_curl; + +// +// StreamObject +// +EasyCurl::StreamObject::StreamObject(std::ostream* stream1, const std::string& cacheFileName): + _stream1(stream1), + _cacheFileName(cacheFileName) { - public: + _foutOpened = false; +} + +void EasyCurl::StreamObject::write(const char* ptr, size_t realsize) +{ + if (_stream1) _stream1->write(ptr, realsize); + + if (!_cacheFileName.empty()) + { + if (!_foutOpened) + { + osg::notify(osg::INFO)<<"Writing to cache: "<<_cacheFileName<write(ptr, realsize); - - if (!_cacheFileName.empty()) - { - if (!_foutOpened) - { - osg::notify(osg::INFO)<<"Writing to cache: "<<_cacheFileName<write((const char*)ptr, realsize); + sp->write((const char*)ptr, realsize); - return realsize; + return realsize; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// +// EasyCurl +// +EasyCurl::EasyCurl() +{ + osg::notify(osg::INFO)<<"EasyCurl::EasyCurl()"<=400) { - osg::notify(osg::INFO)<<"EasyCurl::EasyCurl()"<readObject(fin,options); + case(ARCHIVE): return rw->openArchive(fin,options); + case(IMAGE): return rw->readImage(fin,options); + case(HEIGHTFIELD): return rw->readHeightField(fin,options); + case(NODE): return rw->readNode(fin,options); + default: break; + } + return ReadResult::FILE_NOT_HANDLED; +} + +osgDB::ReaderWriter::ReadResult ReaderWriterCURL::readFile(ObjectType objectType, const std::string& fullFileName, const osgDB::ReaderWriter::Options *options) const +{ + + + if (!osgDB::containsServerAddress(fullFileName)) + { + if (options && !options->getDatabasePathList().empty()) + { + if (osgDB::containsServerAddress(options->getDatabasePathList().front())) + { + std::string newFileName = options->getDatabasePathList().front() + "/" + fullFileName; + + return readFile(objectType, newFileName,options); + } } + return ReadResult::FILE_NOT_HANDLED; + } - osgDB::ReaderWriter::ReadResult read(const std::string& proxyAddress, const std::string& fileName, StreamObject& sp) + osg::notify(osg::INFO)<<"ReaderWriterCURL::readFile("<getOptionString()); + std::string opt; + while (iss >> opt) { - if(!proxyAddress.empty()) - { - osg::notify(osg::NOTICE)<<"Setting proxy: "<=400) - { - osg::notify(osg::NOTICE)<<"Error: libcurl read error, file="<readObject(cacheFileName,options); - CURL* _curl; -}; + return result; + } +#endif + osgDB::ReaderWriter *reader = + osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(fileName)); -class ReaderWriterCURL : public osgDB::ReaderWriter -{ - public: + if (!reader) + { + osg::notify(osg::NOTICE)<<"Error: No ReaderWriter for file "< local_opt = const_cast(options); + if (!local_opt) local_opt = new Options; - virtual ReadResult readHeightField(const std::string& fileName, const Options *options) const - { - return readFile(HEIGHTFIELD,fileName,options); - } + local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); - virtual ReadResult readNode(const std::string& fileName, const Options *options) const - { - return readFile(NODE,fileName,options); - } + ReadResult readResult = readFile(objectType, reader, buffer, local_opt.get() ); - ReadResult readFile(ObjectType objectType, osgDB::ReaderWriter* rw, std::istream& fin, const Options *options) const +#if 0 + if (!cacheFileName.empty() && readResult.success()) { switch(objectType) { - case(OBJECT): return rw->readObject(fin,options); - case(ARCHIVE): return rw->openArchive(fin,options); - case(IMAGE): return rw->readImage(fin,options); - case(HEIGHTFIELD): return rw->readHeightField(fin,options); - case(NODE): return rw->readNode(fin,options); - default: break; - } - return ReadResult::FILE_NOT_HANDLED; - } - - virtual ReadResult readFile(ObjectType objectType, const std::string& fullFileName, const Options *options) const - { - std::string cacheFilePath, cacheFileName; - std::string proxyAddress, optProxy, optProxyPort; - - if (options) - { - std::istringstream iss(options->getOptionString()); - std::string opt; - while (iss >> opt) - { - int index = opt.find( "=" ); - if( opt.substr( 0, index ) == "OSG_FILE_CACHE" ) - cacheFilePath = opt.substr( index+1 ); //Setting Cache Directory by OSG Options - else if( opt.substr( 0, index ) == "OSG_CURL_PROXY" ) - optProxy = opt.substr( index+1 ); - else if( opt.substr( 0, index ) == "OSG_CURL_PROXYPORT" ) - optProxyPort = opt.substr( index+1 ); - } - - //Setting Proxy by OSG Options - if(!optProxy.empty()) - if(!optProxyPort.empty()) - proxyAddress = optProxy + ":" + optProxyPort; - else - proxyAddress = optProxy + ":8080"; //Port not found, using default - } - - if (!osgDB::containsServerAddress(fullFileName)) - { - if (options && !(options->getDatabasePathList().empty())) - { - if (osgDB::containsServerAddress(options->getDatabasePathList().front())) - { - std::string newFileName = options->getDatabasePathList().front() + "/" + fullFileName; - - return readFile(objectType, newFileName,options); - } - } - - return ReadResult::FILE_NOT_HANDLED; - } - - std::string fileName; - std::string ext = osgDB::getFileExtension(fullFileName); - if (ext=="curl") - { - fileName = osgDB::getNameLessExtension(fullFileName); - } - else - { - fileName = fullFileName; - } - - //Getting CURL Environment Variables (If found rewrite OSG Options) - const char* fileCachePath = getenv("OSG_FILE_CACHE"); - if (fileCachePath) //Env Cache Directory - cacheFilePath = std::string(fileCachePath); - - if (!cacheFilePath.empty()) - { - cacheFileName = cacheFilePath + "/" + - osgDB::getServerAddress(fileName) + "/" + - osgDB::getServerFileName(fileName); - - std::string path = osgDB::getFilePath(cacheFileName); - - if (!osgDB::fileExists(path) && !osgDB::makeDirectory(path)) - { - cacheFileName.clear(); - } - } - - if (!cacheFilePath.empty() && osgDB::fileExists(cacheFileName)) - { - osg::notify(osg::INFO) << "Reading cache file " << cacheFileName << std::endl; - ReadResult result = osgDB::Registry::instance()->readObject(cacheFileName,options); - return result; - } - - osgDB::ReaderWriter *reader = - osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(fileName)); - - if (!reader) - { - osg::notify(osg::NOTICE)<<"Error: No ReaderWriter for file "<getAsynchronousFileReadHint() : false; - - osg::notify(osg::INFO)<<"AsynchronousFileReadHint= "< local_opt = const_cast(options); - if (!local_opt) local_opt = new Options; - - local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName)); - - ReadResult readResult = readFile(objectType, reader, buffer, local_opt.get() ); - - local_opt->getDatabasePathList().pop_front(); - - return readResult; - } - else - { - return curlResult; + case(NODE): + osg::notify(osg::NOTICE)<<"Write to cache "<writeNode(*readResult.getNode(), cacheFileName, local_opt.get()); + break; + default: + osg::notify(osg::NOTICE)<<"Curl plugin write to cache not implemented yet"< > ThreadCurlMap; - - EasyCurl& getEasyCurl() const - { - OpenThreads::ScopedLock lock(_threadCurlMapMutex); - - osg::ref_ptr& ec = _threadCurlMap[OpenThreads::Thread::CurrentThread()]; - if (!ec) ec = new EasyCurl; - - return *ec; - } - - mutable OpenThreads::Mutex _threadCurlMapMutex; - mutable ThreadCurlMap _threadCurlMap; -}; +#endif + local_opt->getDatabasePathList().pop_front(); + return readResult; + } + else + { + return curlResult; + } +} // now register with Registry to instantiate the above // reader/writer. -REGISTER_OSGPLUGIN(rgb, ReaderWriterCURL) +REGISTER_OSGPLUGIN(curl, ReaderWriterCURL) diff --git a/src/osgPlugins/osg/PagedLOD.cpp b/src/osgPlugins/osg/PagedLOD.cpp index 778c5e93c..219691ced 100644 --- a/src/osgPlugins/osg/PagedLOD.cpp +++ b/src/osgPlugins/osg/PagedLOD.cpp @@ -28,15 +28,23 @@ bool PagedLOD_readLocalData(Object& obj, Input& fr) PagedLOD& lod = static_cast(obj); - if (lod.getDatabasePath().empty() && fr.getOptions() && !fr.getOptions()->getDatabasePathList().empty()) + std::string path; + if (!fr.read("DatabasePath",path)) { - const std::string& path = fr.getOptions()->getDatabasePathList().front(); - if (!path.empty()) + lod.setDatabasePath(path); + } + else + { + if (lod.getDatabasePath().empty() && fr.getOptions() && !fr.getOptions()->getDatabasePathList().empty()) { - lod.setDatabasePath(path); - } - } - + const std::string& path = fr.getOptions()->getDatabasePathList().front(); + if (!path.empty()) + { + lod.setDatabasePath(path); + } + } + } + unsigned int num; if (fr[0].matchWord("NumChildrenThatCannotBeExpired") && fr[1].getUInt(num)) { @@ -106,6 +114,12 @@ bool PagedLOD_writeLocalData(const Object& obj, Output& fw) { const PagedLOD& lod = static_cast(obj); + + if (!lod.getDatabasePath().empty()) + { + fw.indent() << "DatabasePath "< &, databaseRequest, Properties::PURE_VIRTUAL, - __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_FrameStamp_P1, + __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_FrameStamp_P1__osg_ref_ptrT1_osg_Referenced__R1, "", ""); END_REFLECTOR +BEGIN_VALUE_REFLECTOR(osg::ref_ptr< osg::Referenced >) + I_DeclaringFile("osg/ref_ptr"); + I_Constructor0(____ref_ptr, + "", + ""); + I_Constructor1(IN, osg::Referenced *, ptr, + Properties::NON_EXPLICIT, + ____ref_ptr__T_P1, + "", + ""); + I_Constructor1(IN, const osg::ref_ptr< osg::Referenced > &, rp, + Properties::NON_EXPLICIT, + ____ref_ptr__C5_ref_ptr_R1, + "", + ""); + I_Method0(osg::Referenced *, get, + Properties::NON_VIRTUAL, + __T_P1__get, + "", + ""); + I_Method0(bool, valid, + Properties::NON_VIRTUAL, + __bool__valid, + "", + ""); + I_Method0(osg::Referenced *, release, + Properties::NON_VIRTUAL, + __T_P1__release, + "", + ""); + I_Method1(void, swap, IN, osg::ref_ptr< osg::Referenced > &, rp, + Properties::NON_VIRTUAL, + __void__swap__ref_ptr_R1, + "", + ""); + I_SimpleProperty(osg::Referenced *, , + __T_P1__get, + 0); +END_REFLECTOR + diff --git a/src/osgWrappers/osg/PagedLOD.cpp b/src/osgWrappers/osg/PagedLOD.cpp index 0730b228d..dcfee54c2 100644 --- a/src/osgWrappers/osg/PagedLOD.cpp +++ b/src/osgWrappers/osg/PagedLOD.cpp @@ -16,6 +16,7 @@ #include #include #include +#include // Must undefine IN and OUT macros defined in Windows headers #ifdef IN @@ -162,6 +163,16 @@ BEGIN_OBJECT_REFLECTOR(osg::PagedLOD) __unsigned_int__getNumTimeStamps, "", ""); + I_Method1(osg::ref_ptr< osg::Referenced > &, getDatabaseRequest, IN, unsigned int, childNo, + Properties::NON_VIRTUAL, + __osg_ref_ptrT1_osg_Referenced__R1__getDatabaseRequest__unsigned_int, + "Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests being carried on behalf of the DatabasePager. ", + "Note, in normal OSG usage you should not set this value yourself, as this will be managed by the osgDB::DatabasePager. "); + I_Method1(const osg::ref_ptr< osg::Referenced > &, getDatabaseRequest, IN, unsigned int, childNo, + Properties::NON_VIRTUAL, + __C5_osg_ref_ptrT1_osg_Referenced__R1__getDatabaseRequest__unsigned_int, + "Return the const DatabaseRequest object. ", + ""); I_Method1(void, setFrameNumberOfLastTraversal, IN, int, frameNumber, Properties::NON_VIRTUAL, __void__setFrameNumberOfLastTraversal__int, @@ -246,6 +257,7 @@ BEGIN_VALUE_REFLECTOR(osg::PagedLOD::PerRangeData) I_PublicMemberProperty(float, _priorityOffset); I_PublicMemberProperty(float, _priorityScale); I_PublicMemberProperty(double, _timeStamp); + I_PublicMemberProperty(osg::ref_ptr< osg::Referenced >, _databaseRequest); END_REFLECTOR STD_VECTOR_REFLECTOR(std::vector< osg::PagedLOD::PerRangeData >) diff --git a/src/osgWrappers/osg/ProxyNode.cpp b/src/osgWrappers/osg/ProxyNode.cpp index 901b9ff83..7bcf470c9 100644 --- a/src/osgWrappers/osg/ProxyNode.cpp +++ b/src/osgWrappers/osg/ProxyNode.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include // Must undefine IN and OUT macros defined in Windows headers @@ -30,8 +31,6 @@ TYPE_NAME_ALIAS(osg::BoundingSphere::vec_type, osg::ProxyNode::vec_type) TYPE_NAME_ALIAS(osg::BoundingSphere::value_type, osg::ProxyNode::value_type) -TYPE_NAME_ALIAS(std::vector< std::string >, osg::ProxyNode::FileNameList) - BEGIN_ENUM_REFLECTOR(osg::ProxyNode::CenterMode) I_DeclaringFile("osg/ProxyNode"); I_EnumLabel(osg::ProxyNode::USE_BOUNDING_SPHERE_CENTER); @@ -130,6 +129,16 @@ BEGIN_OBJECT_REFLECTOR(osg::ProxyNode) __unsigned_int__getNumFileNames, "", ""); + I_Method1(osg::ref_ptr< osg::Referenced > &, getDatabaseRequest, IN, unsigned int, childNo, + Properties::NON_VIRTUAL, + __osg_ref_ptrT1_osg_Referenced__R1__getDatabaseRequest__unsigned_int, + "Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests being carried on behalf of the DatabasePager. ", + "Note, in normal OSG usage you should not set this value yourself, as this will be managed by the osgDB::DatabasePager. "); + I_Method1(const osg::ref_ptr< osg::Referenced > &, getDatabaseRequest, IN, unsigned int, childNo, + Properties::NON_VIRTUAL, + __C5_osg_ref_ptrT1_osg_Referenced__R1__getDatabaseRequest__unsigned_int, + "Return the const DatabaseRequest object. ", + ""); I_Method1(void, setCenterMode, IN, osg::ProxyNode::CenterMode, mode, Properties::NON_VIRTUAL, __void__setCenterMode__CenterMode, diff --git a/src/osgWrappers/osgDB/DatabasePager.cpp b/src/osgWrappers/osgDB/DatabasePager.cpp index 691ff9cbd..9d0bb9859 100644 --- a/src/osgWrappers/osgDB/DatabasePager.cpp +++ b/src/osgWrappers/osgDB/DatabasePager.cpp @@ -10,11 +10,13 @@ #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -54,7 +56,6 @@ END_REFLECTOR BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager) I_DeclaringFile("osgDB/DatabasePager"); I_BaseType(osg::NodeVisitor::DatabaseRequestHandler); - I_BaseType(OpenThreads::Thread); I_Constructor0(____DatabasePager, "", ""); @@ -68,31 +69,51 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager) __DatabasePager_P1__clone, "Create a shallow copy on the DatabasePager. ", ""); - I_Method4(void, requestNodeFile, IN, const std::string &, fileName, IN, osg::Group *, group, IN, float, priority, IN, const osg::FrameStamp *, framestamp, + I_Method5(void, requestNodeFile, IN, const std::string &, fileName, IN, osg::Group *, group, IN, float, priority, IN, const osg::FrameStamp *, framestamp, IN, osg::ref_ptr< osg::Referenced > &, databaseRequest, Properties::VIRTUAL, - __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_osg_FrameStamp_P1, + __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_osg_FrameStamp_P1__osg_ref_ptrT1_osg_Referenced__R1, "Add a request to load a node file to end the the database request list. ", ""); - I_Method5(void, requestNodeFile, IN, const std::string &, fileName, IN, osg::Group *, group, IN, float, priority, IN, const osg::FrameStamp *, framestamp, IN, osgDB::ReaderWriter::Options *, loadOptions, + I_Method6(void, requestNodeFile, IN, const std::string &, fileName, IN, osg::Group *, group, IN, float, priority, IN, const osg::FrameStamp *, framestamp, IN, osg::ref_ptr< osg::Referenced > &, databaseRequest, IN, osgDB::ReaderWriter::Options *, loadOptions, Properties::VIRTUAL, - __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_osg_FrameStamp_P1__ReaderWriter_Options_P1, + __void__requestNodeFile__C5_std_string_R1__osg_Group_P1__float__C5_osg_FrameStamp_P1__osg_ref_ptrT1_osg_Referenced__R1__ReaderWriter_Options_P1, "", ""); - I_Method0(void, run, - Properties::VIRTUAL, - __void__run, - "Run does the database paging. ", + I_Method1(int, setSchedulePriority, IN, OpenThreads::Thread::ThreadPriority, priority, + Properties::NON_VIRTUAL, + __int__setSchedulePriority__OpenThreads_Thread_ThreadPriority, + "Set the priority of the database pager thread(s). ", ""); I_Method0(int, cancel, Properties::VIRTUAL, __int__cancel, - "Cancel the database pager thread. ", + "Cancel the database pager thread(s). ", + ""); + I_Method0(bool, isRunning, + Properties::VIRTUAL, + __bool__isRunning, + "", ""); I_Method0(void, clear, Properties::VIRTUAL, __void__clear, "Clear all internally cached structures. ", ""); + I_Method1(osgDB::DatabasePager::DatabaseThread *, getDatabaseThread, IN, unsigned int, i, + Properties::NON_VIRTUAL, + __DatabaseThread_P1__getDatabaseThread__unsigned_int, + "", + ""); + I_Method1(const osgDB::DatabasePager::DatabaseThread *, getDatabaseThread, IN, unsigned int, i, + Properties::NON_VIRTUAL, + __C5_DatabaseThread_P1__getDatabaseThread__unsigned_int, + "", + ""); + I_Method0(unsigned int, getNumDatabaseThreads, + Properties::NON_VIRTUAL, + __unsigned_int__getNumDatabaseThreads, + "", + ""); I_Method1(void, setDatabasePagerThreadPause, IN, bool, pause, Properties::NON_VIRTUAL, __void__setDatabasePagerThreadPause__bool, @@ -301,12 +322,6 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager) __DatabasePager_P1__create_S, "create a DatabasePager by cloning DatabasePager::prototype(). ", ""); - I_ProtectedMethod0(void, updateDatabasePagerThreadBlock, - Properties::NON_VIRTUAL, - Properties::NON_CONST, - __void__updateDatabasePagerThreadBlock, - "", - ""); I_ProtectedMethod1(bool, isCompiled, IN, osg::Texture *, texture, Properties::NON_VIRTUAL, Properties::CONST, @@ -353,6 +368,13 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager) I_SimpleProperty(bool, DatabasePagerThreadPause, __bool__getDatabasePagerThreadPause, __void__setDatabasePagerThreadPause__bool); + I_ArrayProperty(osgDB::DatabasePager::DatabaseThread *, DatabaseThread, + __DatabaseThread_P1__getDatabaseThread__unsigned_int, + 0, + __unsigned_int__getNumDatabaseThreads, + 0, + 0, + 0); I_SimpleProperty(bool, DeleteRemovedSubgraphsInDatabaseThread, __bool__getDeleteRemovedSubgraphsInDatabaseThread, __void__setDeleteRemovedSubgraphsInDatabaseThread__bool); @@ -380,11 +402,58 @@ BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager) I_SimpleProperty(double, MinimumTimeToMergeTile, __double__getMinimumTimeToMergeTile, 0); + I_SimpleProperty(OpenThreads::Thread::ThreadPriority, SchedulePriority, + 0, + __int__setSchedulePriority__OpenThreads_Thread_ThreadPriority); I_SimpleProperty(double, TargetFrameRate, __double__getTargetFrameRate, __void__setTargetFrameRate__double); END_REFLECTOR +BEGIN_ENUM_REFLECTOR(osgDB::DatabasePager::DatabaseThread::Mode) + I_DeclaringFile("osgDB/DatabasePager"); + I_EnumLabel(osgDB::DatabasePager::DatabaseThread::HANDLE_ALL_REQUESTS); + I_EnumLabel(osgDB::DatabasePager::DatabaseThread::HANDLE_NON_HTTP); + I_EnumLabel(osgDB::DatabasePager::DatabaseThread::HANDLE_ONLY_HTTP); +END_REFLECTOR + +BEGIN_OBJECT_REFLECTOR(osgDB::DatabasePager::DatabaseThread) + I_DeclaringFile("osgDB/DatabasePager"); + I_BaseType(osg::Referenced); + I_BaseType(OpenThreads::Thread); + I_Constructor3(IN, osgDB::DatabasePager *, pager, IN, osgDB::DatabasePager::DatabaseThread::Mode, mode, IN, const std::string &, name, + ____DatabaseThread__DatabasePager_P1__Mode__C5_std_string_R1, + "", + ""); + I_Constructor2(IN, const osgDB::DatabasePager::DatabaseThread &, dt, IN, osgDB::DatabasePager *, pager, + ____DatabaseThread__C5_DatabaseThread_R1__DatabasePager_P1, + "", + ""); + I_Method1(void, setDone, IN, bool, done, + Properties::NON_VIRTUAL, + __void__setDone__bool, + "", + ""); + I_Method0(bool, getDone, + Properties::NON_VIRTUAL, + __bool__getDone, + "", + ""); + I_Method0(int, cancel, + Properties::VIRTUAL, + __int__cancel, + "Cancel the thread. ", + "Equivalent to SIGKILL.0 if normal, -1 if errno set, errno code otherwise. "); + I_Method0(void, run, + Properties::VIRTUAL, + __void__run, + "Thread's run method. ", + "Must be implemented by derived classes. This is where the action happens. "); + I_SimpleProperty(bool, Done, + __bool__getDone, + __void__setDone__bool); +END_REFLECTOR + BEGIN_OBJECT_REFLECTOR(osg::observer_ptr< osg::GraphicsContext >) I_DeclaringFile("osg/observer_ptr"); I_BaseType(osg::Observer); diff --git a/src/osgWrappers/osgDB/ReaderWriter.cpp b/src/osgWrappers/osgDB/ReaderWriter.cpp index 051c023a8..a1dca549b 100644 --- a/src/osgWrappers/osgDB/ReaderWriter.cpp +++ b/src/osgWrappers/osgDB/ReaderWriter.cpp @@ -273,16 +273,6 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter::Options) __CacheHintOptions__getObjectCacheHint, "Get whether the Registry::ObjectCache should be used by default. ", ""); - I_Method1(void, setAsynchronousFileReadHint, IN, bool, flag, - Properties::NON_VIRTUAL, - __void__setAsynchronousFileReadHint__bool, - "Set Asynchrnous file read hint. ", - "This hint is used by plugins like the libcurl http reader plugin to inform them that they should make an internal file read requests to their background threads to load files, with the plugin returning immediately with a ReadResult::FILE_REQUESTED status. It is assumed that calls will continue to be made to the plugin until the background threads have read or failed to read the request file, at which point the return status which change to FILE_LOADED and the objects will be returned. Note, this facility is particular useful when using DatabasePager in conjunction with internet based databases where file load latency is relatively high. "); - I_Method0(bool, getAsynchronousFileReadHint, - Properties::NON_VIRTUAL, - __bool__getAsynchronousFileReadHint, - "Get Asynchrnous file read hint. ", - ""); I_Method2(void, setPluginData, IN, const std::string &, s, IN, void *, v, Properties::NON_VIRTUAL, __void__setPluginData__C5_std_string_R1__void_P1, @@ -303,9 +293,6 @@ BEGIN_OBJECT_REFLECTOR(osgDB::ReaderWriter::Options) __void__removePluginData__C5_std_string_R1, "Remove a value from the PluginData. ", ""); - I_SimpleProperty(bool, AsynchronousFileReadHint, - __bool__getAsynchronousFileReadHint, - __void__setAsynchronousFileReadHint__bool); I_SimpleProperty(const std::string &, DatabasePath, 0, __void__setDatabasePath__C5_std_string_R1);