~popey/+junk/usd

« back to all changes in this revision

Viewing changes to USD/pxr/usd/lib/usd/stageCache.cpp

  • Committer: Alan Pope
  • Date: 2016-09-29 12:05:28 UTC
  • Revision ID: alan@popey.com-20160929120528-32j3uk1x0dgaorip
Initial attempt to snap

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
#include "pxr/usd/usd/stageCache.h"
 
25
 
 
26
#include "pxr/usd/sdf/layer.h"
 
27
#include "pxr/usd/usd/debugCodes.h"
 
28
#include "pxr/usd/usd/stage.h"
 
29
 
 
30
#include "pxr/usd/ar/resolverContext.h"
 
31
 
 
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>
 
42
 
 
43
#include <atomic>
 
44
#include <vector>
 
45
#include <utility>
 
46
 
 
47
using std::string;
 
48
using std::vector;
 
49
using std::pair;
 
50
 
 
51
using LockGuard = std::lock_guard<std::mutex>;
 
52
 
 
53
#define DBG TF_DEBUG(USD_STAGE_CACHE).Msg
 
54
#define FMT(...) (TfStringPrintf(__VA_ARGS__).c_str())
 
55
 
 
56
namespace {
 
57
 
 
58
typedef UsdStageCache::Id Id;
 
59
 
 
60
std::atomic_long idCounter(9223000);
 
61
 
 
62
Id GetNextId() { return Id::FromLongInt(++idCounter); }
 
63
 
 
64
struct Entry {
 
65
    Entry() {}
 
66
    Entry(const UsdStageRefPtr &stage, Id id) : stage(stage), id(id) {}
 
67
    UsdStageRefPtr stage;
 
68
    Id id;
 
69
};
 
70
 
 
71
struct ById {};
 
72
 
 
73
struct ByStage {};
 
74
 
 
75
struct ByRootLayer {
 
76
    static SdfLayerHandle Get(const Entry &entry) {
 
77
        return entry.stage->GetRootLayer();
 
78
    }
 
79
};
 
80
 
 
81
typedef boost::multi_index::multi_index_container<
 
82
 
 
83
    Entry,
 
84
 
 
85
    boost::multi_index::indexed_by<
 
86
 
 
87
        boost::multi_index::hashed_unique<
 
88
            boost::multi_index::tag<ById>,
 
89
            boost::multi_index::member<Entry, Id, &Entry::id>
 
90
            >,
 
91
 
 
92
        boost::multi_index::hashed_unique<
 
93
            boost::multi_index::tag<ByStage>,
 
94
            boost::multi_index::member<Entry, UsdStageRefPtr, &Entry::stage>
 
95
            >,
 
96
 
 
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>
 
101
            >
 
102
        >
 
103
    > StageContainer;
 
104
 
 
105
typedef StageContainer::index<ById>::type StagesById;
 
106
typedef StageContainer::index<ByStage>::type StagesByStage;
 
107
typedef StageContainer::index<ByRootLayer>::type StagesByRootLayer;
 
108
 
 
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
 
112
// elements erased.
 
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)) {
 
118
            if (out)
 
119
                out->push_back(*range.first);
 
120
            index.erase(range.first++);
 
121
            ++numErased;
 
122
        } else {
 
123
            ++range.first;
 
124
        }
 
125
    }
 
126
    return numErased;
 
127
}
 
128
 
 
129
struct DebugHelper
 
130
{
 
131
    explicit DebugHelper(const UsdStageCache &cache, const char *prefix = "")
 
132
        : _cache(cache)
 
133
        , _prefix(prefix)
 
134
        , _enabled(TfDebug::IsEnabled(USD_STAGE_CACHE)) {}
 
135
 
 
136
    ~DebugHelper() {
 
137
        if (IsEnabled())
 
138
            IssueMessage();
 
139
    }
 
140
 
 
141
    bool IsEnabled() const { return _enabled; }
 
142
 
 
143
    template <class Range>
 
144
    void AddEntries(const Range &rng) {
 
145
        if (IsEnabled())
 
146
            _entries.insert(_entries.end(), boost::begin(rng), boost::end(rng));
 
147
    }
 
148
 
 
149
    void AddEntry(const Entry &entry) {
 
150
        if (IsEnabled())
 
151
            _entries.push_back(entry);
 
152
    }
 
153
 
 
154
    void IssueMessage() const {
 
155
        if (_entries.size() == 1) {
 
156
            DBG("%s %s %s (id=%s)\n",
 
157
                UsdDescribe(_cache).c_str(),
 
158
                _prefix,
 
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());
 
167
            }
 
168
        }
 
169
    }
 
