Browse Source

implement cache-check-timestamps for models

David Rose 14 years ago
parent
commit
ec81b415a5
2 changed files with 79 additions and 16 deletions
  1. 21 13
      panda/src/pgraph/modelPool.I
  2. 58 3
      panda/src/pgraph/modelPool.cxx

+ 21 - 13
panda/src/pgraph/modelPool.I

@@ -30,9 +30,15 @@ has_model(const Filename &filename) {
 //  Description: Loads the given filename up as a model, if it has
 //  Description: Loads the given filename up as a model, if it has
 //               not already been loaded, and returns true to indicate
 //               not already been loaded, and returns true to indicate
 //               success, or false to indicate failure.  If this
 //               success, or false to indicate failure.  If this
-//               returns true, it is guaranteed that a subsequent call
+//               returns true, it is probable that a subsequent call
 //               to load_model() with the same model name will
 //               to load_model() with the same model name will
-//               return a valid Node pointer.
+//               return a valid PandaNode.
+//
+//               However, even if this returns true, it is still
+//               possible for a subsequent call to load_model() to
+//               fail.  This can happen if cache-check-timestamps is
+//               true, and the on-disk file is subsequently modified
+//               to replace it with an invalid model.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool ModelPool::
 INLINE bool ModelPool::
 verify_model(const Filename &filename) {
 verify_model(const Filename &filename) {
@@ -45,8 +51,11 @@ verify_model(const Filename &filename) {
 //  Description: Loads the given filename up as a model, if it has
 //  Description: Loads the given filename up as a model, if it has
 //               not already been loaded, and returns the new model.
 //               not already been loaded, and returns the new model.
 //               If a model with the same filename was previously
 //               If a model with the same filename was previously
-//               loaded, returns that one instead.  If the model
-//               file cannot be found, returns NULL.
+//               loaded, returns that one instead (unless
+//               cache-check-timestamps is true and the file has
+//               recently changed).  If the model file cannot be
+//               found, or cannot be loaded for some reason, returns
+//               NULL.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE ModelRoot *ModelPool::
 INLINE ModelRoot *ModelPool::
 load_model(const Filename &filename, const LoaderOptions &options) {
 load_model(const Filename &filename, const LoaderOptions &options) {
@@ -57,9 +66,8 @@ load_model(const Filename &filename, const LoaderOptions &options) {
 //     Function: ModelPool::add_model
 //     Function: ModelPool::add_model
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description: Adds the indicated already-loaded model to the
 //  Description: Adds the indicated already-loaded model to the
-//               pool.  The model will always replace any
-//               previously-loaded model in the pool that had the
-//               same filename.
+//               pool.  The model will replace any previously-loaded
+//               model in the pool that had the same filename.
 //
 //
 //               This two-parameter version of this method is
 //               This two-parameter version of this method is
 //               deprecated; use the one-parameter add_model(model)
 //               deprecated; use the one-parameter add_model(model)
@@ -91,9 +99,8 @@ release_model(const Filename &filename) {
 //     Function: ModelPool::add_model
 //     Function: ModelPool::add_model
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description: Adds the indicated already-loaded model to the
 //  Description: Adds the indicated already-loaded model to the
-//               pool.  The model will always replace any
-//               previously-loaded model in the pool that had the
-//               same filename.
+//               pool.  The model will replace any previously-loaded
+//               model in the pool that had the same filename.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void ModelPool::
 INLINE void ModelPool::
 add_model(ModelRoot *model) {
 add_model(ModelRoot *model) {
@@ -105,9 +112,10 @@ add_model(ModelRoot *model) {
 //       Access: Public, Static
 //       Access: Public, Static
 //  Description: Removes the indicated model from the pool,
 //  Description: Removes the indicated model from the pool,
 //               indicating it will never be loaded again; the model
 //               indicating it will never be loaded again; the model
-//               may then be freed.  If this function is never called,
-//               a reference count will be maintained on every model
-//               every loaded, and models will never be freed.
+//               may then be freed.  If this function (and
+//               garbage_collect()) is never called, a reference count
+//               will be maintained on every model every loaded, and
+//               models will never be freed.
 //
 //
 //               The model's get_fullpath() value should not have been
 //               The model's get_fullpath() value should not have been
 //               changed during its lifetime, or this function may
 //               changed during its lifetime, or this function may

+ 58 - 3
panda/src/pgraph/modelPool.cxx

@@ -57,16 +57,67 @@ ns_has_model(const Filename &filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 ModelRoot *ModelPool::
 ModelRoot *ModelPool::
 ns_load_model(const Filename &filename, const LoaderOptions &options) {
 ns_load_model(const Filename &filename, const LoaderOptions &options) {
+  VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
+
+  PT(ModelRoot) cached_model;
+  bool got_cached_model = false;
+
   {
   {
     LightMutexHolder holder(_lock);
     LightMutexHolder holder(_lock);
     Models::const_iterator ti;
     Models::const_iterator ti;
     ti = _models.find(filename);
     ti = _models.find(filename);
     if (ti != _models.end()) {
     if (ti != _models.end()) {
-      // This model was previously loaded.
-      return (*ti).second;
+      // This filename was previously loaded.
+      cached_model = (*ti).second;
+      got_cached_model = true;
+    }
+  }
+
+  if (got_cached_model) {
+    if (pgraph_cat.is_debug()) {
+      pgraph_cat.debug()
+        << "ModelPool found " << cached_model << " for " << filename << "\n";
+    }
+
+    if (cached_model == NULL) {
+      // This filename was previously attempted, but it did not
+      // exist (or the model could not be loaded for some reason).
+      if (cache_check_timestamps) {
+        // Check to see if there is a file there now.
+        if (vfs->exists(filename)) {
+          // There is, so try to load it.
+          got_cached_model = false;
+        }
+      }
+    } else {
+      // This filename was previously attempted, and successfully
+      // loaded.
+      if (cache_check_timestamps && cached_model->get_timestamp() != 0 && 
+          !cached_model->get_fullpath().empty()) {
+        // Compare the timestamp to the file on-disk.
+        PT(VirtualFile) vfile = vfs->get_file(cached_model->get_fullpath());
+        if (vfile == NULL) {
+          // The file has disappeared!  Look further along the model-path.
+          got_cached_model = false;
+
+        } else if (vfile->get_timestamp() > cached_model->get_timestamp()) {
+          // The file still exists, but it has a newer timestamp than
+          // the one we previously loaded.  Force it to re-load.
+          got_cached_model = false;
+        }
+      }
     }
     }
   }
   }
 
 
+  if (got_cached_model) {
+    if (pgraph_cat.is_debug()) {
+      pgraph_cat.debug()
+        << "ModelPool returning " << cached_model << " for " << filename << "\n";
+    }
+    return cached_model;
+  }
+
+  // Look on disk for the current file.
   LoaderOptions new_options(options);
   LoaderOptions new_options(options);
   new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) &
   new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) &
                         ~(LoaderOptions::LF_search | LoaderOptions::LF_report_errors));
                         ~(LoaderOptions::LF_search | LoaderOptions::LF_report_errors));
@@ -97,11 +148,15 @@ ns_load_model(const Filename &filename, const LoaderOptions &options) {
     // another thread.
     // another thread.
     Models::const_iterator ti;
     Models::const_iterator ti;
     ti = _models.find(filename);
     ti = _models.find(filename);
-    if (ti != _models.end()) {
+    if (ti != _models.end() && (*ti).second != cached_model) {
       // This model was previously loaded.
       // This model was previously loaded.
       return (*ti).second;
       return (*ti).second;
     }
     }
 
 
+    if (pgraph_cat.is_debug()) {
+      pgraph_cat.debug()
+        << "ModelPool storing " << node << " for " << filename << "\n";
+    }
     _models[filename] = node;
     _models[filename] = node;
   }
   }