instanceRegistry.h
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 
38 PXR_NAMESPACE_OPEN_SCOPE
39 
40 
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 {
68  ValueHolder(ValueType const & value = ValueType())
69  : value(value)
70  , recycleCounter(0)
71  { }
72  void ResetRecycleCounter() {
73  recycleCounter = 0;
74  }
75 
76  ValueType value;
77  int recycleCounter;
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 
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 
102  explicit HdInstance(KeyType const &key)
103  : _key(key)
104  , _value(ValueType())
105  , _registryLock()
106  , _container(nullptr)
107  , _isFirstInstance(!bool(_value))
108  { }
109 
111  KeyType const &GetKey() const { return _key; }
112 
114  ValueType const &GetValue() const { return _value; }
115 
117  void SetValue(ValueType const &value) {
118  if (_container) (*_container)[_key] = ValueHolder(value);
119  _value = value;
120  }
121 
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 
145 template <typename VALUE>
147 public:
149 
150  HdInstanceRegistry() = default;
151 
155  : _dictionary(other._dictionary)
156  , _registryMutex() // mutex is not copied
157  { }
158 
160  InstanceType GetInstance(
161  typename InstanceType::KeyType const &key);
162 
165  InstanceType FindInstance(
166  typename InstanceType::KeyType const &key, bool *found);
167 
173  size_t GarbageCollect(int recycleCount = 0);
174 
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 {
205  HD_TRACE_FUNCTION();
206  HF_MALLOC_TAG_FUNCTION();
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 {
228  HD_TRACE_FUNCTION();
229  HF_MALLOC_TAG_FUNCTION();
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 {
250  HD_TRACE_FUNCTION();
251  HF_MALLOC_TAG_FUNCTION();
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 {
278  HD_TRACE_FUNCTION();
279  HF_MALLOC_TAG_FUNCTION();
280 
281  _dictionary.clear();
282 }
283 
284 
285 PXR_NAMESPACE_CLOSE_SCOPE
286 
287 #endif // PXR_IMAGING_HD_INSTANCE_REGISTRY_H
HdInstance(KeyType const &key)
Construct an instance with no lock or registry container.
InstanceType::Dictionary::const_iterator const_iterator
Returns a const iterator being/end of dictionary.
HdInstanceRegistry is a dictionary container of HdInstance.
ValueType const & GetValue() const
Returns the value.
HdInstanceRegistry(const HdInstanceRegistry &other)
Copy constructor.
InstanceType FindInstance(typename InstanceType::KeyType const &key, bool *found)
Returns a shared instance for a given key only if the key exists in the dictionary.
InstanceType GetInstance(typename InstanceType::KeyType const &key)
Returns a shared instance for given key.
bool IsFirstInstance() const
Returns true if the value has not been initialized.
size_t GarbageCollect(int recycleCount=0)
Removes unreferenced entries and returns the count of remaining entries.
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)
Construct an instance holding a registry lock, representing a value held in a registry container.
This class is used as an interface to a shared instance in HdInstanceRegistry.
KeyType const & GetKey() const
Returns the key.