170
 
 
171
    vector<Entry> *GetEntryVec() {
 
172
        return IsEnabled() ? &_entries : NULL;
 
173
    }
 
174
 
 
175
private:
 
176
    vector<Entry> _entries;
 
177
    const UsdStageCache &_cache;
 
178
    const char *_prefix;
 
179
    bool _enabled;
 
180
};
 
181
 
 
182
} // anonymous ns
 
183
 
 
184
struct Usd_StageCacheImpl
 
185
{
 
186
    StageContainer stages;
 
187
    string debugName;
 
188
};
 
189
 
 
190
UsdStageCache::UsdStageCache() : _impl(new _Impl)
 
191
{
 
192
}
 
193
 
 
194
UsdStageCache::UsdStageCache(const UsdStageCache &other)
 
195
{
 
196
    LockGuard lock(other._mutex);
 
197
    _impl.reset(new _Impl(*other._impl));
 
198
}
 
199
 
 
200
UsdStageCache::~UsdStageCache()
 
201
{
 
202
}
 
203
 
 
204
void
 
205
UsdStageCache::swap(UsdStageCache &other)
 
206
{
 
207
    if (this != &other) {
 
208
        {
 
209
            LockGuard lockThis(_mutex), lockOther(other._mutex);
 
210
            _impl.swap(other._impl);
 
211
        }
 
212
        DBG("swapped %s with %s\n",
 
213
            UsdDescribe(*this).c_str(), UsdDescribe(other).c_str());
 
214
    }
 
215
}
 
216
 
 
217
UsdStageCache &
 
218
UsdStageCache::operator=(const UsdStageCache &other)
 
219
{
 
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);
 
226
    }
 
227
    return *this;
 
228
}
 
229
 
 
230
vector<UsdStageRefPtr>
 
231
UsdStageCache::GetAllStages() const
 
232
{
 
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);
 
239
    return result;
 
240
}
 
241
 
 
242
size_t
 
243
UsdStageCache::Size() const
 
244
{
 
245
    LockGuard lock(_mutex);
 
246
    return _impl->stages.size();
 
247
}
 
248
 
 
249
UsdStageRefPtr
 
250
UsdStageCache::Find(Id id) const
 
251
{
 
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;
 
257
    }
 
258
 
 
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());
 
263
 
 
264
    return result;
 
265
}
 
266
 
 
267
UsdStageRefPtr
 
268
UsdStageCache::FindOneMatching(const SdfLayerHandle &rootLayer) const
 
269
{
 
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;
 
275
    }
 
276
 
 
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());
 
282
 
 
283
    return result;
 
284
}
 
285
 
 
286
UsdStageRefPtr
 
287
UsdStageCache::FindOneMatching(const SdfLayerHandle &rootLayer,
 
288
                                const SdfLayerHandle &sessionLayer) const
 
289
{
 
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;
 
296
                break;
 
297
            }
 
298
        }
 
299
    }
 
300
 
 
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());
 
308
 
 
309
    return result;
 
310
}
 
311
 
 
312
UsdStageRefPtr
 
313
UsdStageCache::FindOneMatching(
 
314
    const SdfLayerHandle &rootLayer,
 
315
    const ArResolverContext &pathResolverContext) const
 
316
{
 
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;
 
323
                break;
 
324
            }
 
325
        }
 
326
    }
 
327
 
 
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());
 
333
 
 
334
    return result;
 
335
}
 
336
 
 
337
UsdStageRefPtr
 
338
UsdStageCache::FindOneMatching(
 
339
    const SdfLayerHandle &rootLayer,
 
340
    const SdfLayerHandle &sessionLayer,
 
341
    const ArResolverContext &pathResolverContext) const
 
342
{
 
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;
 
350
                break;
 
351
            }
 
352
        }
 
353
    }
 
354
 
 
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());
 
362
 
 
363
    return result;
 
364
}
 
365
 
 
366
std::vector<UsdStageRefPtr>
 
367
UsdStageCache::FindAllMatching(const SdfLayerHandle &rootLayer) const
 
368
{
 
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);
 
374
    return result;
 
375
}
 
376
 
 
377
std::vector<UsdStageRefPtr>
 
378
UsdStageCache::FindAllMatching(const SdfLayerHandle &rootLayer,
 
379
                               const SdfLayerHandle &sessionLayer) const
 
380
{
 
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);
 
387
    }
 
388
    return result;
 
389
}
 
390
 
 
391
std::vector<UsdStageRefPtr>
 
392
UsdStageCache::FindAllMatching(
 
393
    const SdfLayerHandle &rootLayer,
 
394
    const ArResolverContext &pathResolverContext) const
 
395
{
 
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);
 
402
    }
 
403
    return result;
 
404
}
 
