2020
2121PXR_NAMESPACE_OPEN_SCOPE
2222
23+ // Forward declarations
24+ template <typename VALUE>
25+ class HdInstanceRegistry ;
26+
27+ using HdInstanceKey = uint64_t ;
28+ using HdInstanceRegistryMutex = std::mutex;
29+ using HdInstanceRegistryLock = std::unique_lock<HdInstanceRegistryMutex>;
2330
2431// / \class HdInstance
2532// /
26- // / This class is used as an interface to a shared instance in
27- // / HdInstanceRegistry .
33+ // / This class is used as an interface to a shared instance stored in
34+ // / a REGISTRY object .
2835// /
29- // / KeyType is a hashable index type and VALUE is shared_ptr. In most use
30- // / cases, the client computes a hash key which represents large bulky data
31- // / (like topology, primvars) and registers it into HdInstanceRegistry . If the
32- // / key has already been registered, the registry returns HdInstance and the
36+ // / HdInstanceKeyType is a hashable index type and VALUE is shared_ptr. In most
37+ // / use cases, the client computes a hash key which represents large bulky data
38+ // / (like topology, primvars) and registers it into REGISTRY . If the
39+ // / key has already been registered, the registry returns an HdInstance and the
3340// / client can use GetValue() without setting/computing actual bulky data. If
3441// / it doesn't exist, IsFirstInstance() returns true for the first instance
3542// / and the client needs to populate an appropriate data VALUE into the
3643// / instance by SetValue().
3744// /
38- // / In order to support concurrent access to HdInstanceRegistry , this
39- // / class holds a lock to a mutex in HdInstanceRegistry . This lock will
45+ // / In order to support concurrent access to REGISTRY , this
46+ // / class holds a lock to a mutex in REGISTRY . This lock will
4047// / be held until the instance of this interface class is destroyed.
4148// /
42- template <typename VALUE>
49+ template <typename VALUE, class REGISTRY = HdInstanceRegistry<VALUE> >
4350class HdInstance {
4451public:
45- typedef uint64_t KeyType;
4652 typedef VALUE ValueType;
47-
48- typedef KeyType ID;
53+ typedef HdInstanceKey ID;
4954
5055 struct ValueHolder {
5156 ValueHolder (ValueType const & value = ValueType())
@@ -59,46 +64,44 @@ class HdInstance {
5964 ValueType value;
6065 int recycleCounter;
6166 };
62- typedef tbb::concurrent_unordered_map<KeyType, ValueHolder> Dictionary;
63-
64- typedef std::mutex RegistryMutex;
65- typedef std::unique_lock<RegistryMutex> RegistryLock;
6667
6768 HdInstance () = delete ;
6869
6970 // / Construct an instance holding a registry lock, representing a value
7071 // / held in a registry container.
71- explicit HdInstance (KeyType const & key,
72- ValueType const &value,
73- RegistryLock &®istryLock,
74- Dictionary *container )
72+ explicit HdInstance (HdInstanceKey key,
73+ ValueType const &value,
74+ HdInstanceRegistryLock &®istryLock,
75+ REGISTRY *registry )
7576 : _key(key)
7677 , _value(value)
7778 , _registryLock(std::move(registryLock))
78- , _container(container )
79+ , _registry(registry )
7980 , _isFirstInstance(!bool (_value))
8081 { }
8182
8283 // / Construct an instance with no lock or registry container. This
8384 // / is used to present a consistent interface to clients in cases
8485 // / where shared resource registration is disabled.
85- explicit HdInstance (KeyType const & key)
86+ explicit HdInstance (HdInstanceKey key)
8687 : _key(key)
8788 , _value(ValueType())
8889 , _registryLock()
89- , _container (nullptr )
90+ , _registry (nullptr )
9091 , _isFirstInstance(!bool (_value))
9192 { }
9293
9394 // / Returns the key
94- KeyType const & GetKey () const { return _key; }
95+ HdInstanceKey GetKey () const { return _key; }
9596
9697 // / Returns the value
9798 ValueType const &GetValue () const { return _value; }
9899
99- // / Update the value in dictionary indexed by the key.
100+ // / Update the value in the registry
100101 void SetValue (ValueType const &value) {
101- if (_container) (*_container)[_key] = ValueHolder (value);
102+ if (_registry) {
103+ _registry->_SetValue (_key, value);
104+ }
102105 _value = value;
103106 }
104107
@@ -108,45 +111,55 @@ class HdInstance {
108111 }
109112
110113private:
111- KeyType _key;
112- ValueType _value;
113- RegistryLock _registryLock;
114- Dictionary *_container ;
115- bool _isFirstInstance;
114+ HdInstanceKey _key;
115+ ValueType _value;
116+ HdInstanceRegistryLock _registryLock;
117+ REGISTRY *_registry = nullptr ;
118+ bool _isFirstInstance;
116119};
117120
118- // / \class HdInstanceRegistry
121+ // / \class HdInstanceRegistryBase
119122// /
120- // / HdInstanceRegistry is a dictionary container of HdInstance.
121- // / This class is almost just a dictionary from key to value.
122- // / For cleaning unused entries, it provides GarbageCollect() API.
123- // / It sweeps all entries in the dictionary and erase unreferenced entries.
123+ // / HdInstanceRegistryBase is a dictionary container of HdInstance.
124+ // / This class is mostly just a dictionary from key to value, ensuring
125+ // / thread-safe access to the values.
126+ // / The DERIVED template parameter can be used in a Curiously Recurring
127+ // / Template Pattern to extend this class with a persistent cache backing the
128+ // / in-memory dictionary.
129+ // / For cleaning up unused entries, the GarbageCollect() API is provided.
130+ // / It sweeps all entries in the dictionary and erases unreferenced entries.
124131// / When HdInstance::ValueType is shared_ptr, it is regarded as unreferenced
125132// / if the shared_ptr is unique (use_count==1). Note that Key is not
126133// / involved to determine the lifetime of entries.
127134// /
128- template <typename VALUE>
129- class HdInstanceRegistry {
135+ template <typename VALUE, class DERIVED >
136+ class HdInstanceRegistryBase {
130137public:
131- typedef HdInstance<VALUE> InstanceType;
132-
133- HdInstanceRegistry () = default ;
138+ friend class HdInstance <VALUE, DERIVED>;
139+ using InstanceType = HdInstance<VALUE, DERIVED>;
134140
135- // / Copy constructor. Need as HdInstanceRegistry is placed in a map
136- // / and mutex is not copy constructable, so can't use default
137- HdInstanceRegistry (const HdInstanceRegistry &other)
141+ using Dictionary = tbb::concurrent_unordered_map<
142+ HdInstanceKey,
143+ typename InstanceType::ValueHolder
144+ >;
145+
146+ HdInstanceRegistryBase () = default ;
147+
148+ // / Copy constructor. Need as HdInstanceRegistryBase is placed in a map
149+ // / and mutex is not copy-constructible, so can't use default
150+ HdInstanceRegistryBase (const HdInstanceRegistryBase &other)
138151 : _dictionary(other._dictionary)
139- , _registryMutex () // mutex is not copied
152+ , _mutex () // mutex is not copied
140153 { }
141154
142- // / Returns a shared instance for given key.
155+ // / Returns a shared instance for a given key.
143156 InstanceType GetInstance (
144- typename InstanceType::KeyType const & key);
157+ HdInstanceKey key);
145158
146159 // / Returns a shared instance for a given key
147160 // / only if the key exists in the dictionary.
148161 InstanceType FindInstance (
149- typename InstanceType::KeyType const & key, bool *found);
162+ HdInstanceKey key, bool *found);
150163
151164 // / Removes unreferenced entries and returns the count
152165 // / of remaining entries. When recycleCount is greater than zero,
@@ -166,7 +179,7 @@ class HdInstanceRegistry {
166179
167180 // / Returns a const iterator being/end of dictionary. Mainly used for
168181 // / resource auditing.
169- typedef typename InstanceType:: Dictionary::const_iterator const_iterator;
182+ typedef typename Dictionary::const_iterator const_iterator;
170183 const_iterator begin () const { return _dictionary.begin (); }
171184 const_iterator end () const { return _dictionary.end (); }
172185
@@ -180,73 +193,142 @@ class HdInstanceRegistry {
180193 return value.use_count () == 1 ;
181194 }
182195
183- typename InstanceType::Dictionary _dictionary;
184- typename InstanceType::RegistryMutex _registryMutex;
196+ // / Store the value in the in-memory dictionary and write it to the
197+ // / persistent cache if implemented by the derived class.
198+ void _SetValue (
199+ HdInstanceKey key,
200+ VALUE const & value);
185201
186- HdInstanceRegistry &operator =(HdInstanceRegistry &) = delete ;
202+ // / Look a value up by the key in the in-memory dictionary. If the key is
203+ // / not found there and the derived class implements a persistent cache,
204+ // / try to load the value from there.
205+ typename Dictionary::iterator _LookUp (
206+ HdInstanceKey key);
207+
208+ Dictionary _dictionary;
209+ HdInstanceRegistryMutex _mutex;
210+
211+ HdInstanceRegistryBase &operator =(HdInstanceRegistryBase &) = delete ;
212+ };
213+
214+ // / \class HdInstanceRegistry
215+ // /
216+ // / The default implementation of HdInstanceRegistryBase without persistent
217+ // / cache support.
218+ // /
219+ template <typename VALUE>
220+ class HdInstanceRegistry
221+ : public HdInstanceRegistryBase<VALUE, HdInstanceRegistry<VALUE>>
222+ {
223+ public:
224+ friend class HdInstanceRegistryBase <VALUE, HdInstanceRegistry<VALUE>>;
225+
226+ void SaveToDisk (
227+ HdInstanceKey key,
228+ VALUE const & value)
229+ {
230+ }
231+
232+ VALUE LoadFromDisk (HdInstanceKey key)
233+ {
234+ return nullptr ;
235+ }
187236};
188237
189238// ---------------------------------------------------------------------------
190- // instance registry impl
239+ // Implementations
191240
192- template <typename VALUE>
193- HdInstance<VALUE>
194- HdInstanceRegistry<VALUE>::GetInstance(
195- typename HdInstance<VALUE>::KeyType const &key)
241+ template <typename VALUE, class DERIVED >
242+ typename HdInstanceRegistryBase<VALUE, DERIVED>::Dictionary::iterator
243+ HdInstanceRegistryBase<VALUE, DERIVED>::_LookUp(
244+ HdInstanceKey key)
245+ {
246+ typename Dictionary::iterator it = _dictionary.find (key);
247+ if (it != _dictionary.end ()) {
248+ return it;
249+ }
250+
251+ VALUE value = static_cast <DERIVED*>(this )->LoadFromDisk (key);
252+ if (value) {
253+ it = _dictionary.insert (
254+ std::make_pair (key,
255+ typename InstanceType::ValueHolder (value))).first ;
256+ }
257+ return it;
258+ }
259+
260+ template <typename VALUE, class DERIVED >
261+ void
262+ HdInstanceRegistryBase<VALUE, DERIVED>::_SetValue(
263+ HdInstanceKey key,
264+ VALUE const & value)
265+ {
266+ _dictionary[key] = typename InstanceType::ValueHolder (value);
267+ static_cast <DERIVED*>(this )->SaveToDisk (key, value);
268+ }
269+
270+ template <typename VALUE, class DERIVED >
271+ HdInstance<VALUE, DERIVED>
272+ HdInstanceRegistryBase<VALUE, DERIVED>::GetInstance(
273+ HdInstanceKey key)
196274{
197275 HD_TRACE_FUNCTION ();
198276 HF_MALLOC_TAG_FUNCTION ();
199277
200278 // Grab Registry lock
201279 // (and don't release it in this function, return it instead)
202- typename InstanceType::RegistryLock lock (_registryMutex );
280+ HdInstanceRegistryLock lock (_mutex );
203281
204- typename InstanceType:: Dictionary::iterator it = _dictionary. find (key);
282+ typename Dictionary::iterator it = _LookUp (key);
205283 if (it == _dictionary.end ()) {
206284 // not found. create new one
207285 it = _dictionary.insert (
208286 std::make_pair (key, typename InstanceType::ValueHolder ())).first ;
209287 }
210288
211289 it->second .ResetRecycleCounter ();
212- return InstanceType (key, it->second .value , std::move (lock), &_dictionary);
290+ return InstanceType (
291+ key, it->second .value , std::move (lock), static_cast <DERIVED*>(this ));
213292}
214293
215- template <typename VALUE>
216- HdInstance<VALUE>
217- HdInstanceRegistry <VALUE>::FindInstance(
218- typename HdInstance<VALUE>::KeyType const & key, bool *found)
294+ template <typename VALUE, class DERIVED >
295+ HdInstance<VALUE, DERIVED >
296+ HdInstanceRegistryBase <VALUE, DERIVED >::FindInstance(
297+ HdInstanceKey key, bool *found)
219298{
220299 HD_TRACE_FUNCTION ();
221300 HF_MALLOC_TAG_FUNCTION ();
222301
223302 // Grab Registry lock
224303 // (and don't release it in this function, return it instead)
225- typename InstanceType::RegistryLock lock (_registryMutex );
304+ HdInstanceRegistryLock lock (_mutex );
226305
227- typename InstanceType:: Dictionary::iterator it = _dictionary. find (key);
306+ typename Dictionary::iterator it = _LookUp (key);
228307 if (it == _dictionary.end ()) {
229308 *found = false ;
230309 return InstanceType (key, VALUE (), std::move (lock), nullptr );
231310 } else {
232311 *found = true ;
233312 it->second .ResetRecycleCounter ();
234- return InstanceType (key, it->second .value ,std::move (lock),&_dictionary);
313+ return InstanceType (
314+ key, it->second .value , std::move (lock),
315+ static_cast <DERIVED*>(this ));
235316 }
236317}
237318
238- template <typename VALUE>
319+ template <typename VALUE, class DERIVED >
239320size_t
240- HdInstanceRegistry <VALUE>::GarbageCollect(int recycleCount)
321+ HdInstanceRegistryBase <VALUE, DERIVED >::GarbageCollect(int recycleCount)
241322{
242323 // Call GarbageCollect with empty callback function
243324 return GarbageCollect ([](void *){}, recycleCount);
244325}
245326
246- template <typename VALUE>
327+ template <typename VALUE, class DERIVED >
247328template <typename Callback>
248329size_t
249- HdInstanceRegistry<VALUE>::GarbageCollect(Callback &&callback, int recycleCount)
330+ HdInstanceRegistryBase<VALUE, DERIVED>::GarbageCollect(
331+ Callback &&callback, int recycleCount)
250332{
251333 HD_TRACE_FUNCTION ();
252334 HF_MALLOC_TAG_FUNCTION ();
@@ -257,7 +339,7 @@ HdInstanceRegistry<VALUE>::GarbageCollect(Callback &&callback, int recycleCount)
257339 }
258340
259341 size_t inUseCount = 0 ;
260- for (typename InstanceType:: Dictionary::iterator it = _dictionary.begin ();
342+ for (typename Dictionary::iterator it = _dictionary.begin ();
261343 it != _dictionary.end ();) {
262344
263345 // erase instance which isn't referred from anyone
@@ -273,9 +355,9 @@ HdInstanceRegistry<VALUE>::GarbageCollect(Callback &&callback, int recycleCount)
273355 return inUseCount;
274356}
275357
276- template <typename VALUE>
358+ template <typename VALUE, class DERIVED >
277359void
278- HdInstanceRegistry <VALUE>::Invalidate()
360+ HdInstanceRegistryBase <VALUE, DERIVED >::Invalidate()
279361{
280362 HD_TRACE_FUNCTION ();
281363 HF_MALLOC_TAG_FUNCTION ();
0 commit comments