From a56e397313022fdbd68bd950c33c672c36c8f685 Mon Sep 17 00:00:00 2001 From: Larry Gritz Date: Sun, 6 Jan 2019 14:46:49 -0800 Subject: [PATCH] IC/TS: add optional `force` argument to `invalidate()` method This works the same way as the `force` argument to `invalidate_all()` -- if true, invalidates unconditionally; if false, invalidates only if the file's modifiation date has changes since the cache first opened it. The default is true for back compatibility, but probably you will often want `false`, only invalidating if the file has changed. --- src/doc/imagecache.tex | 6 +++++- src/doc/texturesys.tex | 6 +++++- src/include/OpenImageIO/imagecache.h | 11 +++++++++-- src/include/OpenImageIO/texture.h | 5 ++++- src/libtexture/imagecache.cpp | 15 ++++++++++++--- src/libtexture/imagecache_pvt.h | 2 +- src/libtexture/texture_pvt.h | 2 +- src/libtexture/texturesys.cpp | 4 ++-- src/oiiotool/oiiotool.cpp | 4 ++-- src/python/py_imagecache.cpp | 6 +++--- 10 files changed, 44 insertions(+), 17 deletions(-) diff --git a/src/doc/imagecache.tex b/src/doc/imagecache.tex index 540a70af42..f47ffdad9f 100644 --- a/src/doc/imagecache.tex +++ b/src/doc/imagecache.tex @@ -844,7 +844,7 @@ \subsection{Dealing with tiles} {\cf get_tile()} but has not yet been released with {\cf release_tile()}. \apiend -\apiitem{void {\ce invalidate} (ustring filename)} +\apiitem{void {\ce invalidate} (ustring filename, bool force=true)} Invalidate any loaded tiles or open file handles associated with the filename, so that any subsequent queries will be forced to re-open the file or re-load any tiles (even those that were @@ -855,6 +855,10 @@ \subsection{Dealing with tiles} reference-counted tile pointers from the named image, but those procedures will not get updated pixels until they release the tiles they are holding. + +If {\cf force} is true, this invalidation will happen unconditionally; if +false, the file will only be invalidated if it has been changed since it was +first opened by the ImageCache. \apiend \apiitem{void {\ce invalidate_all} (bool force=false)} diff --git a/src/doc/texturesys.tex b/src/doc/texturesys.tex index d2ef0ccb9c..ef3d293e24 100644 --- a/src/doc/texturesys.tex +++ b/src/doc/texturesys.tex @@ -1334,7 +1334,7 @@ \section{Miscellaneous -- Statistics, errors, flushing the cache} would have resulted from a new \ImageCache. \apiend -\apiitem{void {\ce invalidate} (ustring filename)} +\apiitem{void {\ce invalidate} (ustring filename, bool force=true)} Invalidate any loaded tiles or open file handles associated with the filename, so that any subsequent queries will be forced to re-open the file or re-load any tiles (even those that were @@ -1345,6 +1345,10 @@ \section{Miscellaneous -- Statistics, errors, flushing the cache} reference-counted tile pointers from the named image, but those procedures will not get updated pixels until they release the tiles they are holding. + +If {\cf force} is true, this invalidation will happen unconditionally; if +false, the file will only be invalidated if it has been changed since it was +first opened by the ImageCache. \apiend \apiitem{void {\ce invalidate_all} (bool force=false)} diff --git a/src/include/OpenImageIO/imagecache.h b/src/include/OpenImageIO/imagecache.h index bfcb0b89fb..09f73c9b41 100644 --- a/src/include/OpenImageIO/imagecache.h +++ b/src/include/OpenImageIO/imagecache.h @@ -43,8 +43,13 @@ // Define symbols that let client applications determine if newly added // features are supported. + +// Is the close() method present? #define OIIO_IMAGECACHE_SUPPORTS_CLOSE 1 +// Does invalidate() support the optional `force` flag? +#define OIIO_IMAGECACHE_INVALIDATE_FORCE 1 + OIIO_NAMESPACE_BEGIN @@ -394,8 +399,10 @@ class OIIO_API ImageCache { /// to do even if other procedures are currently holding /// reference-counted tile pointers from the named image, but those /// procedures will not get updated pixels until they release the - /// tiles they are holding. - virtual void invalidate(ustring filename) = 0; + /// tiles they are holding. If `force` is true, this invalidation will + /// happen unconditionally; if false, the file will only be invalidated + /// if it has been changed since it was first opened by the ImageCache. + virtual void invalidate(ustring filename, bool force = true) = 0; /// Invalidate all loaded tiles and open file handles. This is safe /// to do even if other procedures are currently holding diff --git a/src/include/OpenImageIO/texture.h b/src/include/OpenImageIO/texture.h index 4eca9a8570..663eb769a1 100644 --- a/src/include/OpenImageIO/texture.h +++ b/src/include/OpenImageIO/texture.h @@ -892,7 +892,10 @@ class OIIO_API TextureSystem { /// Invalidate any cached information about the named file. A client /// might do this if, for example, they are aware that an image /// being held in the cache has been updated on disk. - virtual void invalidate (ustring filename) = 0; + /// If force is true, this invalidation will happen unconditionally; if + /// false, the file will only be invalidated if it has been changed + /// since it was first opened by the underlying image cache. + virtual void invalidate (ustring filename, bool force = true) = 0; /// Invalidate all cached data for all textures. If force is true, /// everything will be invalidated, no matter how wasteful it is, diff --git a/src/libtexture/imagecache.cpp b/src/libtexture/imagecache.cpp index 8e972a0aaf..1e953c5fad 100644 --- a/src/libtexture/imagecache.cpp +++ b/src/libtexture/imagecache.cpp @@ -1203,7 +1203,7 @@ ImageCacheImpl::find_file(ustring filename, } m_files.unlock_bin(bin); if (replace && found) { - invalidate(filename); + invalidate(filename, true); tf->reset(creator, config); } @@ -3211,7 +3211,7 @@ ImageCacheImpl::add_tile(ustring filename, int subimage, int miplevel, int x, void -ImageCacheImpl::invalidate(ustring filename) +ImageCacheImpl::invalidate(ustring filename, bool force) { ImageCacheFile* file = NULL; { @@ -3222,6 +3222,15 @@ ImageCacheImpl::invalidate(ustring filename) return; // no such file } + if (!force) { + // If not in force mode, we don't do anything if the modification + // time of the file has not changed since we opened it. + recursive_lock_guard guard(file->m_input_mutex); + if (file->mod_time() == Filesystem::last_write_time(filename.string()) + && !file->broken()) + return; + } + // Iterate over the entire tilecache, record the TileID's of all // tiles that are from the file we are invalidating. std::vector tiles_to_delete; @@ -3331,7 +3340,7 @@ ImageCacheImpl::invalidate_all(bool force) // Now, invalidate all the files in our "needs invalidation" list for (auto f : all_files) { // fprintf (stderr, "Invalidating %s\n", f.c_str()); - invalidate(f); + invalidate(f, force); } // Mark the per-thread microcaches as invalid diff --git a/src/libtexture/imagecache_pvt.h b/src/libtexture/imagecache_pvt.h index c39d8ac051..26f2962a26 100644 --- a/src/libtexture/imagecache_pvt.h +++ b/src/libtexture/imagecache_pvt.h @@ -1015,7 +1015,7 @@ class ImageCacheImpl : public ImageCache { virtual std::string geterror() const; virtual std::string getstats(int level = 1) const; virtual void reset_stats(); - virtual void invalidate(ustring filename); + virtual void invalidate(ustring filename, bool force); virtual void invalidate_all(bool force = false); virtual void close(ustring filename); virtual void close_all(); diff --git a/src/libtexture/texture_pvt.h b/src/libtexture/texture_pvt.h index 869f9f7895..4cbe966ec0 100644 --- a/src/libtexture/texture_pvt.h +++ b/src/libtexture/texture_pvt.h @@ -354,7 +354,7 @@ class TextureSystemImpl : public TextureSystem { virtual std::string getstats(int level = 1, bool icstats = true) const; virtual void reset_stats(); - virtual void invalidate(ustring filename); + virtual void invalidate(ustring filename, bool force); virtual void invalidate_all(bool force = false); virtual void close(ustring filename); virtual void close_all(); diff --git a/src/libtexture/texturesys.cpp b/src/libtexture/texturesys.cpp index f99ae006f5..0ad736d839 100644 --- a/src/libtexture/texturesys.cpp +++ b/src/libtexture/texturesys.cpp @@ -822,9 +822,9 @@ TextureSystemImpl::append_error(const std::string& message) const // Implementation of invalidate -- just invalidate the image cache. void -TextureSystemImpl::invalidate(ustring filename) +TextureSystemImpl::invalidate(ustring filename, bool force) { - m_imagecache->invalidate(filename); + m_imagecache->invalidate(filename, force); } diff --git a/src/oiiotool/oiiotool.cpp b/src/oiiotool/oiiotool.cpp index a30cfd9ad9..195f571256 100644 --- a/src/oiiotool/oiiotool.cpp +++ b/src/oiiotool/oiiotool.cpp @@ -4572,7 +4572,7 @@ input_file(int argc, const char* argv[]) // User has set some input configuration, so seed the cache with // that information. ustring fn(filename); - ot.imagecache->invalidate(fn); + ot.imagecache->invalidate(fn, true); bool ok = ot.imagecache->add_file(fn, nullptr, &ot.input_config); if (!ok) { std::string err = ot.imagecache->geterror(); @@ -5141,7 +5141,7 @@ output_file(int argc, const char* argv[]) // Make sure to invalidate any IC entries that think they are the // file we just wrote. - ot.imagecache->invalidate(ustring(filename)); + ot.imagecache->invalidate(ustring(filename), true); if (ot.output_adjust_time && ok) { std::string metadatatime = ir->spec(0, 0)->get_string_attribute( diff --git a/src/python/py_imagecache.cpp b/src/python/py_imagecache.cpp index 30f1f804bc..9c4f93b329 100644 --- a/src/python/py_imagecache.cpp +++ b/src/python/py_imagecache.cpp @@ -153,11 +153,11 @@ declare_imagecache(py::module& m) }, "level"_a = 1) .def("invalidate", - [](ImageCacheWrap& ic, const std::string& filename) { + [](ImageCacheWrap& ic, const std::string& filename, bool force) { py::gil_scoped_release gil; - ic.m_cache->invalidate(ustring(filename)); + ic.m_cache->invalidate(ustring(filename), force); }, - "filename"_a) + "filename"_a, "force"_a = true) .def("invalidate_all", [](ImageCacheWrap& ic, bool force) { py::gil_scoped_release gil;