2
// Copyright 2016 Pixar
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:
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.
14
// You may obtain a copy of the Apache License at
16
// http://www.apache.org/licenses/LICENSE-2.0
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.
24
#include "pxr/usd/usd/stageCache.h"
26
#include "pxr/usd/sdf/layer.h"
27
#include "pxr/usd/usd/debugCodes.h"
28
#include "pxr/usd/usd/stage.h"
30
#include "pxr/usd/ar/resolverContext.h"
32
#include <boost/bind.hpp>
33
#include <boost/foreach.hpp>
34
#include <boost/functional/hash.hpp>
35
#include <boost/multi_index_container.hpp>
36
#include <boost/multi_index/hashed_index.hpp>
37
#include <boost/multi_index/identity.hpp>
38
#include <boost/multi_index/member.hpp>
39
#include <boost/multi_index/global_fun.hpp>
40
#include <boost/range/begin.hpp>
41
#include <boost/range/end.hpp>
51
using LockGuard = std::lock_guard<std::mutex>;
53
#define DBG TF_DEBUG(USD_STAGE_CACHE).Msg
54
#define FMT(...) (TfStringPrintf(__VA_ARGS__).c_str())
58
typedef UsdStageCache::Id Id;
60
std::atomic_long idCounter(9223000);
62
Id GetNextId() { return Id::FromLongInt(++idCounter); }
66
Entry(const UsdStageRefPtr &stage, Id id) : stage(stage), id(id) {}
76
static SdfLayerHandle Get(const Entry &entry) {
77
return entry.stage->GetRootLayer();
81
typedef boost::multi_index::multi_index_container<
85
boost::multi_index::indexed_by<
87
boost::multi_index::hashed_unique<
88
boost::multi_index::tag<ById>,
89
boost::multi_index::member<Entry, Id, &Entry::id>
92
boost::multi_index::hashed_unique<
93
boost::multi_index::tag<ByStage>,
94
boost::multi_index::member<Entry, UsdStageRefPtr, &Entry::stage>
97
boost::multi_index::hashed_non_unique<
98
boost::multi_index::tag<ByRootLayer>,
99
boost::multi_index::global_fun<
100
const Entry &, SdfLayerHandle, &ByRootLayer::Get>
105
typedef StageContainer::index<ById>::type StagesById;
106
typedef StageContainer::index<ByStage>::type StagesByStage;
107
typedef StageContainer::index<ByRootLayer>::type StagesByRootLayer;
109
// Walk range, which must be from index, applying pred() to every element. For
110
// those elements where pred(element) is true, erase the element from the index
111
// and invoke out->push_back(element) if out is not null. Return the number of
113
template <class Index, class Range, class Pred, class BackIns>
114
size_t EraseIf(Index &index, Range range, Pred pred, BackIns *out) {
115
size_t numErased = 0;
116
while (range.first != range.second) {
117
if (pred(*range.first)) {
119
out->push_back(*range.first);
120
index.erase(range.first++);
131
explicit DebugHelper(const UsdStageCache &cache, const char *prefix = "")
134
, _enabled(TfDebug::IsEnabled(USD_STAGE_CACHE)) {}
141
bool IsEnabled() const { return _enabled; }
143
template <class Range>
144
void AddEntries(const Range &rng) {
146
_entries.insert(_entries.end(), boost::begin(rng), boost::end(rng));
149
void AddEntry(const Entry &entry) {
151
_entries.push_back(entry);
154
void IssueMessage() const {
155
if (_entries.size() == 1) {
156
DBG("%s %s %s (id=%s)\n",
157
UsdDescribe(_cache).c_str(),
159
UsdDescribe(_entries.front().stage).c_str(),
160
_entries.front().id.ToString().c_str());
161
} else if (_entries.size() > 1) {
162
DBG("%s %s %zu entries:\n",
163
UsdDescribe(_cache).c_str(), _prefix, _entries.size());
164
for (auto const &entry: _entries) {
165
DBG(" %s (id=%s)\n", UsdDescribe(entry.stage).c_str(),
166
entry.id.ToString().c_str());
171
vector<Entry> *GetEntryVec() {
172
return IsEnabled() ? &_entries : NULL;
176
vector<Entry> _entries;
177
const UsdStageCache &_cache;
184
struct Usd_StageCacheImpl
186
StageContainer stages;
190
UsdStageCache::UsdStageCache() : _impl(new _Impl)
194
UsdStageCache::UsdStageCache(const UsdStageCache &other)
196
LockGuard lock(other._mutex);
197
_impl.reset(new _Impl(*other._impl));
200
UsdStageCache::~UsdStageCache()
205
UsdStageCache::swap(UsdStageCache &other)
207
if (this != &other) {
209
LockGuard lockThis(_mutex), lockOther(other._mutex);
210
_impl.swap(other._impl);
212
DBG("swapped %s with %s\n",
213
UsdDescribe(*this).c_str(), UsdDescribe(other).c_str());
218
UsdStageCache::operator=(const UsdStageCache &other)
220
if (this != &other) {
221
DBG("assigning %s from %s\n",
222
UsdDescribe(*this).c_str(), UsdDescribe(other).c_str());
223
UsdStageCache tmp(other);
224
LockGuard lock(_mutex);
225
_impl.swap(tmp._impl);
230
vector<UsdStageRefPtr>
231
UsdStageCache::GetAllStages() const
233
LockGuard lock(_mutex);
234
StagesByStage &byStage = _impl->stages.get<ByStage>();
235
vector<UsdStageRefPtr> result;
236
result.reserve(_impl->stages.size());
237
for (auto const &entry: byStage)
238
result.push_back(entry.stage);
243
UsdStageCache::Size() const
245
LockGuard lock(_mutex);
246
return _impl->stages.size();
250
UsdStageCache::Find(Id id) const
252
UsdStageRefPtr result;
253
{ LockGuard lock(_mutex);
254
StagesById &byId = _impl->stages.get<ById>();
255
StagesById::const_iterator iter = byId.find(id);
256
result = iter != byId.end() ? iter->stage : TfNullPtr;
259
DBG("%s for id=%s in %s\n",
260
(result ? FMT("found %s", UsdDescribe(result).c_str())
261
: "failed to find stage"),
262
id.ToString().c_str(), UsdDescribe(*this).c_str());
268
UsdStageCache::FindOneMatching(const SdfLayerHandle &rootLayer) const
270
UsdStageRefPtr result;
271
{ LockGuard lock(_mutex);
272
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
273
auto iter = byRootLayer.find(rootLayer);
274
result = iter != byRootLayer.end() ? iter->stage : TfNullPtr;
277
DBG("%s by rootLayer%s in %s\n",
278
(result ? FMT("found %s", UsdDescribe(result).c_str())
279
: "failed to find stage"),
280
(result ? "" : FMT(" @%s@", rootLayer->GetIdentifier().c_str())),
281
UsdDescribe(*this).c_str());
287
UsdStageCache::FindOneMatching(const SdfLayerHandle &rootLayer,
288
const SdfLayerHandle &sessionLayer) const
290
UsdStageRefPtr result;
291
{ LockGuard lock(_mutex);
292
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
293
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
294
if (entry.stage->GetSessionLayer() == sessionLayer) {
295
result = entry.stage;
301
DBG("%s by rootLayer%s, sessionLayer%s in %s\n",
302
(result ? FMT("found %s", UsdDescribe(result).c_str())
303
: "failed to find stage"),
304
(result ? "" : FMT(" @%s@", rootLayer->GetIdentifier().c_str())),
305
(result ? "" : (not sessionLayer ? " <null>" :
306
FMT(" @%s@", sessionLayer->GetIdentifier().c_str()))),
307
UsdDescribe(*this).c_str());
313
UsdStageCache::FindOneMatching(
314
const SdfLayerHandle &rootLayer,
315
const ArResolverContext &pathResolverContext) const
317
UsdStageRefPtr result;
318
{ LockGuard lock(_mutex);
319
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
320
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
321
if (entry.stage->GetPathResolverContext() == pathResolverContext) {
322
result = entry.stage;
328
DBG("%s by rootLayer%s, pathResolverContext in %s\n",
329
(result ? FMT("found %s", UsdDescribe(result).c_str())
330
: "failed to find stage"),
331
(result ? "" : FMT(" @%s@", rootLayer->GetIdentifier().c_str())),
332
UsdDescribe(*this).c_str());
338
UsdStageCache::FindOneMatching(
339
const SdfLayerHandle &rootLayer,
340
const SdfLayerHandle &sessionLayer,
341
const ArResolverContext &pathResolverContext) const
343
UsdStageRefPtr result;
344
{ LockGuard lock(_mutex);
345
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
346
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
347
if (entry.stage->GetSessionLayer() == sessionLayer and
348
entry.stage->GetPathResolverContext() == pathResolverContext) {
349
result = entry.stage;
355
DBG("%s by rootLayer%s, sessionLayer%s, pathResolverContext in %s\n",
356
(result ? FMT("found %s", UsdDescribe(result).c_str())
357
: "failed to find stage"),
358
(result ? "" : FMT(" @%s@", rootLayer->GetIdentifier().c_str())),
359
(result ? "" : (not sessionLayer ? " <null>" :
360
FMT(" @%s@", sessionLayer->GetIdentifier().c_str()))),
361
UsdDescribe(*this).c_str());
366
std::vector<UsdStageRefPtr>
367
UsdStageCache::FindAllMatching(const SdfLayerHandle &rootLayer) const
369
LockGuard lock(_mutex);
370
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
371
vector<UsdStageRefPtr> result;
372
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer))
373
result.push_back(entry.stage);
377
std::vector<UsdStageRefPtr>
378
UsdStageCache::FindAllMatching(const SdfLayerHandle &rootLayer,
379
const SdfLayerHandle &sessionLayer) const
381
LockGuard lock(_mutex);
382
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
383
vector<UsdStageRefPtr> result;
384
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
385
if (entry.stage->GetSessionLayer() == sessionLayer)
386
result.push_back(entry.stage);
391
std::vector<UsdStageRefPtr>
392
UsdStageCache::FindAllMatching(
393
const SdfLayerHandle &rootLayer,
394
const ArResolverContext &pathResolverContext) const
396
LockGuard lock(_mutex);
397
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
398
vector<UsdStageRefPtr> result;
399
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
400
if (entry.stage->GetPathResolverContext() == pathResolverContext)
401
result.push_back(entry.stage);
406
std::vector<UsdStageRefPtr>
407
UsdStageCache::FindAllMatching(
408
const SdfLayerHandle &rootLayer,
409
const SdfLayerHandle &sessionLayer,
410
const ArResolverContext &pathResolverContext) const
412
LockGuard lock(_mutex);
413
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
414
vector<UsdStageRefPtr> result;
415
BOOST_FOREACH(const Entry &entry, byRootLayer.equal_range(rootLayer)) {
416
if (entry.stage->GetSessionLayer() == sessionLayer and
417
entry.stage->GetPathResolverContext() == pathResolverContext) {
418
result.push_back(entry.stage);
425
UsdStageCache::GetId(const UsdStageRefPtr &stage) const
427
LockGuard lock(_mutex);
428
StagesByStage &byStage = _impl->stages.get<ByStage>();
429
auto iter = byStage.find(stage);
430
return iter != byStage.end() ? iter->id : Id();
434
UsdStageCache::Insert(const UsdStageRefPtr &stage)
437
TF_CODING_ERROR("Inserted null stage in cache");
441
DebugHelper debug(*this, "inserted");
444
{ LockGuard lock(_mutex);
445
StagesByStage &byStage = _impl->stages.get<ByStage>();
446
auto iresult = byStage.insert(Entry(stage, GetNextId()));
447
if (iresult.second and debug.IsEnabled())
448
debug.AddEntry(*iresult.first);
449
ret = iresult.first->id;
455
UsdStageCache::Erase(Id id)
457
DebugHelper debug(*this, "erased");
459
{ LockGuard lock(_mutex);
460
if (debug.IsEnabled())
461
debug.AddEntries(_impl->stages.get<ById>().equal_range(id));
462
result = _impl->stages.get<ById>().erase(id);
468
UsdStageCache::Erase(const UsdStageRefPtr &stage)
470
DebugHelper debug(*this, "erased");
472
{ LockGuard lock(_mutex);
473
if (debug.IsEnabled())
474
debug.AddEntries(_impl->stages.get<ByStage>().equal_range(stage));
475
result = _impl->stages.get<ByStage>().erase(stage);
481
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer)
483
DebugHelper debug(*this, "erased");
485
{ LockGuard lock(_mutex);
486
if (debug.IsEnabled()) {
488
_impl->stages.get<ByRootLayer>().equal_range(rootLayer));
490
result = _impl->stages.get<ByRootLayer>().erase(rootLayer);
496
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer,
497
const SdfLayerHandle &sessionLayer)
499
DebugHelper debug(*this, "erased");
501
{ LockGuard lock(_mutex);
502
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
504
EraseIf(byRootLayer, byRootLayer.equal_range(rootLayer),
505
bind(&UsdStage::GetSessionLayer,
506
bind(&Entry::stage, _1)) == sessionLayer,
507
debug.GetEntryVec());
513
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer,
514
const SdfLayerHandle &sessionLayer,
515
const ArResolverContext &pathResolverContext)
517
DebugHelper debug(*this, "erased");
519
{ LockGuard lock(_mutex);
520
StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
522
EraseIf(byRootLayer, byRootLayer.equal_range(rootLayer),
523
(bind(&UsdStage::GetSessionLayer,
524
bind(&Entry::stage, _1)) == sessionLayer) and
525
(bind(&UsdStage::GetPathResolverContext,
526
bind(&Entry::stage, _1)) == pathResolverContext),
527
debug.GetEntryVec());
534
UsdStageCache::Clear()
536
DebugHelper debug(*this, "cleared");
539
{ LockGuard lock(_mutex);
540
if (debug.IsEnabled())
541
debug.AddEntries(_impl->stages.get<ByStage>());
542
_impl.swap(tmp._impl);
547
UsdStageCache::SetDebugName(const string &debugName)
549
LockGuard lock(_mutex);
550
_impl->debugName = debugName;
554
UsdStageCache::GetDebugName() const
556
LockGuard lock(_mutex);
557
return _impl->debugName;
561
UsdDescribe(const UsdStageCache &cache)
563
return TfStringPrintf("stage cache %s (size=%zu)",
564
(cache.GetDebugName().empty()
566
: FMT("\"%s\"", cache.GetDebugName().c_str())),