HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_AgentFileCache.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_AgentFileCache.h (GU Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __GU_AgentFileCache__
12 #define __GU_AgentFileCache__
13 
14 #include "GU_API.h"
15 
16 #include <FS/FS_Info.h>
18 #include <UT/UT_IntrusivePtr.h>
19 #include <UT/UT_WorkBuffer.h>
20 
21 template <typename T>
23 {
24 public:
25  /// Searches for a cached file with the same key, and returns it if the
26  /// timestamp matches the file on disk. Otherwise, the callback is invoked
27  /// to load the file, which is then inserted into the cache and returned.
28  /// The key should include the filename and any dependencies on other agent
29  /// files (e.g. when loading the same clip for slightly different rigs).
30  template <typename F>
32  const UT_StringRef &key,
33  F load_new_item);
34 
35  /// Removes a cached file with the given key.
36  void removeCachedFile(const UT_StringRef &key);
37 
38 private:
39  struct CachedFile
40  {
41  CachedFile(T *ptr = nullptr, time_t mod_time = 0)
42  : myPtr(ptr), myModTime(mod_time)
43  {
44  }
45 
46  /// Since we hold a raw pointer and expect the item's destructor to
47  /// remove itself from this cache, there is a small time window where
48  /// another thread could access this cache and add a reference after
49  /// the count has already gone to 0 and triggered the destructor,
50  /// resulting in a dangling pointer being returned.
51  /// So, we only allow adding a reference if the ref count is not
52  /// already 0 - this is the same idea as a weak_ptr::lock().
53  ///
54  /// Returns nullptr if a reference could not be added because this item
55  /// is pending deletion.
56  UT_IntrusivePtr<T> tryGetItem() const
57  {
58  UT_IntrusivePtr<T> ref(myPtr, /* add_ref */ false);
59  if (!ref->conditionalAddRef())
60  ref.detach(); // Reset without decrementing, since we never incremented.
61 
62  return ref;
63  }
64 
65  time_t getModTime() const { return myModTime; }
66 
67  private:
68  T *myPtr;
69  time_t myModTime;
70  };
71 
72  using CachedFileMap = UT_ConcurrentHashMap<UT_StringHolder, CachedFile>;
73  CachedFileMap myFiles;
74 };
75 
76 /// Builds a list of paths to use when attempting to load an external file,
77 /// ordered by priority.
78 GU_API extern void GUgetAgentFilePaths(UT_StringArray &paths,
79  const UT_StringHolder &condensed_path,
80  const UT_StringHolder &expanded_path);
81 
82 template <typename T>
83 template <typename F>
84 inline UT_IntrusivePtr<T>
86  const UT_StringRef &key,
87  F load_new_item)
88 {
89  FS_Info info(filename);
90  time_t mod_time = 0;
91  if (info.hasAccess())
92  mod_time = info.getModTime();
93 
94  // First, do a quick check to see if there's a valid entry.
95  UT_IntrusivePtr<T> item;
96  {
97  typename CachedFileMap::const_accessor acc;
98  if (myFiles.find(acc, UTmakeUnsafeRef(key)) &&
99  acc->second.getModTime() == mod_time &&
100  (item = acc->second.tryGetItem()))
101  {
102  return item;
103  }
104  }
105 
106  typename CachedFileMap::accessor acc;
107  if (myFiles.insert(acc, key) || acc->second.getModTime() != mod_time
108  || !(item = acc->second.tryGetItem()))
109  {
110  // If the item was not in the cache or is out of date, load it.
111  auto new_item = load_new_item();
112  if (new_item)
113  acc->second = CachedFile(new_item.get(), mod_time);
114  else
115  {
116  // If the item failed to load, remove the empty entry from the map.
117  // Note that this erasure might also happen at the same time from
118  // removeCachedFile() but that's ok.
119  (void) myFiles.erase(acc);
120  }
121 
122  return new_item;
123  }
124  else
125  {
126  UT_ASSERT_P(item);
127  return item;
128  }
129 }
130 
131 template <typename T>
132 inline void
134 {
135  myFiles.erase(key);
136 }
137 
138 #endif
GT_API const UT_StringHolder filename
bool hasAccess(int mode=0) const
GU_API void GUgetAgentFilePaths(UT_StringArray &paths, const UT_StringHolder &condensed_path, const UT_StringHolder &expanded_path)
void
Definition: png.h:1083
GLint ref
Definition: glcorearb.h:124
#define UT_ASSERT_P(ZZ)
Definition: UT_Assert.h:155
SYS_FORCE_INLINE const UT_StringHolder & UTmakeUnsafeRef(const UT_StringRef &ref)
Convert a UT_StringRef into a UT_StringHolder that is a shallow reference.
void removeCachedFile(const UT_StringRef &key)
Removes a cached file with the given key.
Wrapper around hboost::intrusive_ptr.
#define GU_API
Definition: GU_API.h:14
UT_IntrusivePtr< T > findCachedFileOrLoad(const UT_StringRef &filename, const UT_StringRef &key, F load_new_item)
time_t getModTime() const
auto ptr(T p) -> const void *
Definition: format.h:2448
Class for retrieving file information.
Definition: FS_Info.h:99