Changeset 8325

Show
Ignore:
Timestamp:
05/21/08 23:09:45
Author:
robert
Message:

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.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • OpenSceneGraph/trunk/include/osg/NodeVisitor

    r7731 r8325  
    269269                Referenced(true) {} 
    270270         
    271             virtual void requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const FrameStamp* framestamp) = 0; 
     271            virtual void requestNodeFile(const std::string& fileName,osg::Group* group, float priority, const FrameStamp* framestamp, osg::ref_ptr<osg::Referenced>& databaseRequest) = 0; 
    272272             
    273273        protected: 
  • OpenSceneGraph/trunk/include/osg/PagedLOD

    r5328 r8325  
    5959            PerRangeData& operator = (const PerRangeData& prd); 
    6060 
    61             std::string _filename; 
    62             float       _priorityOffset; 
    63             float       _priorityScale; 
    64             double      _timeStamp; 
     61            std::string                     _filename; 
     62            float                           _priorityOffset; 
     63            float                           _priorityScale; 
     64            double                          _timeStamp; 
     65            osg::ref_ptr<osg::Referenced>   _databaseRequest; 
    6566        }; 
    6667 
     
    8485        double getTimeStamp(unsigned int childNo) const { return _perRangeDataList[childNo]._timeStamp; } 
    8586        unsigned int getNumTimeStamps() const { return _perRangeDataList.size(); } 
     87 
     88 
     89        /** Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests  
     90          * being carried on behalf of the DatabasePager. 
     91          * Note, in normal OSG usage you should not set this value yourself, as this will be managed by  
     92          * the osgDB::DatabasePager.*/ 
     93        osg::ref_ptr<osg::Referenced>& getDatabaseRequest(unsigned int childNo) { return _perRangeDataList[childNo]._databaseRequest; } 
     94         
     95        /** Return the const DatabaseRequest object.*/  
     96        const osg::ref_ptr<osg::Referenced>& getDatabaseRequest(unsigned int childNo) const { return _perRangeDataList[childNo]._databaseRequest; } 
    8697 
    8798 
  • OpenSceneGraph/trunk/include/osg/ProxyNode

    r8038 r8325  
    4747        inline const std::string& getDatabasePath() const { return _databasePath; } 
    4848 
    49         typedef std::vector<std::string> FileNameList; 
     49        void setFileName(unsigned int childNo, const std::string& filename) { expandFileNameListTo(childNo); _filenameList[childNo].first=filename; } 
     50        const std::string& getFileName(unsigned int childNo) const { return _filenameList[childNo].first; } 
     51        unsigned int getNumFileNames() const { return _filenameList.size(); } 
     52 
     53        /** Return the DatabaseRequest object used by the DatabasePager to keep track of file load requests  
     54          * being carried on behalf of the DatabasePager. 
     55          * Note, in normal OSG usage you should not set this value yourself, as this will be managed by  
     56          * the osgDB::DatabasePager.*/ 
     57        osg::ref_ptr<osg::Referenced>& getDatabaseRequest(unsigned int childNo) { return _filenameList[childNo].second; } 
    5058         
    51         void setFileName(unsigned int childNo, const std::string& filename) { expandFileNameListTo(childNo); _filenameList[childNo]=filename; } 
    52         const std::string& getFileName(unsigned int childNo) const { return _filenameList[childNo]; } 
    53         unsigned int getNumFileNames() const { return _filenameList.size(); } 
     59        /** Return the const DatabaseRequest object.*/  
     60        const osg::ref_ptr<osg::Referenced>& getDatabaseRequest(unsigned int childNo) const { return _filenameList[childNo].second; } 
     61 
    5462 
    5563        /** Modes which control how the center of object should be determined when computed which child is active.*/ 
     
    103111        void expandFileNameListTo(unsigned int pos); 
    104112 
    105         FileNameList        _filenameList; 
    106         std::string         _databasePath; 
     113        typedef std::pair< std::string, osg::ref_ptr<osg::Referenced> >  FileNameDatabaseRequestPair; 
     114        typedef std::vector<FileNameDatabaseRequestPair>                 FileNameDatabaseRequestList; 
     115 
     116        FileNameDatabaseRequestList     _filenameList; 
     117        std::string                     _databasePath; 
    107118         
    108         LoadingExternalReferenceMode _loadingExtReference; 
     119        LoadingExternalReferenceMode    _loadingExtReference; 
    109120         
    110         CenterMode          _centerMode; 
    111         vec_type            _userDefinedCenter; 
    112         value_type          _radius; 
     121        CenterMode                      _centerMode; 
     122        vec_type                        _userDefinedCenter; 
     123        value_type                      _radius; 
    113124         
    114125}; 
  • OpenSceneGraph/trunk/include/osgDB/DatabasePager

    r8007 r8325  
    3838 
    3939 
     40 
    4041/** Database paging class which manages the loading of files in a background thread,  
    4142  * and synchronizing of loaded models with the main scene graph.*/ 
    42 class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler, public OpenThreads::Thread 
     43class OSGDB_EXPORT DatabasePager : public osg::NodeVisitor::DatabaseRequestHandler 
    4344{ 
    4445    public : 
     
    6364        /** Add a request to load a node file to end the the database request list.*/ 
    6465        virtual void requestNodeFile(const std::string& fileName,osg::Group* group, 
    65                                      float priority, const osg::FrameStamp* framestamp); 
     66                                     float priority, const osg::FrameStamp* framestamp, 
     67                                     osg::ref_ptr<osg::Referenced>& databaseRequest); 
    6668 
    6769        virtual void requestNodeFile(const std::string& fileName,osg::Group* group, 
    6870                                     float priority, const osg::FrameStamp* framestamp, 
     71                                     osg::ref_ptr<osg::Referenced>& databaseRequest, 
    6972                                     ReaderWriter::Options* loadOptions); 
    7073 
    71         /** Run does the database paging.*/         
    72         virtual void run(); 
    73          
    74         /** Cancel the database pager thread.*/         
     74        /** Set the priority of the database pager thread(s).*/ 
     75        int setSchedulePriority(OpenThreads::Thread::ThreadPriority priority); 
     76 
     77        /** Cancel the database pager thread(s).*/         
    7578        virtual int cancel(); 
     79         
     80        virtual bool isRunning() const; 
    7681         
    7782        /** Clear all internally cached structures.*/ 
    7883        virtual void clear(); 
     84         
     85        class DatabaseThread : public osg::Referenced, public OpenThreads::Thread 
     86        { 
     87        public: 
     88         
     89            enum Mode 
     90            { 
     91                HANDLE_ALL_REQUESTS, 
     92                HANDLE_NON_HTTP, 
     93                HANDLE_ONLY_HTTP 
     94            }; 
     95         
     96            DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name); 
     97             
     98            DatabaseThread(const DatabaseThread& dt, DatabasePager* pager); 
     99             
     100            void setDone(bool done) { _done = done; } 
     101            bool getDone() const { return _done; } 
     102 
     103            virtual int cancel(); 
     104             
     105            virtual void run(); 
     106             
     107        protected: 
     108 
     109            virtual ~DatabaseThread(); 
     110         
     111            bool            _done; 
     112            DatabasePager*  _pager; 
     113            Mode            _mode; 
     114            std::string     _name; 
     115        }; 
     116 
     117        DatabaseThread* getDatabaseThread(unsigned int i) { return _databaseThreads[i].get(); } 
     118         
     119        const DatabaseThread* getDatabaseThread(unsigned int i) const { return _databaseThreads[i].get(); } 
     120 
     121        unsigned int getNumDatabaseThreads() const { return _databaseThreads.size(); } 
    79122         
    80123        /** Set whether the database pager thread should be paused or not.*/ 
     
    233276 
    234277        /** Report how many items are in the _fileRequestList queue */ 
    235         unsigned int getFileRequestListSize() const { return _fileRequestList.size(); } 
     278        unsigned int getFileRequestListSize() const { return _fileRequestQueue._requestList.size() + _httpRequestQueue._requestList.size(); } 
    236279 
    237280        /** Report how many items are in the _dataToCompileList queue */ 
     
    264307        virtual ~DatabasePager(); 
    265308 
     309        friend class DatabaseThread; 
     310 
    266311 
    267312        friend struct DatabaseRequest; 
     
    270315        { 
    271316            DatabaseRequest(): 
     317                osg::Referenced(true), 
     318                _frameNumberFirstRequest(0), 
     319                _timestampFirstRequest(0.0), 
     320                _priorityFirstRequest(0.f), 
     321                _frameNumberLastRequest(0), 
     322                _timestampLastRequest(0.0), 
     323                _priorityLastRequest(0.0f), 
    272324                _numOfRequests(0) 
    273325            {} 
     
    291343            } 
    292344        }; 
    293  
    294         typedef std::vector< osg::ref_ptr<DatabaseRequest> > DatabaseRequestList; 
     345         
     346        typedef std::vector< osg::ref_ptr<DatabaseThread> > DatabaseThreadList; 
     347        typedef std::list< osg::ref_ptr<DatabaseRequest> > DatabaseRequestList; 
    295348        typedef std::vector<  osg::ref_ptr<osg::Object> > ObjectList; 
     349 
     350        struct RequestQueue : public osg::Referenced 
     351        { 
     352            RequestQueue(DatabasePager* pager, const std::string& name); 
     353             
     354            void block() { _block->block(); } 
     355             
     356            void release() { _block->release(); } 
     357             
     358            void updateBlock() 
     359            { 
     360                _block->set((!_requestList.empty() || !_childrenToDeleteList.empty()) &&  
     361                             !_pager->_databasePagerThreadPaused); 
     362            } 
     363             
     364            void clear(); 
     365             
     366            void add(DatabaseRequest* databaseRequest); 
     367             
     368            void takeFirst(osg::ref_ptr<DatabaseRequest>& databaseRequest); 
     369             
     370            osg::ref_ptr<osg::RefBlock> _block; 
     371             
     372            DatabasePager*              _pager; 
     373            std::string                 _name; 
     374             
     375            OpenThreads::Mutex          _requestMutex; 
     376            DatabaseRequestList         _requestList; 
     377             
     378            OpenThreads::Mutex          _childrenToDeleteListMutex; 
     379            ObjectList                  _childrenToDeleteList; 
     380        }; 
    296381 
    297382        // forward declare inner helper classes 
     
    310395        OpenThreads::Mutex              _run_mutex; 
    311396        bool                            _startThreadCalled; 
    312  
    313          
    314         osg::ref_ptr<osg::RefBlock>    _databasePagerThreadBlock; 
    315  
    316         inline void updateDatabasePagerThreadBlock() 
    317         { 
    318             _databasePagerThreadBlock->set( 
    319                 (!_fileRequestList.empty() || !_childrenToDeleteList.empty()) && !_databasePagerThreadPaused); 
    320         } 
    321397 
    322398        // Helper functions for determining if objects need to be 
     
    411487        bool                            _databasePagerThreadPaused; 
    412488     
     489        DatabaseThreadList              _databaseThreads; 
     490 
    413491        int                             _numFramesActive; 
    414492        mutable OpenThreads::Mutex      _numFramesActiveMutex; 
    415493        int                             _frameNumber; 
    416494 
    417         DatabaseRequestList             _fileRequestList; 
    418         mutable OpenThreads::Mutex      _fileRequestListMutex; 
     495        RequestQueue                    _fileRequestQueue; 
     496        RequestQueue                    _httpRequestQueue; 
     497 
     498        //DatabaseRequestList             _fileRequestList; 
     499        //mutable OpenThreads::Mutex      _fileRequestListMutex; 
    419500         
    420501        DatabaseRequestList             _dataToCompileList; 
     
    429510 
    430511        bool                            _deleteRemovedSubgraphsInDatabaseThread; 
    431         ObjectList                      _childrenToDeleteList; 
    432         mutable OpenThreads::Mutex      _childrenToDeleteListMutex; 
     512        //ObjectList                      _childrenToDeleteList; 
     513        //mutable OpenThreads::Mutex      _childrenToDeleteListMutex; 
    433514 
    434515        DatabaseRequestList             _dataToMergeList; 
     
    452533        unsigned int                    _numTilesMerges; 
    453534         
    454          
    455535        struct CompileOperation : public osg::GraphicsOperation 
    456536        { 
  • OpenSceneGraph/trunk/include/osgDB/ReaderWriter

    r8322 r8325  
    9191                Options(): 
    9292                    osg::Object(true), 
    93                     _objectCacheHint(CACHE_ARCHIVES), 
    94                     _asynchronousFileReadHint(false) {} 
     93                    _objectCacheHint(CACHE_ARCHIVES) {} 
    9594                     
    9695                Options(const std::string& str): 
    9796                    osg::Object(true), 
    9897                    _str(str),  
    99                     _objectCacheHint(CACHE_ARCHIVES), 
    100                     _asynchronousFileReadHint(false) {} 
     98                    _objectCacheHint(CACHE_ARCHIVES) {} 
    10199                 
    102100                Options(const Options& options,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY): 
     
    104102                    _str(options._str), 
    105103                    _databasePaths(options._databasePaths), 
    106                     _objectCacheHint(options._objectCacheHint), 
    107                     _asynchronousFileReadHint(options._asynchronousFileReadHint) {} 
     104                    _objectCacheHint(options._objectCacheHint) {} 
    108105 
    109106                META_Object(osgDB,Options); 
     
    130127                /** Get whether the Registry::ObjectCache should be used by default.*/ 
    131128                CacheHintOptions getObjectCacheHint() const { return _objectCacheHint; } 
    132  
    133  
    134                 /** Set Asynchrnous file read hint.  
    135                   * This hint is used by plugins like the libcurl http reader plugin to inform them that 
    136                   * they should make an internal file read requests to their background threads to load files, 
    137                   * with the plugin returning immediately with a ReadResult::FILE_REQUESTED status.  It is  
    138                   * assumed that calls will continue to be made to the plugin until the background threads 
    139                   * have read or failed to read the request file, at which point the return status which change 
    140                   * to FILE_LOADED and the objects will be returned. 
    141                   * Note, this facility is particular useful when using DatabasePager in conjunction with 
    142                   * internet based databases where file load latency is relatively high.*/ 
    143                 void setAsynchronousFileReadHint(bool flag) { _asynchronousFileReadHint = flag; } 
    144  
    145                 /** Get Asynchrnous file read hint. */ 
    146                 bool getAsynchronousFileReadHint() const { return _asynchronousFileReadHint; } 
    147129 
    148130 
     
    170152                FilePathList        _databasePaths; 
    171153                CacheHintOptions    _objectCacheHint; 
    172                 bool                _asynchronousFileReadHint; 
    173154 
    174155                typedef std::map<std::string,void*> PluginDataMap; 
  • OpenSceneGraph/trunk/src/osg/PagedLOD.cpp

    r7343 r8325  
    2929    _priorityOffset(prd._priorityOffset), 
    3030    _priorityScale(prd._priorityScale), 
    31     _timeStamp(prd._timeStamp) {} 
     31    _timeStamp(prd._timeStamp), 
     32    _databaseRequest(prd._databaseRequest) {} 
    3233 
    3334PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData& prd) 
     
    3839    _priorityScale = prd._priorityScale; 
    3940    _timeStamp = prd._timeStamp; 
     41    _databaseRequest = prd._databaseRequest; 
    4042    return *this; 
    4143} 
     
    189191                    if (_databasePath.empty()) 
    190192                    { 
    191                         nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); 
     193                        nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest); 
    192194                    } 
    193195                    else 
    194196                    { 
    195197                        // prepend the databasePath to the child's filename. 
    196                         nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); 
     198                        nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest); 
    197199                    } 
    198200                } 
  • OpenSceneGraph/trunk/src/osg/ProxyNode.cpp

    r7881 r8325  
    6363        for(unsigned int i=_children.size(); i<_filenameList.size(); ++i) 
    6464        { 
    65             nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_filenameList[i], this, 1.0f, nv.getFrameStamp()); 
     65            nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_filenameList[i].first, this, 1.0f, nv.getFrameStamp(), _filenameList[i].second); 
    6666        } 
    6767    } 
  • OpenSceneGraph/trunk/src/osgDB/DatabasePager.cpp

    r8322 r8325  
    11#include <osgDB/DatabasePager> 
    22#include <osgDB/ReadFile> 
     3#include <osgDB/WriteFile> 
    34#include <osgDB/FileNameUtils> 
     5#include <osgDB/FileUtils> 
    46 
    57#include <osg/Geode> 
     
    79#include <osg/Texture> 
    810#include <osg/Notify> 
     11#include <osg/ProxyNode> 
    912#include <osg/ApplicationUsage> 
    1013 
     
    8184} 
    8285 
    83 DatabasePager::DatabasePager() 
    84 
    85     //osg::notify(osg::INFO)<<"Constructing DatabasePager()"<<std::endl; 
    86      
    87     _startThreadCalled = false; 
    88  
    89     _done = false; 
    90     _acceptNewRequests = true; 
    91     _databasePagerThreadPaused = false; 
    92      
    93     _numFramesActive = 0; 
    94     _frameNumber = 0; 
    95     _databasePagerThreadBlock = new osg::RefBlock; 
    96      
    97     const char* str = getenv("OSG_DATABASE_PAGER_PRIORITY"); 
    98     if (str) 
    99     { 
    100         if (strcmp(str,"DEFAULT")==0) 
    101         { 
    102             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_DEFAULT); 
    103         } 
    104         else if (strcmp(str,"MIN")==0) 
    105         { 
    106             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MIN); 
    107         } 
    108         else if (strcmp(str,"LOW")==0) 
    109         { 
    110             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_LOW); 
    111         } 
    112         else if (strcmp(str,"NOMINAL")==0) 
    113         { 
    114             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_NOMINAL); 
    115         } 
    116         else if (strcmp(str,"HIGH")==0) 
    117         { 
    118             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_HIGH); 
    119         }  
    120         else if (strcmp(str,"MAX")==0) 
    121         { 
    122             setSchedulePriority(OpenThreads::Thread::THREAD_PRIORITY_MAX); 
    123         }  
    124     } 
    125  
    126 #if __APPLE__ 
    127     // OSX really doesn't like compiling display lists, and performs poorly when they are used, 
    128     // so apply this hack to make up for its short comings. 
    129     _drawablePolicy = USE_VERTEX_ARRAYS; 
    130 #else 
    131     _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS; 
    132 #endif     
    133      
    134     str = getenv("OSG_DATABASE_PAGER_GEOMETRY"); 
    135     if (!str) str = getenv("OSG_DATABASE_PAGER_DRAWABLE"); 
    136     if (str) 
    137     { 
    138         if (strcmp(str,"DoNotModify")==0) 
    139         { 
    140             _drawablePolicy = DO_NOT_MODIFY_DRAWABLE_SETTINGS; 
    141         } 
    142         else if (strcmp(str,"DisplayList")==0 || strcmp(str,"DL")==0) 
    143         { 
    144             _drawablePolicy = USE_DISPLAY_LISTS; 
    145         } 
    146         else if (strcmp(str,"VBO")==0) 
    147         { 
    148             _drawablePolicy = USE_VERTEX_BUFFER_OBJECTS; 
    149         } 
    150         else if (strcmp(str,"VertexArrays")==0 || strcmp(str,"VA")==0 ) 
    151         { 
    152             _drawablePolicy = USE_VERTEX_ARRAYS; 
    153         }  
    154     } 
    155  
    156     _changeAutoUnRef = true; 
    157     _valueAutoUnRef = true; 
    158     _changeAnisotropy = false; 
    159     _valueAnisotropy = 1.0f; 
    160  
    161  
    162      
    163     const char* ptr=0; 
    164  
    165     _deleteRemovedSubgraphsInDatabaseThread = true; 
    166     if( (ptr = getenv("OSG_DELETE_IN_DATABASE_THREAD")) != 0) 
    167     { 
    168         _deleteRemovedSubgraphsInDatabaseThread = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 || 
    169                         strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0; 
    170  
    171     } 
    172  
    173     _expiryDelay = 10.0; 
    174     if( (ptr = getenv("OSG_EXPIRY_DELAY")) != 0) 
    175     { 
    176         _expiryDelay = atof(ptr); 
    177         osg::notify(osg::NOTICE)<<"Expiry delay = "<<_expiryDelay<<std::endl; 
    178     } 
    179  
    180     _doPreCompile = true; 
    181     if( (ptr = getenv("OSG_DO_PRE_COMPILE")) != 0) 
    182     { 
    183         _doPreCompile = strcmp(ptr,"yes")==0 || strcmp(ptr,"YES")==0 || 
    184                         strcmp(ptr,"on")==0 || strcmp(ptr,"ON")==0; 
    185     } 
    186  
    187     _targetFrameRate = 100.0; 
    188     _minimumTimeAvailableForGLCompileAndDeletePerFrame = 0.001; // 1ms. 
    189     _maximumNumOfObjectsToCompilePerFrame = 4; 
    190     if( (ptr = getenv("OSG_MINIMUM_COMPILE_TIME_PER_FRAME")) != 0) 
    191     { 
    192         _minimumTimeAvailableForGLCompileAndDeletePerFrame = atof(ptr); 
    193     } 
    194  
    195     if( (ptr = getenv("OSG_MAXIMUM_OBJECTS_TO_COMPILE_PER_FRAME")) != 0) 
    196     { 
    197         _maximumNumOfObjectsToCompilePerFrame = atoi(ptr); 
    198     } 
    199  
    200     // initialize the stats variables 
    201     resetStats(); 
    202  
    203     // make sure a SharedStateManager exists. 
    204     //osgDB::Registry::instance()->getOrCreateSharedStateManager(); 
    205      
    206     //if (osgDB::Registry::instance()->getSharedStateManager()) 
    207         //osgDB::Registry::instance()->setUseObjectCacheHint(true); 
    208 
    209  
    210 DatabasePager::DatabasePager(const DatabasePager& rhs) 
    211 
    212     //osg::notify(osg::INFO)<<"Constructing DatabasePager(const DatabasePager& )"<<std::endl; 
    213      
    214     _startThreadCalled = false; 
    215  
    216     _done = false; 
    217     _acceptNewRequests = true; 
    218     _databasePagerThreadPaused = false; 
    219      
    220     _numFramesActive = 0; 
    221     _frameNumber = 0; 
    222     _databasePagerThreadBlock = new osg::RefBlock; 
    223  
    224     _drawablePolicy = rhs._drawablePolicy; 
    225  
    226     _changeAutoUnRef = rhs._changeAutoUnRef; 
    227     _valueAutoUnRef = rhs._valueAutoUnRef; 
    228     _changeAnisotropy = rhs._changeAnisotropy; 
    229     _valueAnisotropy = rhs._valueAnisotropy; 
    230  
    231  
    232     _deleteRemovedSubgraphsInDatabaseThread = rhs._deleteRemovedSubgraphsInDatabaseThread; 
    233      
    234     _expiryDelay = rhs._expiryDelay; 
    235     _doPreCompile = rhs._doPreCompile; 
    236     _targetFrameRate = rhs._targetFrameRate; 
    237     _minimumTimeAvailableForGLCompileAndDeletePerFrame = rhs._minimumTimeAvailableForGLCompileAndDeletePerFrame; 
    238     _maximumNumOfObjectsToCompilePerFrame = rhs._maximumNumOfObjectsToCompilePerFrame; 
    239  
    240     // initialize the stats variables 
    241     resetStats(); 
    242 
    243  
    244  
    245 DatabasePager::~DatabasePager() 
    246 
    247     cancel(); 
    248 
    249  
    250 osg::ref_ptr<DatabasePager>& DatabasePager::prototype() 
    251 
    252     static osg::ref_ptr<DatabasePager> s_DatabasePager = new DatabasePager; 
    253     return s_DatabasePager; 
    254 
    255  
    256 DatabasePager* DatabasePager::create() 
    257 
    258     return DatabasePager::prototype().valid() ?  
    259            DatabasePager::prototype()->clone() : 
    260            new DatabasePager;  
    261 
    262  
    263  
    264 int DatabasePager::cancel() 
    265 
    266     int result = 0; 
    267     if( isRunning() ) 
    268     { 
    269      
    270         _done = true; 
    271  
    272         // cancel the thread.. 
    273         // result = Thread::cancel(); 
    274         //join(); 
    275  
    276         // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. 
    277         _databasePagerThreadBlock->release(); 
    278  
    279         // then wait for the the thread to stop running. 
    280         while(isRunning()) 
    281         { 
    282             // commenting out debug info as it was cashing crash on exit, presumable 
    283             // due to osg::notify or std::cout destructing earlier than this destructor. 
    284             // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<<std::endl; 
    285             OpenThreads::Thread::YieldCurrentThread(); 
    286         } 
    287          
    288         _startThreadCalled = false; 
    289     } 
    290     //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl; 
    291     return result; 
    292 
    293  
    294 void DatabasePager::clear() 
    295 
    296     { 
    297         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex); 
    298         _fileRequestList.clear(); 
    299     } 
    300  
    301     { 
    302         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex); 
    303         _dataToCompileList.clear(); 
    304     } 
    305  
    306     { 
    307         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_childrenToDeleteListMutex); 
    308         _childrenToDeleteList.clear(); 
    309     } 
    310      
    311     { 
    312         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex); 
    313         _dataToMergeList.clear(); 
    314     } 
    315  
    316     // note, no need to use a mutex as the list is only accessed from the update thread. 
    317     _pagedLODList.clear(); 
    318  
    319     // ?? 
    320     // _activeGraphicsContexts 
    321 
    322  
    323 void DatabasePager::resetStats() 
    324 
    325     // initialize the stats variables 
    326     _minimumTimeToMergeTile = DBL_MAX; 
    327     _maximumTimeToMergeTile = -DBL_MAX; 
    328     _totalTimeToMergeTiles = 0.0; 
    329     _numTilesMerges = 0; 
    330 
    331  
    332 void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, 
    333                                     float priority, const osg::FrameStamp* framestamp) 
    334 
    335     requestNodeFile(fileName,group,priority,framestamp,Registry::instance()->getOptions()); 
    336 
    337  
    338 void DatabasePager::requestNodeFile(const std::string& fileName,osg::Group* group, 
    339                                     float priority, const osg::FrameStamp* framestamp, 
    340                                     ReaderWriter::Options* loadOptions) 
    341 
    342     if (!_acceptNewRequests) return; 
    343     
    344     double timestamp = framestamp?framestamp->getReferenceTime():0.0; 
    345     int frameNumber = framestamp?framestamp->getFrameNumber():_frameNumber; 
    346     
    347     // search to see if filename already exist in the file loaded list. 
    348     bool foundEntry = false; 
    349  
    350     { 
    351         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToCompileListMutex); 
    352      
    353         for(DatabaseRequestList::iterator litr = _dataToCompileList.begin(); 
    354             litr != _dataToCompileList.end() && !foundEntry; 
    355             ++litr) 
    356         { 
    357             if ((*litr)->_fileName==fileName) 
    358             { 
    359                 foundEntry = true; 
    360                 (*litr)->_frameNumberLastRequest = frameNumber; 
    361                 (*litr)->_timestampLastRequest = timestamp; 
    362                 (*litr)->_priorityLastRequest = priority; 
    363                 ++((*litr)->_numOfRequests); 
    364             } 
    365         }         
    366  
    367     } 
    368  
    369     if (!foundEntry) 
    370     { 
    371         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_dataToMergeListMutex); 
    372  
    373         for(DatabaseRequestList::iterator litr = _dataToMergeList.begin(); 
    374             litr != _dataToMergeList.end() && !foundEntry; 
    375             ++litr) 
    376         { 
    377             if ((*litr)->_fileName==fileName) 
    378             { 
    379                 foundEntry = true; 
    380                 (*litr)->_frameNumberLastRequest = frameNumber; 
    381                 (*litr)->_timestampLastRequest = timestamp; 
    382                 (*litr)->_priorityLastRequest = priority; 
    383                 ++((*litr)->_numOfRequests); 
    384             } 
    385         }         
    386     } 
    387      
    388     if (!foundEntry) 
    389     { 
    390      
    391         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_fileRequestListMutex); 
    392  
    393         // search to see if entry already  in file request list. 
    394         bool foundEntry = false; 
    395         for(DatabaseRequestList::iterator ritr = _fileRequestList.begin(); 
    396             ritr != _fileRequestList.end() && !foundEntry; 
    397             ++ritr) 
    398         { 
    399             if ((*ritr)->_fileName==fileName) 
    400             { 
    401                 foundEntry = true; 
    402                 (*ritr)->_timestampLastRequest = timestamp; 
    403                 (*ritr)->_priorityLastRequest = priority; 
    404                 (*ritr)->_frameNumberLastRequest = frameNumber; 
    405                 ++((*ritr)->_numOfRequests); 
    406             } 
    407         }         
    408  
    409         if (!foundEntry) 
    410         { 
    411             osg::notify(osg::INFO)<<"In DatabasePager::fileRquest("<<fileName<<")"<<std::endl; 
    412  
    413             osg::ref_ptr<DatabaseRequest> databaseRequest = new DatabaseRequest; 
    414  
    415             databaseRequest->_fileName = fileName; 
    416             databaseRequest->_frameNumberFirstRequest = frameNumber; 
    417             databaseRequest->_timestampFirstRequest = timestamp; 
    418             databaseRequest->_priorityFirstRequest = priority; 
    419             databaseRequest->_frameNumberLastRequest = frameNumber; 
    420             databaseRequest->_timestampLastRequest = timestamp; 
    421             databaseRequest->_priorityLastRequest = priority; 
    422             databaseRequest->_groupForAddingLoadedSubgraph = group; 
    423  
    424             if ((Registry::instance()->getOptions()==loadOptions) && 
    425                 (loadOptions ? !loadOptions->getAsynchronousFileReadHint() : true) && 
    426                 osgDB::containsServerAddress(fileName)) 
    427             { 
    428                 // we need to enable asynchronous file reading. 
    429                 databaseRequest->_loadOptions = loadOptions ?  
    430                         dynamic_cast<osgDB::ReaderWriter::Options*>(loadOptions->clone(osg::CopyOp::SHALLOW_COPY)) : 
    431                         new osgDB::ReaderWriter::Options; 
    432  
    433                 databaseRequest->_loadOptions->setAsynchronousFileReadHint(true); 
    434             } 
    435             else 
    436             { 
    437                 databaseRequest->_loadOptions = loadOptions; 
    438             } 
    439  
    440             _fileRequestList.push_back(databaseRequest); 
    441  
    442             updateDatabasePagerThreadBlock(); 
    443         } 
    444     } 
    445      
    446     if (!isRunning()) 
    447     { 
    448         OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex); 
    449          
    450         if (!_startThreadCalled) 
    451         { 
    452             _startThreadCalled = true; 
    453             _done = false; 
    454             osg::notify(osg::DEBUG_INFO)<<"DatabasePager::startThread()"<<std::endl; 
    455             startThread(); 
    456         } 
    457     } 
    458 
    459  
    460 void DatabasePager::signalBeginFrame(const osg::FrameStamp* framestamp) 
    461 
    462     if (framestamp) 
    463     { 
    464         //osg::notify(osg::INFO) << "signalBeginFrame "<<framestamp->getFrameNumber()<<">>>>>>>>>>>>>>>>"<<std::endl; 
    465         _frameNumber = framestamp->getFrameNumber(); 
    466          
    467     } //else osg::notify(osg::INFO) << "signalBeginFrame >>>>>>>>>>>>>>>>"<<std::endl; 
    468 
    469  
    470 void DatabasePager::signalEndFrame() 
    471 
    472     //osg::notify(osg::INFO) << "signalEndFrame <<<<<<<<<<<<<<<<<<<< "<<std::endl; 
    473 
    474  
     86///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     87// 
     88//  SortFileRequestFunctor 
     89// 
     90struct DatabasePager::SortFileRequestFunctor 
     91
     92    bool operator() (const osg::ref_ptr<DatabasePager::DatabaseRequest>& lhs,const osg::ref_ptr<DatabasePager::DatabaseRequest>& rhs) const 
     93    { 
     94        if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; 
     95        else if (lhs->_timestampLastRequest<rhs->_timestampLastRequest) return false; 
     96        else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); 
     97    } 
     98}; 
     99 
     100///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     101// 
     102//  FindCompileableGLObjectsVisitor 
     103// 
    475104class DatabasePager::FindCompileableGLObjectsVisitor : public osg::NodeVisitor 
    476105{ 
     
    608237 
    609238 
    610 struct DatabasePager::SortFileRequestFunctor 
    611 
    612     bool operator() (const osg::ref_ptr<DatabasePager::DatabaseRequest>& lhs,const osg::ref_ptr<DatabasePager::DatabaseRequest>& rhs) const 
    613     { 
    614         if (lhs->_timestampLastRequest>rhs->_timestampLastRequest) return true; 
    615         else if (lhs->_timestampLastRequest<rhs->_timestampLastRequest) return false; 
    616         else return (lhs->_priorityLastRequest>rhs->_priorityLastRequest); 
    617     } 
    618 }; 
    619  
    620  
    621 void DatabasePager::setDatabasePagerThreadPause(bool pause) 
    622 
    623     _databasePagerThreadPaused = pause; 
    624     updateDatabasePagerThreadBlock(); 
    625 
    626  
    627 void DatabasePager::run() 
    628 
    629     osg::notify(osg::INFO)<<"DatabasePager::run()"<<std::endl; 
    630  
     239///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     240// 
     241//  RequestQueue 
     242// 
     243DatabasePager::RequestQueue::RequestQueue(DatabasePager* pager, const std::string& name): 
     244    _pager(pager), 
     245    _name(name) 
     246
     247    _block = new osg::RefBlock; 
     248
     249 
     250void DatabasePager::RequestQueue::clear() 
     251
     252    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex); 
     253    _requestList.clear(); 
     254 
     255    updateBlock(); 
     256
     257 
     258void DatabasePager::RequestQueue::add(DatabasePager::DatabaseRequest* databaseRequest) 
     259
     260    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex); 
     261    _requestList.push_back(databaseRequest); 
     262 
     263    updateBlock(); 
     264
     265 
     266void DatabasePager::RequestQueue::takeFirst(osg::ref_ptr<DatabaseRequest>& databaseRequest) 
     267
     268    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex); 
     269 
     270    if (!_requestList.empty()) 
     271    { 
     272        _requestList.sort(SortFileRequestFunctor()); 
     273        databaseRequest = _requestList.front(); 
     274        _requestList.erase(_requestList.begin()); 
     275    } 
     276
     277 
     278///////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
     279// 
     280//  DatabaseThread 
     281// 
     282DatabasePager::DatabaseThread::DatabaseThread(DatabasePager* pager, Mode mode, const std::string& name): 
     283    _done(false), 
     284    _pager(pager), 
     285    _mode(mode), 
     286    _name(name) 
     287
     288
     289 
     290DatabasePager::DatabaseThread::DatabaseThread(const DatabaseThread& dt, DatabasePager* pager): 
     291    _done(false), 
     292    _pager(pager), 
     293    _mode(dt._mode), 
     294    _name(dt._name) 
     295
     296     
     297
     298 
     299DatabasePager::DatabaseThread::~DatabaseThread() 
     300
     301    cancel(); 
     302
     303 
     304int DatabasePager::DatabaseThread::cancel() 
     305
     306    int result = 0; 
     307 
     308    if( isRunning() ) 
     309    { 
     310     
     311        _done = true; 
     312 
     313        // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation. 
     314        // _databasePagerThreadBlock->release(); 
     315 
     316        // then wait for the the thread to stop running. 
     317        while(isRunning()) 
     318        { 
     319            // commenting out debug info as it was cashing crash on exit, presumable 
     320            // due to osg::notify or std::cout destructing earlier than this destructor. 
     321            // osg::notify(osg::DEBUG_INFO)<<"Waiting for DatabasePager to cancel"<&l