405
 
 
406
std::vector<UsdStageRefPtr>
 
407
UsdStageCache::FindAllMatching(
 
408
    const SdfLayerHandle &rootLayer,
 
409
    const SdfLayerHandle &sessionLayer,
 
410
    const ArResolverContext &pathResolverContext) const
 
411
{
 
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);
 
419
        }
 
420
    }
 
421
    return result;
 
422
}
 
423
 
 
424
UsdStageCache::Id
 
425
UsdStageCache::GetId(const UsdStageRefPtr &stage) const
 
426
{
 
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();
 
431
}
 
432
 
 
433
UsdStageCache::Id
 
434
UsdStageCache::Insert(const UsdStageRefPtr &stage)
 
435
{
 
436
    if (not stage) {
 
437
        TF_CODING_ERROR("Inserted null stage in cache");
 
438
        return Id();
 
439
    }
 
440
 
 
441
    DebugHelper debug(*this, "inserted");
 
442
    Id ret;
 
443
 
 
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;
 
450
    }
 
451
    return ret;
 
452
}
 
453
 
 
454
bool
 
455
UsdStageCache::Erase(Id id)
 
456
{
 
457
    DebugHelper debug(*this, "erased");
 
458
    bool result;
 
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);
 
463
    }
 
464
    return result;
 
465
}
 
466
 
 
467
bool
 
468
UsdStageCache::Erase(const UsdStageRefPtr &stage)
 
469
{
 
470
    DebugHelper debug(*this, "erased");
 
471
    bool result;
 
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);
 
476
    }
 
477
    return result;
 
478
}
 
479
 
 
480
size_t
 
481
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer)
 
482
{
 
483
    DebugHelper debug(*this, "erased");
 
484
    size_t result;
 
485
    { LockGuard lock(_mutex);
 
486
        if (debug.IsEnabled()) {
 
487
            debug.AddEntries(
 
488
                _impl->stages.get<ByRootLayer>().equal_range(rootLayer));
 
489
        }
 
490
        result = _impl->stages.get<ByRootLayer>().erase(rootLayer);
 
491
    }
 
492
    return result;
 
493
}
 
494
 
 
495
size_t
 
496
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer,
 
497
                         const SdfLayerHandle &sessionLayer)
 
498
{
 
499
    DebugHelper debug(*this, "erased");
 
500
    size_t numErased;
 
501
    { LockGuard lock(_mutex);
 
502
        StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
 
503
        numErased =
 
504
            EraseIf(byRootLayer, byRootLayer.equal_range(rootLayer),
 
505
                    bind(&UsdStage::GetSessionLayer,
 
506
                         bind(&Entry::stage, _1)) == sessionLayer,
 
507
                    debug.GetEntryVec());
 
508
    }
 
509
    return numErased;
 
510
}
 
511
 
 
512
size_t
 
513
UsdStageCache::EraseAll(const SdfLayerHandle &rootLayer,
 
514
                         const SdfLayerHandle &sessionLayer,
 
515
                         const ArResolverContext &pathResolverContext)
 
516
{
 
517
    DebugHelper debug(*this, "erased");
 
518
    size_t numErased;
 
519
    { LockGuard lock(_mutex);
 
520
        StagesByRootLayer &byRootLayer = _impl->stages.get<ByRootLayer>();
 
521
        numErased =
 
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());
 
528
    }
 
529
    return numErased;
 
530
}
 
531
 
 
532
 
 
533
void
 
534
UsdStageCache::Clear()
 
535
{
 
536
    DebugHelper debug(*this, "cleared");
 
537
 
 
538
    UsdStageCache tmp;
 
539
    { LockGuard lock(_mutex);
 
540
        if (debug.IsEnabled())
 
541
            debug.AddEntries(_impl->stages.get<ByStage>());
 
542
        _impl.swap(tmp._impl);
 
543
    }
 
544
}
 
545
 
 
546
void
 
547
UsdStageCache::SetDebugName(const string &debugName)
 
548
{
 
549
    LockGuard lock(_mutex);
 
550
    _impl->debugName = debugName;
 
551
}
 
552
 
 
553
string
 
554
UsdStageCache::GetDebugName() const
 
555
{
 
556
    LockGuard lock(_mutex);
 
557
    return _impl->debugName;
 
558
}
 
559
 
 
560
string
 
561
UsdDescribe(const UsdStageCache &cache)
 
562
{
 
563
    return TfStringPrintf("stage cache %s (size=%zu)",
 
564
                          (cache.GetDebugName().empty()
 
565
                           ? FMT("%p", &cache)
 
566
                           : FMT("\"%s\"", cache.GetDebugName().c_str())),
 
567
                          cache.Size());
 
568
}
 
569