diff options
author | Henrik Edin <henrik.edin@mongodb.com> | 2020-09-17 17:09:19 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-09-26 02:12:49 +0000 |
commit | 2b82ab88982566114d1bb7667477b71c883b0799 (patch) | |
tree | c152b35ff047fdc42f69aa6cd6b04fee1d811fe4 /src/mongo/db/catalog/collection.cpp | |
parent | 08e92a678a1ed288f6a95e7950597e082556ae59 (diff) | |
download | mongo-2b82ab88982566114d1bb7667477b71c883b0799.tar.gz |
SERVER-50984 Add CollectionPtr to replace usage of const Collection*
It implements a yieldable interface that is used to re-load the
Collection pointer from the catalog after a yield that released locks.
With lock-free reads and copy-on-write on Collection instances releasing
locks without notifying an AutoGetCollection at a higher level may cause
its pointers to dangle if a MODE_X writer installs a new Collection
instance in the catalog.
CollectionPtr should be passed by const reference so a yield can notify
all the way up.
Diffstat (limited to 'src/mongo/db/catalog/collection.cpp')
-rw-r--r-- | src/mongo/db/catalog/collection.cpp | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/mongo/db/catalog/collection.cpp b/src/mongo/db/catalog/collection.cpp index e02689c7622..36f73778483 100644 --- a/src/mongo/db/catalog/collection.cpp +++ b/src/mongo/db/catalog/collection.cpp @@ -67,6 +67,63 @@ bool CappedInsertNotifier::isDead() { return _dead; } +// We can't reference the catalog from this library as it would create a cyclic library dependency. +// Setup a weak dependency using a std::function that is installed by the catalog lib +std::function<CollectionPtr(OperationContext*, CollectionUUID, uint64_t)>& _catalogLookup() { + static std::function<CollectionPtr(OperationContext*, CollectionUUID, uint64_t)> func; + return func; +} + +void CollectionPtr::installCatalogLookupImpl( + std::function<CollectionPtr(OperationContext*, CollectionUUID, uint64_t)> impl) { + _catalogLookup() = std::move(impl); +} + +CollectionPtr CollectionPtr::null; + +CollectionPtr::CollectionPtr() : _collection(nullptr), _opCtx(nullptr) {} +CollectionPtr::CollectionPtr(OperationContext* opCtx, + const Collection* collection, + uint64_t catalogEpoch) + : _collection(collection), _opCtx(opCtx), _catalogEpoch(catalogEpoch) {} +CollectionPtr::CollectionPtr(const Collection* collection, NoYieldTag) + : CollectionPtr(nullptr, collection, 0) {} +CollectionPtr::CollectionPtr(Collection* collection) : CollectionPtr(collection, NoYieldTag{}) {} +CollectionPtr::CollectionPtr(const std::shared_ptr<const Collection>& collection) + : CollectionPtr(collection.get(), NoYieldTag{}) {} +CollectionPtr::CollectionPtr(CollectionPtr&&) = default; +CollectionPtr::~CollectionPtr() {} +CollectionPtr& CollectionPtr::operator=(CollectionPtr&&) = default; + +CollectionPtr CollectionPtr::detached() const { + return CollectionPtr(_opCtx, _collection, _catalogEpoch); +} + +bool CollectionPtr::_canYield() const { + // We only set the opCtx when we use a constructor that allows yielding. + // When we are doing a lock free read or having a writable pointer in a WUOW it is not allowed + // to yield. + return _opCtx; +} + +void CollectionPtr::yield() const { + if (_canYield()) { + _uuid = _collection->uuid(); + _ns = _collection->ns(); + _collection = nullptr; + } +} +void CollectionPtr::restore() const { + if (_canYield()) { + // We may only do yield restore when we were holding locks that was yielded so we need to + // refresh from the catalog to make sure we have a valid collection pointer. + auto coll = _catalogLookup()(_opCtx, *_uuid, _catalogEpoch); + if (coll && coll->ns() == _ns) { + _collection = coll.get(); + } + } +} + // ---- namespace { |