From ec81b415a57a49921f4598148bf96492e00312d5 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 26 Feb 2012 03:02:57 +0000 Subject: [PATCH] implement cache-check-timestamps for models --- panda/src/pgraph/modelPool.I | 34 +++++++++++-------- panda/src/pgraph/modelPool.cxx | 61 ++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 16 deletions(-) diff --git a/panda/src/pgraph/modelPool.I b/panda/src/pgraph/modelPool.I index f0b80ea2d7..18e4fadf48 100644 --- a/panda/src/pgraph/modelPool.I +++ b/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 // not already been loaded, and returns true to indicate // 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 -// 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:: 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 // not already been loaded, and returns the new model. // 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:: load_model(const Filename &filename, const LoaderOptions &options) { @@ -57,9 +66,8 @@ load_model(const Filename &filename, const LoaderOptions &options) { // Function: ModelPool::add_model // Access: Public, Static // 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 // deprecated; use the one-parameter add_model(model) @@ -91,9 +99,8 @@ release_model(const Filename &filename) { // Function: ModelPool::add_model // Access: Public, Static // 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:: add_model(ModelRoot *model) { @@ -105,9 +112,10 @@ add_model(ModelRoot *model) { // Access: Public, Static // Description: Removes the indicated model from the pool, // 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 // changed during its lifetime, or this function may diff --git a/panda/src/pgraph/modelPool.cxx b/panda/src/pgraph/modelPool.cxx index 64009e1f6b..4b57720794 100644 --- a/panda/src/pgraph/modelPool.cxx +++ b/panda/src/pgraph/modelPool.cxx @@ -57,16 +57,67 @@ ns_has_model(const Filename &filename) { //////////////////////////////////////////////////////////////////// ModelRoot *ModelPool:: 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); Models::const_iterator ti; ti = _models.find(filename); 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); new_options.set_flags((new_options.get_flags() | LoaderOptions::LF_no_ram_cache) & ~(LoaderOptions::LF_search | LoaderOptions::LF_report_errors)); @@ -97,11 +148,15 @@ ns_load_model(const Filename &filename, const LoaderOptions &options) { // another thread. Models::const_iterator ti; ti = _models.find(filename); - if (ti != _models.end()) { + if (ti != _models.end() && (*ti).second != cached_model) { // This model was previously loaded. return (*ti).second; } + if (pgraph_cat.is_debug()) { + pgraph_cat.debug() + << "ModelPool storing " << node << " for " << filename << "\n"; + } _models[filename] = node; }