HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
instanceRegistry.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_IMAGING_HD_INSTANCE_REGISTRY_H
25 #define PXR_IMAGING_HD_INSTANCE_REGISTRY_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/imaging/hd/api.h"
29 #include "pxr/imaging/hd/version.h"
30 #include "pxr/imaging/hd/perfLog.h"
31 #include "pxr/imaging/hf/perfLog.h"
32 
33 #include <tbb/concurrent_unordered_map.h>
34 
35 #include <memory>
36 #include <mutex>
37 
39 
40 
41 /// \class HdInstance
42 ///
43 /// This class is used as an interface to a shared instance in
44 /// HdInstanceRegistry.
45 ///
46 /// KeyType is a hashable index type and VALUE is shared_ptr. In most use
47 /// cases, the client computes a hash key which represents large bulky data
48 /// (like topology, primvars) and registers it into HdInstanceRegistry. If the
49 /// key has already been registered, the registry returns HdInstance and the
50 /// client can use GetValue() without setting/computing actual bulky data. If
51 /// it doesn't exist, IsFirstInstance() returns true for the first instance
52 /// and the client needs to populate an appropriate data VALUE into the
53 /// instance by SetValue().
54 ///
55 /// In order to support concurrent access to HdInstanceRegistry, this
56 /// class holds a lock to a mutex in HdInstanceRegistry. This lock will
57 /// be held until the instance of this interface class is destroyed.
58 ///
59 template <typename VALUE>
60 class HdInstance {
61 public:
62  typedef uint64_t KeyType;
63  typedef VALUE ValueType;
64 
65  typedef KeyType ID;
66 
67  struct ValueHolder {
69  : value(value)
70  , recycleCounter(0)
71  { }
73  recycleCounter = 0;
74  }
75 
78  };
79  typedef tbb::concurrent_unordered_map<KeyType, ValueHolder> Dictionary;
80 
81  typedef std::mutex RegistryMutex;
82  typedef std::unique_lock<RegistryMutex> RegistryLock;
83 
84  HdInstance() = delete;
85 
86  /// Construct an instance holding a registry lock, representing a value
87  /// held in a registry container.
88  explicit HdInstance(KeyType const &key,
89  ValueType const &value,
90  RegistryLock &&registryLock,
91  Dictionary *container)
92  : _key(key)
93  , _value(value)
94  , _registryLock(std::move(registryLock))
95  , _container(container)
96  , _isFirstInstance(!bool(_value))
97  { }
98 
99  /// Construct an instance with no lock or registry container. This
100  /// is used to present a consistent interface to clients in cases
101  /// where shared resource registration is disabled.
102  explicit HdInstance(KeyType const &key)
103  : _key(key)
104  , _value(ValueType())
105  , _registryLock()
106  , _container(nullptr)
107  , _isFirstInstance(!bool(_value))
108  { }
109 
110  /// Returns the key
111  KeyType const &GetKey() const { return _key; }
112 
113  /// Returns the value
114  ValueType const &GetValue() const { return _value; }
115 
116  /// Update the value in dictionary indexed by the key.
117  void SetValue(ValueType const &value) {
118  if (_container) (*_container)[_key] = ValueHolder(value);
119  _value = value;
120  }
121 
122  /// Returns true if the value has not been initialized.
123  bool IsFirstInstance() const {
124  return _isFirstInstance;
125  }
126 
127 private:
128  KeyType _key;
129  ValueType _value;
130  RegistryLock _registryLock;
131  Dictionary *_container;
132  bool _isFirstInstance;
133 };
134 
135 /// \class HdInstanceRegistry
136 ///
137 /// HdInstanceRegistry is a dictionary container of HdInstance.
138 /// This class is almost just a dictionary from key to value.
139 /// For cleaning unused entries, it provides GarbageCollect() API.
140 /// It sweeps all entries in the dictionary and erase unreferenced entries.
141 /// When HdInstance::ValueType is shared_ptr, it is regarded as unreferenced
142 /// if the shared_ptr is unique (use_count==1). Note that Key is not
143 /// involved to determine the lifetime of entries.
144 ///
145 template <typename VALUE>
147 public:
149 
150  HdInstanceRegistry() = default;
151 
152  /// Copy constructor. Need as HdInstanceRegistry is placed in a map
153  /// and mutex is not copy constructable, so can't use default
155  : _dictionary(other._dictionary)
156  , _registryMutex() // mutex is not copied
157  { }
158 
159  /// Returns a shared instance for given key.
161  typename InstanceType::KeyType const &key);
162 
163  /// Returns a shared instance for a given key
164  /// only if the key exists in the dictionary.
166  typename InstanceType::KeyType const &key, bool *found);
167 
168  /// Removes unreferenced entries and returns the count
169  /// of remaining entries. When recycleCount is greater than zero,
170  /// unreferenced entries will not be removed until GarbageCollect() is
171  /// called that many more times, i.e. allowing unreferenced entries to
172  /// be recycled if they are needed again.
173  size_t GarbageCollect(int recycleCount = 0);
174 
175  /// Returns a const iterator being/end of dictionary. Mainly used for
176  /// resource auditing.
177  typedef typename InstanceType::Dictionary::const_iterator const_iterator;
178  const_iterator begin() const { return _dictionary.begin(); }
179  const_iterator end() const { return _dictionary.end(); }
180 
181  size_t size() const { return _dictionary.size(); }
182 
183  void Invalidate();
184 
185 private:
186  template <typename T>
187  static bool _IsUnique(std::shared_ptr<T> const &value) {
188  return value.unique();
189  }
190 
191  typename InstanceType::Dictionary _dictionary;
192  typename InstanceType::RegistryMutex _registryMutex;
193 
194  HdInstanceRegistry &operator =(HdInstanceRegistry &) = delete;
195 };
196 
197 // ---------------------------------------------------------------------------
198 // instance registry impl
199 
200 template <typename VALUE>
203  typename HdInstance<VALUE>::KeyType const &key)
204 {
207 
208  // Grab Registry lock
209  // (and don't release it in this function, return it instead)
210  typename InstanceType::RegistryLock lock(_registryMutex);
211 
212  typename InstanceType::Dictionary::iterator it = _dictionary.find(key);
213  if (it == _dictionary.end()) {
214  // not found. create new one
215  it = _dictionary.insert(
216  std::make_pair(key, typename InstanceType::ValueHolder())).first;
217  }
218 
219  it->second.ResetRecycleCounter();
220  return InstanceType(key, it->second.value, std::move(lock), &_dictionary);
221 }
222 
223 template <typename VALUE>
226  typename HdInstance<VALUE>::KeyType const &key, bool *found)
227 {
230 
231  // Grab Registry lock
232  // (and don't release it in this function, return it instead)
233  typename InstanceType::RegistryLock lock(_registryMutex);
234 
235  typename InstanceType::Dictionary::iterator it = _dictionary.find(key);
236  if (it == _dictionary.end()) {
237  *found = false;
238  return InstanceType(key, VALUE(), std::move(lock), nullptr);
239  } else {
240  *found = true;
241  it->second.ResetRecycleCounter();
242  return InstanceType(key, it->second.value,std::move(lock),&_dictionary);
243  }
244 }
245 
246 template <typename VALUE>
247 size_t
249 {
252 
253  // Skip garbage collection entirely when then the recycleCount is < 0
254  if (recycleCount < 0) {
255  return _dictionary.size();
256  }
257 
258  size_t inUseCount = 0;
259  for (typename InstanceType::Dictionary::iterator it = _dictionary.begin();
260  it != _dictionary.end();) {
261 
262  // erase instance which isn't referred from anyone
263  bool isUnique = _IsUnique(it->second.value);
264  if (isUnique && (++it->second.recycleCounter > recycleCount)) {
265  it = _dictionary.unsafe_erase(it);
266  } else {
267  ++it;
268  ++inUseCount;
269  }
270  }
271  return inUseCount;
272 }
273 
274 template <typename VALUE>
275 void
277 {
280 
281  _dictionary.clear();
282 }
283 
284 
286 
287 #endif // PXR_IMAGING_HD_INSTANCE_REGISTRY_H
size_t GarbageCollect(int recycleCount=0)
tbb::concurrent_unordered_map< KeyType, ValueHolder > Dictionary
KeyType const & GetKey() const
Returns the key.
HdInstance()=delete
#define HF_MALLOC_TAG_FUNCTION()
Definition: perfLog.h:37
uint64_t KeyType
const_iterator begin() const
bool IsFirstInstance() const
Returns true if the value has not been initialized.
HdInstanceRegistry()=default
HdInstance< VALUE > InstanceType
HdInstance(KeyType const &key)
void SetValue(ValueType const &value)
Update the value in dictionary indexed by the key.
HdInstance(KeyType const &key, ValueType const &value, RegistryLock &&registryLock, Dictionary *container)
InstanceType::Dictionary::const_iterator const_iterator
#define HD_TRACE_FUNCTION()
Definition: perfLog.h:57
std::unique_lock< RegistryMutex > RegistryLock
HdInstanceRegistry(const HdInstanceRegistry &other)
InstanceType GetInstance(typename InstanceType::KeyType const &key)
Returns a shared instance for given key.
std::mutex RegistryMutex
size_t size() const
ValueType const & GetValue() const
Returns the value.
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1375
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
GLsizei const GLfloat * value
Definition: glcorearb.h:823
InstanceType FindInstance(typename InstanceType::KeyType const &key, bool *found)
ValueHolder(ValueType const &value=ValueType())
const_iterator end() const