diff options
55 files changed, 932 insertions, 913 deletions
diff --git a/src/mongo/db/catalog/capped_utils.cpp b/src/mongo/db/catalog/capped_utils.cpp index 74bed97f6d5..05692e11536 100644 --- a/src/mongo/db/catalog/capped_utils.cpp +++ b/src/mongo/db/catalog/capped_utils.cpp @@ -140,7 +140,8 @@ void cloneCollectionAsCapped(OperationContext* opCtx, // create new collection { - auto options = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, fromNss); + auto options = + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, fromCollection->getCatalogId()); // The capped collection will get its own new unique id, as the conversion isn't reversible, // so it can't be rolled back. options.uuid.reset(); diff --git a/src/mongo/db/catalog/capped_utils_test.cpp b/src/mongo/db/catalog/capped_utils_test.cpp index d621beb280d..986552622c8 100644 --- a/src/mongo/db/catalog/capped_utils_test.cpp +++ b/src/mongo/db/catalog/capped_utils_test.cpp @@ -98,7 +98,7 @@ CollectionOptions getCollectionOptions(OperationContext* opCtx, const NamespaceS auto collection = autoColl.getCollection(); ASSERT_TRUE(collection) << "Unable to get collections options for " << nss << " because collection does not exist."; - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); } // Size of capped collection to be passed to convertToCapped() which accepts a double. diff --git a/src/mongo/db/catalog/catalog_control.cpp b/src/mongo/db/catalog/catalog_control.cpp index b7e4dfae103..916deb9f2c7 100644 --- a/src/mongo/db/catalog/catalog_control.cpp +++ b/src/mongo/db/catalog/catalog_control.cpp @@ -116,16 +116,17 @@ void openCatalog(OperationContext* opCtx, const MinVisibleTimestampMap& minVisib // Determine which indexes need to be rebuilt. rebuildIndexesOnCollection() requires that all // indexes on that collection are done at once, so we use a map to group them together. StringMap<IndexNameObjs> nsToIndexNameObjMap; - for (auto indexNamespace : indexesToRebuild.getValue()) { - NamespaceString collNss(indexNamespace.first); - auto indexName = indexNamespace.second; - auto indexSpecs = getIndexNameObjs( - opCtx, collNss, [&indexName](const std::string& name) { return name == indexName; }); + for (StorageEngine::IndexIdentifier indexIdentifier : indexesToRebuild.getValue()) { + auto indexName = indexIdentifier.indexName; + auto indexSpecs = + getIndexNameObjs(opCtx, + indexIdentifier.catalogId, + [&indexName](const std::string& name) { return name == indexName; }); if (!indexSpecs.isOK() || indexSpecs.getValue().first.empty()) { fassert(40689, {ErrorCodes::InternalError, str::stream() << "failed to get index spec for index " << indexName - << " in collection " << collNss.toString()}); + << " in collection " << indexIdentifier.nss}); } auto indexesToRebuild = indexSpecs.getValue(); invariant( @@ -137,7 +138,7 @@ void openCatalog(OperationContext* opCtx, const MinVisibleTimestampMap& minVisib str::stream() << "expected to find a list containing exactly 1 index spec, but found " << indexesToRebuild.second.size()); - auto& ino = nsToIndexNameObjMap[collNss.ns()]; + auto& ino = nsToIndexNameObjMap[indexIdentifier.nss.ns()]; ino.first.emplace_back(std::move(indexesToRebuild.first.back())); ino.second.emplace_back(std::move(indexesToRebuild.second.back())); } diff --git a/src/mongo/db/catalog/catalog_control_test.cpp b/src/mongo/db/catalog/catalog_control_test.cpp index a96fa812f82..21740aa1b12 100644 --- a/src/mongo/db/catalog/catalog_control_test.cpp +++ b/src/mongo/db/catalog/catalog_control_test.cpp @@ -96,7 +96,9 @@ public: return Status(ErrorCodes::CommandNotSupported, "The current storage engine does not support a concurrent mode."); } - Status repairRecordStore(OperationContext* opCtx, const NamespaceString& ns) final { + Status repairRecordStore(OperationContext* opCtx, + RecordId catalogId, + const NamespaceString& ns) final { return Status::OK(); } std::unique_ptr<TemporaryRecordStore> makeTemporaryRecordStore(OperationContext* opCtx) final { @@ -146,9 +148,9 @@ public: } void setCachePressureForTest(int pressure) final {} void triggerJournalFlush() const final {} - StatusWith<std::vector<CollectionIndexNamePair>> reconcileCatalogAndIdents( + StatusWith<std::vector<IndexIdentifier>> reconcileCatalogAndIdents( OperationContext* opCtx) final { - return std::vector<CollectionIndexNamePair>(); + return std::vector<IndexIdentifier>(); } Timestamp getAllDurableTimestamp() const final { return {}; diff --git a/src/mongo/db/catalog/coll_mod.cpp b/src/mongo/db/catalog/coll_mod.cpp index 8ee9582bd1c..38c0a9b4aa3 100644 --- a/src/mongo/db/catalog/coll_mod.cpp +++ b/src/mongo/db/catalog/coll_mod.cpp @@ -350,7 +350,7 @@ Status _collModInternal(OperationContext* opCtx, // options so we save the relevant TTL index data in a separate object. CollectionOptions oldCollOptions = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, coll->getCatalogId()); boost::optional<TTLCollModInfo> ttlInfo; @@ -363,8 +363,10 @@ Status _collModInternal(OperationContext* opCtx, if (SimpleBSONElementComparator::kInstance.evaluate(oldExpireSecs != newExpireSecs)) { // Change the value of "expireAfterSeconds" on disk. - DurableCatalog::get(opCtx)->updateTTLSetting( - opCtx, coll->ns(), cmrOld.idx->indexName(), newExpireSecs.safeNumberLong()); + DurableCatalog::get(opCtx)->updateTTLSetting(opCtx, + coll->getCatalogId(), + cmrOld.idx->indexName(), + newExpireSecs.safeNumberLong()); // Notify the index catalog that the definition of this index changed. This will // invalidate the idx pointer in cmrOld. On rollback of this WUOW, the idx pointer diff --git a/src/mongo/db/catalog/collection.h b/src/mongo/db/catalog/collection.h index 2da11684f68..f4d22f31ee8 100644 --- a/src/mongo/db/catalog/collection.h +++ b/src/mongo/db/catalog/collection.h @@ -178,6 +178,7 @@ public: */ virtual std::unique_ptr<Collection> make(OperationContext* opCtx, const NamespaceString& nss, + RecordId catalogId, CollectionUUID uuid, std::unique_ptr<RecordStore> rs) const = 0; }; @@ -190,6 +191,8 @@ public: Collection() = default; virtual ~Collection() = default; + virtual RecordId getCatalogId() const = 0; + virtual const NamespaceString& ns() const = 0; /** diff --git a/src/mongo/db/catalog/collection_catalog_test.cpp b/src/mongo/db/catalog/collection_catalog_test.cpp index 205a5647e75..e31e2c9af3e 100644 --- a/src/mongo/db/catalog/collection_catalog_test.cpp +++ b/src/mongo/db/catalog/collection_catalog_test.cpp @@ -683,7 +683,7 @@ TEST_F(ForEachCollectionFromDbTest, ForEachCollectionFromDbWithPredicate) { ASSERT_TRUE( opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_NONE)); return DurableCatalog::get(opCtx) - ->getCollectionOptions(opCtx, collection->ns()) + ->getCollectionOptions(opCtx, collection->getCatalogId()) .temp; }); @@ -707,7 +707,7 @@ TEST_F(ForEachCollectionFromDbTest, ForEachCollectionFromDbWithPredicate) { ASSERT_TRUE( opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_NONE)); return !DurableCatalog::get(opCtx) - ->getCollectionOptions(opCtx, collection->ns()) + ->getCollectionOptions(opCtx, collection->getCatalogId()) .temp; }); diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp index cadf71b6faf..c5c4912b584 100644 --- a/src/mongo/db/catalog/collection_impl.cpp +++ b/src/mongo/db/catalog/collection_impl.cpp @@ -190,9 +190,11 @@ StatusWith<CollectionImpl::ValidationAction> _parseValidationAction(StringData n CollectionImpl::CollectionImpl(OperationContext* opCtx, const NamespaceString& nss, + RecordId catalogId, UUID uuid, std::unique_ptr<RecordStore> recordStore) : _ns(nss), + _catalogId(catalogId), _uuid(uuid), _recordStore(std::move(recordStore)), _needCappedLock(supportsDocLocking() && _recordStore && _recordStore->isCapped() && @@ -219,13 +221,15 @@ CollectionImpl::~CollectionImpl() { std::unique_ptr<Collection> CollectionImpl::FactoryImpl::make( OperationContext* opCtx, const NamespaceString& nss, + RecordId catalogId, CollectionUUID uuid, std::unique_ptr<RecordStore> rs) const { - return std::make_unique<CollectionImpl>(opCtx, nss, uuid, std::move(rs)); + return std::make_unique<CollectionImpl>(opCtx, nss, catalogId, uuid, std::move(rs)); } void CollectionImpl::init(OperationContext* opCtx) { - auto collectionOptions = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, _ns); + auto collectionOptions = + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, getCatalogId()); _collator = parseCollation(opCtx, _ns, collectionOptions.collation); _validatorDoc = collectionOptions.validator.getOwned(); _validator = uassertStatusOK( @@ -728,7 +732,7 @@ StatusWith<RecordData> CollectionImpl::updateDocumentWithDamages( } bool CollectionImpl::isTemporary(OperationContext* opCtx) const { - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, _ns).temp; + return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, getCatalogId()).temp; } bool CollectionImpl::isCapped() const { @@ -840,7 +844,7 @@ Status CollectionImpl::setValidator(OperationContext* opCtx, BSONObj validatorDo return statusWithMatcher.getStatus(); DurableCatalog::get(opCtx)->updateValidator( - opCtx, ns(), validatorDoc, getValidationLevel(), getValidationAction()); + opCtx, getCatalogId(), validatorDoc, getValidationLevel(), getValidationAction()); opCtx->recoveryUnit()->onRollback([this, oldValidator = std::move(_validator), @@ -887,7 +891,7 @@ Status CollectionImpl::setValidationLevel(OperationContext* opCtx, StringData ne _validationLevel = levelSW.getValue(); DurableCatalog::get(opCtx)->updateValidator( - opCtx, ns(), _validatorDoc, getValidationLevel(), getValidationAction()); + opCtx, getCatalogId(), _validatorDoc, getValidationLevel(), getValidationAction()); opCtx->recoveryUnit()->onRollback( [this, oldValidationLevel]() { this->_validationLevel = oldValidationLevel; }); @@ -907,7 +911,7 @@ Status CollectionImpl::setValidationAction(OperationContext* opCtx, StringData n DurableCatalog::get(opCtx)->updateValidator( - opCtx, ns(), _validatorDoc, getValidationLevel(), getValidationAction()); + opCtx, getCatalogId(), _validatorDoc, getValidationLevel(), getValidationAction()); opCtx->recoveryUnit()->onRollback( [this, oldValidationAction]() { this->_validationAction = oldValidationAction; }); @@ -931,7 +935,8 @@ Status CollectionImpl::updateValidator(OperationContext* opCtx, this->_validationAction = oldValidationAction; }); - DurableCatalog::get(opCtx)->updateValidator(opCtx, ns(), newValidator, newLevel, newAction); + DurableCatalog::get(opCtx)->updateValidator( + opCtx, getCatalogId(), newValidator, newLevel, newAction); _validatorDoc = std::move(newValidator); auto validatorSW = @@ -1020,7 +1025,8 @@ void CollectionImpl::setNs(NamespaceString nss) { } void CollectionImpl::indexBuildSuccess(OperationContext* opCtx, IndexCatalogEntry* index) { - DurableCatalog::get(opCtx)->indexBuildSuccess(opCtx, ns(), index->descriptor()->indexName()); + DurableCatalog::get(opCtx)->indexBuildSuccess( + opCtx, getCatalogId(), index->descriptor()->indexName()); _indexCatalog->indexBuildSuccess(opCtx, index); } diff --git a/src/mongo/db/catalog/collection_impl.h b/src/mongo/db/catalog/collection_impl.h index a33c507ecda..5e60d4b91db 100644 --- a/src/mongo/db/catalog/collection_impl.h +++ b/src/mongo/db/catalog/collection_impl.h @@ -44,6 +44,7 @@ public: explicit CollectionImpl(OperationContext* opCtx, const NamespaceString& nss, + RecordId catalogId, UUID uuid, std::unique_ptr<RecordStore> recordStore); @@ -53,6 +54,7 @@ public: public: std::unique_ptr<Collection> make(OperationContext* opCtx, const NamespaceString& nss, + RecordId catalogId, CollectionUUID uuid, std::unique_ptr<RecordStore> rs) const final; }; @@ -63,6 +65,10 @@ public: void setNs(NamespaceString nss) final; + RecordId getCatalogId() const { + return _catalogId; + } + UUID uuid() const { return _uuid; } @@ -357,6 +363,7 @@ private: OpDebug* opDebug); NamespaceString _ns; + RecordId _catalogId; UUID _uuid; // The RecordStore may be null during a repair operation. diff --git a/src/mongo/db/catalog/collection_mock.h b/src/mongo/db/catalog/collection_mock.h index c851d8ceb51..e8a7e2aa2f5 100644 --- a/src/mongo/db/catalog/collection_mock.h +++ b/src/mongo/db/catalog/collection_mock.h @@ -31,6 +31,7 @@ #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/index_catalog.h" +#include "mongo/platform/atomic_word.h" namespace mongo { @@ -39,15 +40,26 @@ namespace mongo { */ class CollectionMock : public Collection { public: - CollectionMock(const NamespaceString& ns) : CollectionMock(ns, {}) {} + CollectionMock(const NamespaceString& ns) + : CollectionMock(ns, std::unique_ptr<IndexCatalog>()) {} CollectionMock(const NamespaceString& ns, std::unique_ptr<IndexCatalog> indexCatalog) : _ns(ns), _indexCatalog(std::move(indexCatalog)) {} + CollectionMock(const NamespaceString& ns, RecordId catalogId) + : _ns(ns), _catalogId(catalogId) {} ~CollectionMock() = default; void init(OperationContext* opCtx) { std::abort(); } + RecordId getCatalogId() const { + return _catalogId; + } + + void setCatalogId(RecordId catalogId) { + _catalogId = catalogId; + } + const NamespaceString& ns() const { return _ns; } @@ -263,6 +275,7 @@ public: private: UUID _uuid = UUID::gen(); NamespaceString _ns; + RecordId _catalogId{0}; std::unique_ptr<IndexCatalog> _indexCatalog; }; diff --git a/src/mongo/db/catalog/collection_validation.cpp b/src/mongo/db/catalog/collection_validation.cpp index cfb9fdf102d..83feee3965c 100644 --- a/src/mongo/db/catalog/collection_validation.cpp +++ b/src/mongo/db/catalog/collection_validation.cpp @@ -326,7 +326,7 @@ void _validateCatalogEntry(OperationContext* opCtx, ValidateResults* results) { Collection* collection = validateState->getCollection(); CollectionOptions options = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, validateState->nss()); + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); if (options.uuid) { addErrorIfUnequal(*(options.uuid), validateState->uuid(), "UUID", results); } else { @@ -364,11 +364,11 @@ void _validateCatalogEntry(OperationContext* opCtx, } std::vector<std::string> indexes; - DurableCatalog::get(opCtx)->getReadyIndexes(opCtx, validateState->nss(), &indexes); + DurableCatalog::get(opCtx)->getReadyIndexes(opCtx, collection->getCatalogId(), &indexes); for (auto& index : indexes) { MultikeyPaths multikeyPaths; const bool isMultikey = DurableCatalog::get(opCtx)->isIndexMultikey( - opCtx, validateState->nss(), index, &multikeyPaths); + opCtx, collection->getCatalogId(), index, &multikeyPaths); const bool hasMultiKeyPaths = std::any_of(multikeyPaths.begin(), multikeyPaths.end(), [](auto& pathSet) { return pathSet.size() > 0; }); diff --git a/src/mongo/db/catalog/create_collection_test.cpp b/src/mongo/db/catalog/create_collection_test.cpp index 8584212c03f..a75abe4e1f0 100644 --- a/src/mongo/db/catalog/create_collection_test.cpp +++ b/src/mongo/db/catalog/create_collection_test.cpp @@ -101,7 +101,7 @@ CollectionOptions getCollectionOptions(OperationContext* opCtx, const NamespaceS auto collection = autoColl.getCollection(); ASSERT_TRUE(collection) << "Unable to get collections options for " << nss << " because collection does not exist."; - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); } /** diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp index 2d8b519bba0..bea3f169399 100644 --- a/src/mongo/db/catalog/database_impl.cpp +++ b/src/mongo/db/catalog/database_impl.cpp @@ -183,7 +183,9 @@ void DatabaseImpl::clearTmpCollections(OperationContext* opCtx) const { }; CollectionCatalog::CollectionInfoFn predicate = [&](const Collection* collection) { - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->ns()).temp; + return DurableCatalog::get(opCtx) + ->getCollectionOptions(opCtx, collection->getCatalogId()) + .temp; }; catalog::forEachCollectionFromDb(opCtx, name(), MODE_X, callback, predicate); @@ -448,7 +450,8 @@ void DatabaseImpl::_dropCollectionIndexes(OperationContext* opCtx, LOG(1) << "dropCollection: " << nss << " - dropAllIndexes start"; collection->getIndexCatalog()->dropAllIndexes(opCtx, true); - invariant(DurableCatalog::get(opCtx)->getTotalIndexCount(opCtx, nss) == 0); + invariant(DurableCatalog::get(opCtx)->getTotalIndexCount(opCtx, collection->getCatalogId()) == + 0); LOG(1) << "dropCollection: " << nss << " - dropAllIndexes done"; } @@ -458,7 +461,7 @@ Status DatabaseImpl::_finishDropCollection(OperationContext* opCtx, UUID uuid = collection->uuid(); log() << "Finishing collection drop for " << nss << " (" << uuid << ")."; - auto status = DurableCatalog::get(opCtx)->dropCollection(opCtx, nss); + auto status = DurableCatalog::get(opCtx)->dropCollection(opCtx, collection->getCatalogId()); if (!status.isOK()) return status; @@ -509,7 +512,8 @@ Status DatabaseImpl::renameCollection(OperationContext* opCtx, Top::get(opCtx->getServiceContext()).collectionDropped(fromNss); - Status status = DurableCatalog::get(opCtx)->renameCollection(opCtx, fromNss, toNss, stayTemp); + Status status = DurableCatalog::get(opCtx)->renameCollection( + opCtx, collToRename->getCatalogId(), toNss, stayTemp); // Set the namespace of 'collToRename' from within the CollectionCatalog. This is necessary // because @@ -631,12 +635,16 @@ Collection* DatabaseImpl::createCollection(OperationContext* opCtx, // Create Collection object auto storageEngine = opCtx->getServiceContext()->getStorageEngine(); - auto statusWithRecordStore = storageEngine->getCatalog()->createCollection( - opCtx, nss, optionsWithUUID, true /*allocateDefaultSpace*/); - massertStatusOK(statusWithRecordStore.getStatus()); - std::unique_ptr<RecordStore> rs = std::move(statusWithRecordStore.getValue()); - std::unique_ptr<Collection> ownedCollection = Collection::Factory::get(opCtx)->make( - opCtx, nss, optionsWithUUID.uuid.get(), std::move(rs)); + std::pair<RecordId, std::unique_ptr<RecordStore>> catalogIdRecordStorePair = + uassertStatusOK(storageEngine->getCatalog()->createCollection( + opCtx, nss, optionsWithUUID, true /*allocateDefaultSpace*/)); + auto catalogId = catalogIdRecordStorePair.first; + std::unique_ptr<Collection> ownedCollection = + Collection::Factory::get(opCtx)->make(opCtx, + nss, + catalogId, + optionsWithUUID.uuid.get(), + std::move(catalogIdRecordStorePair.second)); auto collection = ownedCollection.get(); ownedCollection->init(opCtx); diff --git a/src/mongo/db/catalog/database_test.cpp b/src/mongo/db/catalog/database_test.cpp index aec6f8d42fb..47f2acd3d97 100644 --- a/src/mongo/db/catalog/database_test.cpp +++ b/src/mongo/db/catalog/database_test.cpp @@ -369,7 +369,7 @@ TEST_F(DatabaseTest, RenameCollectionPreservesUuidOfSourceCollectionAndUpdatesUu ASSERT_TRUE(toCollection); auto toCollectionOptions = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, toCollection->ns()); + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, toCollection->getCatalogId()); auto toUuid = toCollectionOptions.uuid; ASSERT_TRUE(toUuid); diff --git a/src/mongo/db/catalog/index_build_block.cpp b/src/mongo/db/catalog/index_build_block.cpp index c7a1578f83e..77c7f04fb60 100644 --- a/src/mongo/db/catalog/index_build_block.cpp +++ b/src/mongo/db/catalog/index_build_block.cpp @@ -95,7 +95,7 @@ Status IndexBuildBlock::init(OperationContext* opCtx, Collection* collection) { // Setup on-disk structures. const auto protocol = IndexBuildProtocol::kSinglePhase; Status status = DurableCatalog::get(opCtx)->prepareForIndexBuild( - opCtx, _nss, descriptor.get(), protocol, isBackgroundSecondaryBuild); + opCtx, collection->getCatalogId(), descriptor.get(), protocol, isBackgroundSecondaryBuild); if (!status.isOK()) return status; @@ -118,7 +118,7 @@ Status IndexBuildBlock::init(OperationContext* opCtx, Collection* collection) { DurableCatalog::get(opCtx)->setIndexBuildScanning( opCtx, - _nss, + collection->getCatalogId(), _indexCatalogEntry->descriptor()->indexName(), sideWritesIdent, constraintsIdent); diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.cpp b/src/mongo/db/catalog/index_catalog_entry_impl.cpp index 6e8538bce53..72102857cf3 100644 --- a/src/mongo/db/catalog/index_catalog_entry_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_entry_impl.cpp @@ -70,7 +70,7 @@ IndexCatalogEntryImpl::IndexCatalogEntryImpl(OperationContext* const opCtx, _isReady(false), _isDropped(false), _prefix(DurableCatalog::get(opCtx)->getIndexPrefix( - opCtx, _descriptor->parentNS(), _descriptor->indexName())) { + opCtx, _descriptor->getCollection()->getCatalogId(), _descriptor->indexName())) { _descriptor->_cachedEntry = this; _isReady = _catalogIsReady(opCtx); @@ -287,7 +287,10 @@ void IndexCatalogEntryImpl::setMultikey(OperationContext* opCtx, } fassert(31164, status); indexMetadataHasChanged = DurableCatalog::get(opCtx)->setIndexIsMultikey( - opCtx, ns(), _descriptor->indexName(), paths); + opCtx, + _descriptor->getCollection()->getCatalogId(), + _descriptor->indexName(), + paths); opCtx->recoveryUnit()->onCommit( [onMultikeyCommitFn, indexMetadataHasChanged](boost::optional<Timestamp>) { onMultikeyCommitFn(indexMetadataHasChanged); @@ -296,7 +299,7 @@ void IndexCatalogEntryImpl::setMultikey(OperationContext* opCtx, }); } else { indexMetadataHasChanged = DurableCatalog::get(opCtx)->setIndexIsMultikey( - opCtx, ns(), _descriptor->indexName(), paths); + opCtx, _descriptor->getCollection()->getCatalogId(), _descriptor->indexName(), paths); } opCtx->recoveryUnit()->onCommit( @@ -308,21 +311,26 @@ void IndexCatalogEntryImpl::setMultikey(OperationContext* opCtx, // ---- bool IndexCatalogEntryImpl::_catalogIsReady(OperationContext* opCtx) const { - return DurableCatalog::get(opCtx)->isIndexReady(opCtx, ns(), _descriptor->indexName()); + return DurableCatalog::get(opCtx)->isIndexReady( + opCtx, _descriptor->getCollection()->getCatalogId(), _descriptor->indexName()); } bool IndexCatalogEntryImpl::_catalogIsPresent(OperationContext* opCtx) const { - return DurableCatalog::get(opCtx)->isIndexPresent(opCtx, ns(), _descriptor->indexName()); + return DurableCatalog::get(opCtx)->isIndexPresent( + opCtx, _descriptor->getCollection()->getCatalogId(), _descriptor->indexName()); } bool IndexCatalogEntryImpl::_catalogIsMultikey(OperationContext* opCtx, MultikeyPaths* multikeyPaths) const { - return DurableCatalog::get(opCtx)->isIndexMultikey( - opCtx, ns(), _descriptor->indexName(), multikeyPaths); + return DurableCatalog::get(opCtx)->isIndexMultikey(opCtx, + _descriptor->getCollection()->getCatalogId(), + _descriptor->indexName(), + multikeyPaths); } KVPrefix IndexCatalogEntryImpl::_catalogGetPrefix(OperationContext* opCtx) const { - return DurableCatalog::get(opCtx)->getIndexPrefix(opCtx, ns(), _descriptor->indexName()); + return DurableCatalog::get(opCtx)->getIndexPrefix( + opCtx, _descriptor->getCollection()->getCatalogId(), _descriptor->indexName()); } } // namespace mongo diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp index e8f444bcb0f..88ca5640675 100644 --- a/src/mongo/db/catalog/index_catalog_impl.cpp +++ b/src/mongo/db/catalog/index_catalog_impl.cpp @@ -93,12 +93,13 @@ IndexCatalogImpl::IndexCatalogImpl(Collection* collection) : _collection(collect Status IndexCatalogImpl::init(OperationContext* opCtx) { vector<string> indexNames; auto durableCatalog = DurableCatalog::get(opCtx); - durableCatalog->getAllIndexes(opCtx, _collection->ns(), &indexNames); + durableCatalog->getAllIndexes(opCtx, _collection->getCatalogId(), &indexNames); for (size_t i = 0; i < indexNames.size(); i++) { const string& indexName = indexNames[i]; - BSONObj spec = durableCatalog->getIndexSpec(opCtx, _collection->ns(), indexName).getOwned(); - invariant(durableCatalog->isIndexReady(opCtx, _collection->ns(), indexName)); + BSONObj spec = + durableCatalog->getIndexSpec(opCtx, _collection->getCatalogId(), indexName).getOwned(); + invariant(durableCatalog->isIndexReady(opCtx, _collection->getCatalogId(), indexName)); BSONObj keyPattern = spec.getObjectField("key"); auto descriptor = @@ -236,25 +237,26 @@ void IndexCatalogImpl::_logInternalState(OperationContext* opCtx, std::vector<std::string> readyIndexes; auto durableCatalog = DurableCatalog::get(opCtx); - durableCatalog->getAllIndexes(opCtx, _collection->ns(), &allIndexes); - durableCatalog->getReadyIndexes(opCtx, _collection->ns(), &readyIndexes); + durableCatalog->getAllIndexes(opCtx, _collection->getCatalogId(), &allIndexes); + durableCatalog->getReadyIndexes(opCtx, _collection->getCatalogId(), &readyIndexes); error() << "All indexes:"; for (const auto& index : allIndexes) { error() << "Index '" << index << "' with specification: " - << redact(durableCatalog->getIndexSpec(opCtx, _collection->ns(), index)); + << redact(durableCatalog->getIndexSpec(opCtx, _collection->getCatalogId(), index)); } error() << "Ready indexes:"; for (const auto& index : readyIndexes) { error() << "Index '" << index << "' with specification: " - << redact(durableCatalog->getIndexSpec(opCtx, _collection->ns(), index)); + << redact(durableCatalog->getIndexSpec(opCtx, _collection->getCatalogId(), index)); } error() << "Index names to drop:"; for (const auto& indexNameToDrop : indexNamesToDrop) { error() << "Index '" << indexNameToDrop << "' with specification: " - << redact(durableCatalog->getIndexSpec(opCtx, _collection->ns(), indexNameToDrop)); + << redact(durableCatalog->getIndexSpec( + opCtx, _collection->getCatalogId(), indexNameToDrop)); } } @@ -349,8 +351,8 @@ IndexCatalogEntry* IndexCatalogImpl::createIndexEntry(OperationContext* opCtx, } auto engine = opCtx->getServiceContext()->getStorageEngine(); - std::string ident = - engine->getCatalog()->getIndexIdent(opCtx, _collection->ns(), descriptor->indexName()); + std::string ident = engine->getCatalog()->getIndexIdent( + opCtx, _collection->getCatalogId(), descriptor->indexName()); auto* const descriptorPtr = descriptor.get(); auto entry = std::make_shared<IndexCatalogEntryImpl>( @@ -423,7 +425,7 @@ StatusWith<BSONObj> IndexCatalogImpl::createIndexOnEmptyCollection(OperationCont // sanity check invariant(DurableCatalog::get(opCtx)->isIndexReady( - opCtx, _collection->ns(), descriptor->indexName())); + opCtx, _collection->getCatalogId(), descriptor->indexName())); return spec; } @@ -826,7 +828,7 @@ void IndexCatalogImpl::dropAllIndexes(OperationContext* opCtx, // verify state is sane post cleaning long long numIndexesInCollectionCatalogEntry = - DurableCatalog::get(opCtx)->getTotalIndexCount(opCtx, _collection->ns()); + DurableCatalog::get(opCtx)->getTotalIndexCount(opCtx, _collection->getCatalogId()); if (haveIdIndex) { fassert(17324, numIndexesTotal(opCtx) == 1); @@ -934,7 +936,8 @@ Status IndexCatalogImpl::dropIndexEntry(OperationContext* opCtx, IndexCatalogEnt void IndexCatalogImpl::deleteIndexFromDisk(OperationContext* opCtx, const string& indexName) { invariant(opCtx->lockState()->isCollectionLockedForMode(_collection->ns(), MODE_X)); - Status status = DurableCatalog::get(opCtx)->removeIndex(opCtx, _collection->ns(), indexName); + Status status = + DurableCatalog::get(opCtx)->removeIndex(opCtx, _collection->getCatalogId(), indexName); if (status.code() == ErrorCodes::NamespaceNotFound) { /* * This is ok, as we may be partially through index creation. @@ -988,8 +991,8 @@ int IndexCatalogImpl::numIndexesTotal(OperationContext* opCtx) const { // This can throw a WriteConflictException when retries on write conflicts are disabled // during testing. The DurableCatalog fetches the metadata off of the disk using a // findRecord() call. - dassert(DurableCatalog::get(opCtx)->getTotalIndexCount(opCtx, _collection->ns()) == - count); + dassert(DurableCatalog::get(opCtx)->getTotalIndexCount( + opCtx, _collection->getCatalogId()) == count); } catch (const WriteConflictException& ex) { log() << " Skipping dassert check due to: " << ex; } @@ -1007,7 +1010,7 @@ int IndexCatalogImpl::numIndexesReady(OperationContext* opCtx) const { } if (kDebugBuild) { std::vector<std::string> completedIndexes; - durableCatalog->getReadyIndexes(opCtx, _collection->ns(), &completedIndexes); + durableCatalog->getReadyIndexes(opCtx, _collection->getCatalogId(), &completedIndexes); // There is a potential inconistency where the index information in the collection catalog // entry and the index catalog differ. Log as much information as possible here. @@ -1159,7 +1162,7 @@ const IndexDescriptor* IndexCatalogImpl::refreshEntry(OperationContext* opCtx, const std::string indexName = oldDesc->indexName(); auto durableCatalog = DurableCatalog::get(opCtx); - invariant(durableCatalog->isIndexReady(opCtx, _collection->ns(), indexName)); + invariant(durableCatalog->isIndexReady(opCtx, _collection->getCatalogId(), indexName)); // Delete the IndexCatalogEntry that owns this descriptor. After deletion, 'oldDesc' is // invalid and should not be dereferenced. Also, invalidate the index from the @@ -1171,7 +1174,8 @@ const IndexDescriptor* IndexCatalogImpl::refreshEntry(OperationContext* opCtx, CollectionQueryInfo::get(_collection).droppedIndex(opCtx, indexName); // Ask the CollectionCatalogEntry for the new index spec. - BSONObj spec = durableCatalog->getIndexSpec(opCtx, _collection->ns(), indexName).getOwned(); + BSONObj spec = + durableCatalog->getIndexSpec(opCtx, _collection->getCatalogId(), indexName).getOwned(); BSONObj keyPattern = spec.getObjectField("key"); // Re-register this index in the index catalog with the new spec. Also, add the new index diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp index 324c64aff8d..15ac455da05 100644 --- a/src/mongo/db/catalog/multi_index_block.cpp +++ b/src/mongo/db/catalog/multi_index_block.cpp @@ -841,7 +841,7 @@ Status MultiIndexBlock::commit(OperationContext* opCtx, opCtx->getServiceContext()->getStorageEngine()->getCheckpointLock(opCtx); auto indexIdent = opCtx->getServiceContext()->getStorageEngine()->getCatalog()->getIndexIdent( - opCtx, collection->ns(), _indexes[i].block->getIndexName()); + opCtx, collection->getCatalogId(), _indexes[i].block->getIndexName()); opCtx->getServiceContext()->getStorageEngine()->addIndividuallyCheckpointedIndexToList( indexIdent); } diff --git a/src/mongo/db/catalog/rename_collection.cpp b/src/mongo/db/catalog/rename_collection.cpp index af0a0cce8e2..c70792a1d3a 100644 --- a/src/mongo/db/catalog/rename_collection.cpp +++ b/src/mongo/db/catalog/rename_collection.cpp @@ -548,7 +548,7 @@ Status renameBetweenDBs(OperationContext* opCtx, Collection* tmpColl = nullptr; { auto collectionOptions = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, sourceColl->ns()); + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, sourceColl->getCatalogId()); // Renaming across databases will result in a new UUID. collectionOptions.uuid = UUID::gen(); diff --git a/src/mongo/db/catalog/rename_collection_test.cpp b/src/mongo/db/catalog/rename_collection_test.cpp index 8ef720a9c0c..ebef7bd241e 100644 --- a/src/mongo/db/catalog/rename_collection_test.cpp +++ b/src/mongo/db/catalog/rename_collection_test.cpp @@ -430,7 +430,7 @@ CollectionOptions _getCollectionOptions(OperationContext* opCtx, const Namespace auto collection = autoColl.getCollection(); ASSERT_TRUE(collection) << "Unable to get collections options for " << nss << " because collection does not exist."; - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); } /** diff --git a/src/mongo/db/catalog/validate_state.cpp b/src/mongo/db/catalog/validate_state.cpp index f9e0b93c8ac..19a20a178b5 100644 --- a/src/mongo/db/catalog/validate_state.cpp +++ b/src/mongo/db/catalog/validate_state.cpp @@ -179,7 +179,8 @@ void ValidateState::initializeCursors(OperationContext* opCtx) { std::vector<std::string> readyDurableIndexes; try { - DurableCatalog::get(opCtx)->getReadyIndexes(opCtx, _nss, &readyDurableIndexes); + DurableCatalog::get(opCtx)->getReadyIndexes( + opCtx, _collection->getCatalogId(), &readyDurableIndexes); } catch (const ExceptionFor<ErrorCodes::CursorNotFound>& ex) { invariant(_background); log() << "Skipping background validation on collection '" << _nss @@ -213,7 +214,7 @@ void ValidateState::initializeCursors(OperationContext* opCtx) { // because its in-memory representation is gone). auto diskIndexIdent = opCtx->getServiceContext()->getStorageEngine()->getCatalog()->getIndexIdent( - opCtx, _nss, desc->indexName()); + opCtx, _collection->getCatalogId(), desc->indexName()); if (entry->getIdent() != diskIndexIdent) { log() << "Skipping validation on index '" << desc->indexName() << "' in collection '" << _nss << "' because the index was recreated and is not yet in a checkpoint."; diff --git a/src/mongo/db/catalog/validate_state_test.cpp b/src/mongo/db/catalog/validate_state_test.cpp index d4d0f65a56e..f4397374908 100644 --- a/src/mongo/db/catalog/validate_state_test.cpp +++ b/src/mongo/db/catalog/validate_state_test.cpp @@ -54,11 +54,11 @@ public: /** * Create collection 'nss' and insert some documents. It will possess a default _id index. */ - void createCollectionAndPopulateIt(OperationContext* opCtx, const NamespaceString& nss); + Collection* createCollectionAndPopulateIt(OperationContext* opCtx, const NamespaceString& nss); }; -void ValidateStateTest::createCollectionAndPopulateIt(OperationContext* opCtx, - const NamespaceString& nss) { +Collection* ValidateStateTest::createCollectionAndPopulateIt(OperationContext* opCtx, + const NamespaceString& nss) { // Create collection. CollectionOptions defaultCollectionOptions; ASSERT_OK(storageInterface()->createCollection(opCtx, nss, defaultCollectionOptions)); @@ -75,6 +75,8 @@ void ValidateStateTest::createCollectionAndPopulateIt(OperationContext* opCtx, collection->insertDocument(opCtx, InsertStatement(BSON("_id" << i)), nullOpDebug)); wuow.commit(); } + + return collection; } /** @@ -199,7 +201,7 @@ TEST_F(ValidateStateTest, OpenCursorsOnCheckpointedIndexes) { // Only open cursors against indexes that are consistent with the rest of the checkpoint'ed data. TEST_F(ValidateStateTest, OpenCursorsOnConsistentlyCheckpointedIndexes) { auto opCtx = operationContext(); - createCollectionAndPopulateIt(opCtx, kNss); + Collection* coll = createCollectionAndPopulateIt(opCtx, kNss); // Disable periodic checkpoint'ing thread so we can control when checkpoints occur. FailPointEnableBlock failPoint("pauseCheckpointThread"); @@ -220,10 +222,10 @@ TEST_F(ValidateStateTest, OpenCursorsOnConsistentlyCheckpointedIndexes) { opCtx->getServiceContext()->getStorageEngine()->getCheckpointLock(opCtx); auto indexIdentA = opCtx->getServiceContext()->getStorageEngine()->getCatalog()->getIndexIdent( - opCtx, kNss, "a_1"); + opCtx, coll->getCatalogId(), "a_1"); auto indexIdentB = opCtx->getServiceContext()->getStorageEngine()->getCatalog()->getIndexIdent( - opCtx, kNss, "b_1"); + opCtx, coll->getCatalogId(), "b_1"); opCtx->getServiceContext()->getStorageEngine()->addIndividuallyCheckpointedIndexToList( indexIdentA); opCtx->getServiceContext()->getStorageEngine()->addIndividuallyCheckpointedIndexToList( diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 9c547811e69..c6475cbe0e9 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -600,8 +600,8 @@ Status Cloner::createCollectionsForDb( // exists on the target, we check if the existing collection's UUID matches // that of the one we're trying to create. If it does, we treat the create // as a no-op; if it doesn't match, we return an error. - auto existingOpts = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->ns()); + auto existingOpts = DurableCatalog::get(opCtx)->getCollectionOptions( + opCtx, collection->getCatalogId()); const UUID clonedUUID = uassertStatusOK(UUID::parse(params.collectionInfo["info"]["uuid"])); diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 9c6e5394797..033023ec710 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -151,7 +151,8 @@ public: vector<string> indexNames; writeConflictRetry(opCtx, "listIndexes", toReIndexNss.ns(), [&] { indexNames.clear(); - DurableCatalog::get(opCtx)->getAllIndexes(opCtx, collection->ns(), &indexNames); + DurableCatalog::get(opCtx)->getAllIndexes( + opCtx, collection->getCatalogId(), &indexNames); }); all.reserve(indexNames.size()); @@ -159,7 +160,8 @@ public: for (size_t i = 0; i < indexNames.size(); i++) { const string& name = indexNames[i]; BSONObj spec = writeConflictRetry(opCtx, "getIndexSpec", toReIndexNss.ns(), [&] { - return DurableCatalog::get(opCtx)->getIndexSpec(opCtx, collection->ns(), name); + return DurableCatalog::get(opCtx)->getIndexSpec( + opCtx, collection->getCatalogId(), name); }); { diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index 398c4f4fb36..ca0dab0d375 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -186,7 +186,8 @@ BSONObj buildCollectionBson(OperationContext* opCtx, return b.obj(); } - CollectionOptions options = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + CollectionOptions options = + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); // While the UUID is stored as a collection option, from the user's perspective it is an // unsettable read-only property, so put it in the 'info' section. diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index b7c26eb3309..858b22daba0 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -164,7 +164,7 @@ public: vector<string> indexNames; writeConflictRetry(opCtx, "listIndexes", nss.ns(), [&] { indexNames.clear(); - durableCatalog->getAllIndexes(opCtx, nss, &indexNames); + durableCatalog->getAllIndexes(opCtx, collection->getCatalogId(), &indexNames); }); auto ws = std::make_unique<WorkingSet>(); @@ -173,17 +173,20 @@ public: for (size_t i = 0; i < indexNames.size(); i++) { auto indexSpec = writeConflictRetry(opCtx, "listIndexes", nss.ns(), [&] { if (includeBuildUUIDs && - !durableCatalog->isIndexReady(opCtx, nss, indexNames[i])) { + !durableCatalog->isIndexReady( + opCtx, collection->getCatalogId(), indexNames[i])) { BSONObjBuilder builder; builder.append("spec"_sd, - durableCatalog->getIndexSpec(opCtx, nss, indexNames[i])); + durableCatalog->getIndexSpec( + opCtx, collection->getCatalogId(), indexNames[i])); // TODO(SERVER-37980): Replace with index build UUID. auto indexBuildUUID = UUID::gen(); indexBuildUUID.appendToBuilder(&builder, "buildUUID"_sd); return builder.obj(); } - return durableCatalog->getIndexSpec(opCtx, nss, indexNames[i]); + return durableCatalog->getIndexSpec( + opCtx, collection->getCatalogId(), indexNames[i]); }); WorkingSetID id = ws->allocate(); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index f9f1ced56da..f7bc154dfb8 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -560,8 +560,8 @@ void State::prepTempCollection() { auto const finalColl = autoGetFinalColl.getCollection(); if (finalColl) { - finalOptions = - DurableCatalog::get(_opCtx)->getCollectionOptions(_opCtx, finalColl->ns()); + finalOptions = DurableCatalog::get(_opCtx)->getCollectionOptions( + _opCtx, finalColl->getCatalogId()); std::unique_ptr<IndexCatalog::IndexIterator> ii = finalColl->getIndexCatalog()->getIndexIterator(_opCtx, true); diff --git a/src/mongo/db/commands/resize_oplog.cpp b/src/mongo/db/commands/resize_oplog.cpp index 2cd5f851cb4..31c2153a8da 100644 --- a/src/mongo/db/commands/resize_oplog.cpp +++ b/src/mongo/db/commands/resize_oplog.cpp @@ -105,7 +105,7 @@ public: WriteUnitOfWork wunit(opCtx); Status status = coll->getRecordStore()->updateCappedSize(opCtx, size); uassertStatusOK(status); - DurableCatalog::get(opCtx)->updateCappedSize(opCtx, coll->ns(), size); + DurableCatalog::get(opCtx)->updateCappedSize(opCtx, coll->getCatalogId(), size); wunit.commit(); LOG(0) << "replSetResizeOplog success, currentSize:" << size; return true; diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp index 493eecd9aa6..0eaa5962d85 100644 --- a/src/mongo/db/index_builds_coordinator.cpp +++ b/src/mongo/db/index_builds_coordinator.cpp @@ -353,8 +353,8 @@ StatusWith<std::pair<long long, long long>> IndexBuildsCoordinator::startIndexRe auto descriptor = indexCatalog->findIndexByName(opCtx, indexNames[i], false); if (!descriptor) { // If it's unfinished index, drop it directly via removeIndex. - Status status = - DurableCatalog::get(opCtx)->removeIndex(opCtx, nss, indexNames[i]); + Status status = DurableCatalog::get(opCtx)->removeIndex( + opCtx, collection->getCatalogId(), indexNames[i]); continue; } Status s = indexCatalog->dropIndex(opCtx, descriptor); diff --git a/src/mongo/db/op_observer_impl.cpp b/src/mongo/db/op_observer_impl.cpp index 73d31fd799d..28696a8a95f 100644 --- a/src/mongo/db/op_observer_impl.cpp +++ b/src/mongo/db/op_observer_impl.cpp @@ -614,7 +614,7 @@ void OpObserverImpl::onCollMod(OperationContext* opCtx, Collection* coll = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss); invariant(coll->uuid() == uuid); - invariant(DurableCatalog::get(opCtx)->isEqualToMetadataUUID(opCtx, nss, uuid)); + invariant(DurableCatalog::get(opCtx)->isEqualToMetadataUUID(opCtx, coll->getCatalogId(), uuid)); } void OpObserverImpl::onDropDatabase(OperationContext* opCtx, const std::string& dbName) { diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp index 092857b8a81..19e5a8fe114 100644 --- a/src/mongo/db/repair_database.cpp +++ b/src/mongo/db/repair_database.cpp @@ -61,7 +61,7 @@ namespace mongo { StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, - const NamespaceString& nss, + RecordId catalogId, std::function<bool(const std::string&)> filter) { IndexNameObjs ret; std::vector<std::string>& indexNames = ret.first; @@ -69,7 +69,7 @@ StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, auto durableCatalog = DurableCatalog::get(opCtx); { // Fetch all indexes - durableCatalog->getAllIndexes(opCtx, nss, &indexNames); + durableCatalog->getAllIndexes(opCtx, catalogId, &indexNames); auto newEnd = std::remove_if(indexNames.begin(), indexNames.end(), @@ -80,7 +80,7 @@ StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, for (const auto& name : indexNames) { - BSONObj spec = durableCatalog->getIndexSpec(opCtx, nss, name); + BSONObj spec = durableCatalog->getIndexSpec(opCtx, catalogId, name); using IndexVersion = IndexDescriptor::IndexVersion; IndexVersion indexVersion = IndexVersion::kV1; if (auto indexVersionElem = spec[IndexDescriptor::kIndexVersionFieldName]) { @@ -147,7 +147,8 @@ Status repairCollections(OperationContext* opCtx, log() << "Repairing collection " << nss; - Status status = engine->repairRecordStore(opCtx, nss); + auto collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss); + Status status = engine->repairRecordStore(opCtx, collection->getCatalogId(), nss); if (!status.isOK()) return status; } @@ -155,7 +156,7 @@ Status repairCollections(OperationContext* opCtx, for (const auto& nss : colls) { opCtx->checkForInterrupt(); auto collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss); - auto swIndexNameObjs = getIndexNameObjs(opCtx, nss); + auto swIndexNameObjs = getIndexNameObjs(opCtx, collection->getCatalogId()); if (!swIndexNameObjs.isOK()) return swIndexNameObjs.getStatus(); diff --git a/src/mongo/db/repair_database.h b/src/mongo/db/repair_database.h index 50fed16a86c..6989515b7c6 100644 --- a/src/mongo/db/repair_database.h +++ b/src/mongo/db/repair_database.h @@ -33,6 +33,7 @@ #include <string> #include "mongo/bson/bsonobj.h" +#include "mongo/db/record_id.h" namespace mongo { class Collection; @@ -52,7 +53,7 @@ typedef std::pair<std::vector<std::string>, std::vector<BSONObj>> IndexNameObjs; * should be included in the result. */ StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, - const NamespaceString& nss, + RecordId catalogId, std::function<bool(const std::string&)> filter = [](const std::string& indexName) { return true; }); diff --git a/src/mongo/db/repair_database_and_check_version.cpp b/src/mongo/db/repair_database_and_check_version.cpp index ab1fedc9cd2..1995e67e60a 100644 --- a/src/mongo/db/repair_database_and_check_version.cpp +++ b/src/mongo/db/repair_database_and_check_version.cpp @@ -140,11 +140,11 @@ Status restoreMissingFeatureCompatibilityVersionDocument(OperationContext* opCtx * Returns true if the collection associated with the given CollectionCatalogEntry has an index on * the _id field */ -bool checkIdIndexExists(OperationContext* opCtx, const NamespaceString& nss) { +bool checkIdIndexExists(OperationContext* opCtx, RecordId catalogId) { auto durableCatalog = DurableCatalog::get(opCtx); - auto indexCount = durableCatalog->getTotalIndexCount(opCtx, nss); + auto indexCount = durableCatalog->getTotalIndexCount(opCtx, catalogId); auto indexNames = std::vector<std::string>(indexCount); - durableCatalog->getAllIndexes(opCtx, nss, &indexNames); + durableCatalog->getAllIndexes(opCtx, catalogId, &indexNames); for (auto name : indexNames) { if (name == "_id_") { @@ -213,13 +213,15 @@ Status ensureCollectionProperties(OperationContext* opCtx, // All user-created replicated collections created since MongoDB 4.0 have _id indexes. auto requiresIndex = coll->requiresIdIndex() && coll->ns().isReplicated(); - auto collOptions = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, coll->ns()); + auto collOptions = + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, coll->getCatalogId()); auto hasAutoIndexIdField = collOptions.autoIndexId == CollectionOptions::YES; // Even if the autoIndexId field is not YES, the collection may still have an _id index // that was created manually by the user. Check the list of indexes to confirm index // does not exist before attempting to build it or returning an error. - if (requiresIndex && !hasAutoIndexIdField && !checkIdIndexExists(opCtx, coll->ns())) { + if (requiresIndex && !hasAutoIndexIdField && + !checkIdIndexExists(opCtx, coll->getCatalogId())) { log() << "collection " << coll->ns() << " is missing an _id index; building it now"; auto status = buildMissingIdIndex(opCtx, coll); if (!status.isOK()) { @@ -262,7 +264,7 @@ void checkForCappedOplog(OperationContext* opCtx, Database* db) { } void rebuildIndexes(OperationContext* opCtx, StorageEngine* storageEngine) { - std::vector<StorageEngine::CollectionIndexNamePair> indexesToRebuild = + std::vector<StorageEngine::IndexIdentifier> indexesToRebuild = fassert(40593, storageEngine->reconcileCatalogAndIdents(opCtx)); if (!indexesToRebuild.empty() && serverGlobalParams.indexBuildRetry) { @@ -278,11 +280,13 @@ void rebuildIndexes(OperationContext* opCtx, StorageEngine* storageEngine) { // Determine which indexes need to be rebuilt. rebuildIndexesOnCollection() requires that all // indexes on that collection are done at once, so we use a map to group them together. StringMap<IndexNameObjs> nsToIndexNameObjMap; - for (auto&& indexNamespace : indexesToRebuild) { - NamespaceString collNss(indexNamespace.first); - const std::string& indexName = indexNamespace.second; - auto swIndexSpecs = getIndexNameObjs( - opCtx, collNss, [&indexName](const std::string& name) { return name == indexName; }); + for (auto&& idxIdentifier : indexesToRebuild) { + NamespaceString collNss = idxIdentifier.nss; + const std::string& indexName = idxIdentifier.indexName; + auto swIndexSpecs = + getIndexNameObjs(opCtx, idxIdentifier.catalogId, [&indexName](const std::string& name) { + return name == indexName; + }); if (!swIndexSpecs.isOK() || swIndexSpecs.getValue().first.empty()) { fassert(40590, {ErrorCodes::InternalError, diff --git a/src/mongo/db/repl/dbcheck.cpp b/src/mongo/db/repl/dbcheck.cpp index 16011047f43..c9e822b0cc3 100644 --- a/src/mongo/db/repl/dbcheck.cpp +++ b/src/mongo/db/repl/dbcheck.cpp @@ -359,11 +359,11 @@ std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, Collection* co // List the indices, auto durableCatalog = DurableCatalog::get(opCtx); - durableCatalog->getAllIndexes(opCtx, collection->ns(), &names); + durableCatalog->getAllIndexes(opCtx, collection->getCatalogId(), &names); // and get the info for each one. for (const auto& name : names) { - result.push_back(durableCatalog->getIndexSpec(opCtx, collection->ns(), name)); + result.push_back(durableCatalog->getIndexSpec(opCtx, collection->getCatalogId(), name)); } auto comp = std::make_unique<SimpleBSONObjComparator>(); @@ -374,7 +374,9 @@ std::vector<BSONObj> collectionIndexInfo(OperationContext* opCtx, Collection* co } BSONObj collectionOptions(OperationContext* opCtx, Collection* collection) { - return DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->ns()).toBSON(); + return DurableCatalog::get(opCtx) + ->getCollectionOptions(opCtx, collection->getCatalogId()) + .toBSON(); } AutoGetDbForDbCheck::AutoGetDbForDbCheck(OperationContext* opCtx, const NamespaceString& nss) diff --git a/src/mongo/db/repl/idempotency_test_fixture.cpp b/src/mongo/db/repl/idempotency_test_fixture.cpp index b06bb4e5f1b..2d398f1a817 100644 --- a/src/mongo/db/repl/idempotency_test_fixture.cpp +++ b/src/mongo/db/repl/idempotency_test_fixture.cpp @@ -609,12 +609,14 @@ CollectionState IdempotencyTest::validate(const NamespaceString& nss) { std::string dataHash = computeDataHash(collection); auto durableCatalog = DurableCatalog::get(_opCtx.get()); - auto collectionOptions = durableCatalog->getCollectionOptions(_opCtx.get(), collection->ns()); + auto collectionOptions = + durableCatalog->getCollectionOptions(_opCtx.get(), collection->getCatalogId()); std::vector<std::string> allIndexes; BSONObjSet indexSpecs = SimpleBSONObjComparator::kInstance.makeBSONObjSet(); - durableCatalog->getAllIndexes(_opCtx.get(), collection->ns(), &allIndexes); + durableCatalog->getAllIndexes(_opCtx.get(), collection->getCatalogId(), &allIndexes); for (auto const& index : allIndexes) { - indexSpecs.insert(durableCatalog->getIndexSpec(_opCtx.get(), collection->ns(), index)); + indexSpecs.insert( + durableCatalog->getIndexSpec(_opCtx.get(), collection->getCatalogId(), index)); } ASSERT_EQUALS(indexSpecs.size(), allIndexes.size()); diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 5f0548d92cb..027b9d80cac 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -594,7 +594,7 @@ void createOplog(OperationContext* opCtx, if (collection) { if (replSettings.getOplogSizeBytes() != 0) { const CollectionOptions oplogOpts = - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, oplogCollectionName); + DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, collection->getCatalogId()); int o = (int)(oplogOpts.cappedSize / (1024 * 1024)); int n = (int)(replSettings.getOplogSizeBytes() / (1024 * 1024)); diff --git a/src/mongo/db/repl/rollback_test_fixture.cpp b/src/mongo/db/repl/rollback_test_fixture.cpp index 881a0b2c612..d0b0463fe07 100644 --- a/src/mongo/db/repl/rollback_test_fixture.cpp +++ b/src/mongo/db/repl/rollback_test_fixture.cpp @@ -320,7 +320,8 @@ void RollbackResyncsCollectionOptionsTest::resyncCollectionOptionsTest( // Make sure the collection options are correct. AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(nss.toString())); auto collAfterRollbackOptions = - DurableCatalog::get(_opCtx.get())->getCollectionOptions(_opCtx.get(), nss); + DurableCatalog::get(_opCtx.get()) + ->getCollectionOptions(_opCtx.get(), autoColl.getCollection()->getCatalogId()); BSONObjBuilder expectedOptionsBob; if (localCollOptions.uuid) { diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 255dedd9995..87f3448c504 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -1278,7 +1278,7 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, WriteUnitOfWork wuow(opCtx); // Set collection to whatever temp status is on the sync source. - DurableCatalog::get(opCtx)->setIsTemp(opCtx, *nss, options.temp); + DurableCatalog::get(opCtx)->setIsTemp(opCtx, collection->getCatalogId(), options.temp); // Set any document validation options. We update the validator fields without // parsing/validation, since we fetched the options object directly from the sync @@ -1296,8 +1296,9 @@ void rollback_internal::syncFixUp(OperationContext* opCtx, LOG(1) << "Resynced collection metadata for collection: " << *nss << ", UUID: " << uuid << ", with: " << redact(info) << ", to: " - << redact( - DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, *nss).toBSON()); + << redact(DurableCatalog::get(opCtx) + ->getCollectionOptions(opCtx, collection->getCatalogId()) + .toBSON()); } // Since we read from the sync source to retrieve the metadata of the diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp index 337144013b0..9380cbe51ad 100644 --- a/src/mongo/db/repl/rs_rollback_test.cpp +++ b/src/mongo/db/repl/rs_rollback_test.cpp @@ -1061,7 +1061,7 @@ TEST_F(RSRollbackTest, RollbackRenameCollectionInSameDatabaseCommand) { // Remote collection options should have been empty. auto collAfterRollbackOptions = DurableCatalog::get(_opCtx.get()) - ->getCollectionOptions(_opCtx.get(), oldCollName.getCollection()->ns()); + ->getCollectionOptions(_opCtx.get(), oldCollName.getCollection()->getCatalogId()); ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid), collAfterRollbackOptions.toBSON()); } } @@ -1117,7 +1117,8 @@ TEST_F(RSRollbackTest, AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString(renameFromNss)); auto collAfterRollbackOptions = - DurableCatalog::get(_opCtx.get())->getCollectionOptions(_opCtx.get(), renameFromNss); + DurableCatalog::get(_opCtx.get()) + ->getCollectionOptions(_opCtx.get(), autoColl.getCollection()->getCatalogId()); ASSERT_TRUE(collAfterRollbackOptions.temp); ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid << "temp" << true), collAfterRollbackOptions.toBSON()); @@ -1712,7 +1713,7 @@ TEST_F(RSRollbackTest, RollbackCollectionModificationCommand) { AutoGetCollectionForReadCommand autoColl(_opCtx.get(), NamespaceString("test.t")); auto collAfterRollbackOptions = DurableCatalog::get(_opCtx.get()) - ->getCollectionOptions(_opCtx.get(), NamespaceString("test.t")); + ->getCollectionOptions(_opCtx.get(), autoColl.getCollection()->getCatalogId()); ASSERT_BSONOBJ_EQ(BSON("uuid" << *options.uuid), collAfterRollbackOptions.toBSON()); } diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp index 0770b586e37..ef77a529a56 100644 --- a/src/mongo/db/repl/storage_interface_impl.cpp +++ b/src/mongo/db/repl/storage_interface_impl.cpp @@ -426,7 +426,8 @@ StatusWith<size_t> StorageInterfaceImpl::getOplogMaxSize(OperationContext* opCtx return collectionResult.getStatus(); } - const auto options = DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, nss); + const auto options = DurableCatalog::get(opCtx)->getCollectionOptions( + opCtx, collectionResult.getValue()->getCatalogId()); if (!options.capped) return {ErrorCodes::BadValue, str::stream() << nss.ns() << " isn't capped"}; diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp index aa3a3fa0b46..6c91cc5e090 100644 --- a/src/mongo/db/repl/storage_interface_impl_test.cpp +++ b/src/mongo/db/repl/storage_interface_impl_test.cpp @@ -791,7 +791,9 @@ TEST_F(StorageInterfaceImplTest, RenameCollectionWithStayTempFalseMakesItNotTemp AutoGetCollectionForReadCommand autoColl2(opCtx, toNss); ASSERT_TRUE(autoColl2.getCollection()); - ASSERT_FALSE(DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, toNss).temp); + ASSERT_FALSE(DurableCatalog::get(opCtx) + ->getCollectionOptions(opCtx, autoColl2.getCollection()->getCatalogId()) + .temp); } TEST_F(StorageInterfaceImplTest, RenameCollectionWithStayTempTrueMakesItTemp) { @@ -810,7 +812,9 @@ TEST_F(StorageInterfaceImplTest, RenameCollectionWithStayTempTrueMakesItTemp) { AutoGetCollectionForReadCommand autoColl2(opCtx, toNss); ASSERT_TRUE(autoColl2.getCollection()); - ASSERT_TRUE(DurableCatalog::get(opCtx)->getCollectionOptions(opCtx, toNss).temp); + ASSERT_TRUE(DurableCatalog::get(opCtx) + ->getCollectionOptions(opCtx, autoColl2.getCollection()->getCatalogId()) + .temp); } TEST_F(StorageInterfaceImplTest, RenameCollectionFailsBetweenDatabases) { diff --git a/src/mongo/db/storage/durable_catalog.h b/src/mongo/db/storage/durable_catalog.h index 8a87d2ae37b..a13527268d7 100644 --- a/src/mongo/db/storage/durable_catalog.h +++ b/src/mongo/db/storage/durable_catalog.h @@ -54,6 +54,18 @@ protected: DurableCatalog() = default; public: + /** + * `Entry` ties together the common identifiers of a single `_mdb_catalog` document. + */ + struct Entry { + Entry() {} + Entry(RecordId catalogId, std::string ident, NamespaceString nss) + : catalogId(catalogId), ident(std::move(ident)), nss(std::move(nss)) {} + RecordId catalogId; + std::string ident; + NamespaceString nss; + }; + virtual ~DurableCatalog() {} static DurableCatalog* get(OperationContext* opCtx) { @@ -62,16 +74,16 @@ public: virtual void init(OperationContext* opCtx) = 0; - virtual std::vector<NamespaceString> getAllCollections() const = 0; + virtual std::vector<Entry> getAllCatalogEntries(OperationContext* opCtx) const = 0; - virtual std::string getCollectionIdent(const NamespaceString& nss) const = 0; + virtual Entry getEntry(RecordId catalogId) const = 0; virtual std::string getIndexIdent(OperationContext* opCtx, - const NamespaceString& nss, - StringData idName) const = 0; + RecordId id, + StringData idxName) const = 0; virtual BSONCollectionCatalogEntry::MetaData getMetaData(OperationContext* opCtx, - const NamespaceString& nss) const = 0; + RecordId id) const = 0; /** * Updates the catalog entry for the collection 'nss' with the fields specified in 'md'. If @@ -79,10 +91,9 @@ public: * adds it to the catalog entry. */ virtual void putMetaData(OperationContext* opCtx, - const NamespaceString& nss, + RecordId id, BSONCollectionCatalogEntry::MetaData& md) = 0; - virtual std::vector<std::string> getAllIdentsForDB(StringData db) const = 0; virtual std::vector<std::string> getAllIdents(OperationContext* opCtx) const = 0; virtual bool isUserDataIdent(StringData ident) const = 0; @@ -109,23 +120,27 @@ public: */ virtual std::string newInternalIdent() = 0; - virtual StatusWith<std::unique_ptr<RecordStore>> createCollection( + /** + * On success, returns the RecordId which identifies the new record store in the durable catalog + * in addition to ownership of the new RecordStore. + */ + virtual StatusWith<std::pair<RecordId, std::unique_ptr<RecordStore>>> createCollection( OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options, bool allocateDefaultSpace) = 0; virtual Status renameCollection(OperationContext* opCtx, - const NamespaceString& fromNss, + RecordId catalogId, const NamespaceString& toNss, bool stayTemp) = 0; - virtual Status dropCollection(OperationContext* opCtx, const NamespaceString& nss) = 0; + virtual Status dropCollection(OperationContext* opCtx, RecordId catalogId) = 0; /** * Updates size of a capped Collection. */ - virtual void updateCappedSize(OperationContext* opCtx, NamespaceString ns, long long size) = 0; + virtual void updateCappedSize(OperationContext* opCtx, RecordId catalogId, long long size) = 0; /* * Updates the expireAfterSeconds field of the given index to the value in newExpireSecs. @@ -133,7 +148,7 @@ public: * that field and newExpireSecs must both be numeric. */ virtual void updateTTLSetting(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData idxName, long long newExpireSeconds) = 0; @@ -141,16 +156,16 @@ public: * equal, false otherwise. */ virtual bool isEqualToMetadataUUID(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, OptionalCollectionUUID uuid) = 0; /** * Updates the 'temp' setting for this collection. */ - virtual void setIsTemp(OperationContext* opCtx, NamespaceString ns, bool isTemp) = 0; + virtual void setIsTemp(OperationContext* opCtx, RecordId catalogId, bool isTemp) = 0; virtual boost::optional<std::string> getSideWritesIdent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; /** @@ -159,13 +174,13 @@ public: * An empty validator removes all validation. */ virtual void updateValidator(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const BSONObj& validator, StringData validationLevel, StringData validationAction) = 0; virtual Status removeIndex(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) = 0; /** @@ -173,7 +188,7 @@ public: * disk. */ virtual Status prepareForIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const IndexDescriptor* spec, IndexBuildProtocol indexBuildProtocol, bool isBackgroundSecondaryBuild) = 0; @@ -182,7 +197,7 @@ public: * Returns whether or not the index is being built with the two-phase index build procedure. */ virtual bool isTwoPhaseIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; /** @@ -192,7 +207,7 @@ public: * It is only valid to call this when the index is using the kTwoPhase IndexBuildProtocol. */ virtual void setIndexBuildScanning(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, std::string sideWritesIdent, boost::optional<std::string> constraintViolationsIdent) = 0; @@ -202,7 +217,7 @@ public: * Returns whether or not this index is building in the "scanning" phase. */ virtual bool isIndexBuildScanning(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; /** @@ -211,21 +226,21 @@ public: * It is only valid to call this when the index is using the kTwoPhase IndexBuildProtocol. */ virtual void setIndexBuildDraining(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) = 0; /** * Returns whether or not this index is building in the "draining" phase. */ virtual bool isIndexBuildDraining(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; /** * Indicate that an index build is completed and the index is ready to use. */ virtual void indexBuildSuccess(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) = 0; /** @@ -240,7 +255,7 @@ public: * number of elements in the index key pattern of empty sets. */ virtual bool isIndexMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, MultikeyPaths* multikeyPaths) const = 0; @@ -254,49 +269,49 @@ public: * This function returns true if the index metadata has changed, and returns false otherwise. */ virtual bool setIndexIsMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, const MultikeyPaths& multikeyPaths) = 0; virtual boost::optional<std::string> getConstraintViolationsIdent( - OperationContext* opCtx, NamespaceString ns, StringData indexName) const = 0; + OperationContext* opCtx, RecordId catalogId, StringData indexName) const = 0; /** * Returns the server-compatibility version of the index build procedure. */ virtual long getIndexBuildVersion(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; virtual CollectionOptions getCollectionOptions(OperationContext* opCtx, - NamespaceString ns) const = 0; + RecordId catalogId) const = 0; - virtual int getTotalIndexCount(OperationContext* opCtx, NamespaceString ns) const = 0; + virtual int getTotalIndexCount(OperationContext* opCtx, RecordId catalogId) const = 0; - virtual int getCompletedIndexCount(OperationContext* opCtx, NamespaceString ns) const = 0; + virtual int getCompletedIndexCount(OperationContext* opCtx, RecordId catalogId) const = 0; virtual BSONObj getIndexSpec(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; virtual void getAllIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const = 0; virtual void getReadyIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const = 0; virtual bool isIndexPresent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; virtual bool isIndexReady(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; virtual KVPrefix getIndexPrefix(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const = 0; }; } // namespace mongo diff --git a/src/mongo/db/storage/durable_catalog_impl.cpp b/src/mongo/db/storage/durable_catalog_impl.cpp index 0189a8d22b1..f6511da8264 100644 --- a/src/mongo/db/storage/durable_catalog_impl.cpp +++ b/src/mongo/db/storage/durable_catalog_impl.cpp @@ -146,32 +146,32 @@ using std::unique_ptr; class DurableCatalogImpl::AddIdentChange : public RecoveryUnit::Change { public: - AddIdentChange(DurableCatalogImpl* catalog, StringData ident) - : _catalog(catalog), _ident(ident.toString()) {} + AddIdentChange(DurableCatalogImpl* catalog, RecordId catalogId) + : _catalog(catalog), _catalogId(catalogId) {} virtual void commit(boost::optional<Timestamp>) {} virtual void rollback() { - stdx::lock_guard<Latch> lk(_catalog->_identsLock); - _catalog->_idents.erase(_ident); + stdx::lock_guard<Latch> lk(_catalog->_catalogIdToEntryMapLock); + _catalog->_catalogIdToEntryMap.erase(_catalogId); } DurableCatalogImpl* const _catalog; - const std::string _ident; + const RecordId _catalogId; }; class DurableCatalogImpl::RemoveIdentChange : public RecoveryUnit::Change { public: - RemoveIdentChange(DurableCatalogImpl* catalog, StringData ident, const Entry& entry) - : _catalog(catalog), _ident(ident.toString()), _entry(entry) {} + RemoveIdentChange(DurableCatalogImpl* catalog, RecordId catalogId, const Entry& entry) + : _catalog(catalog), _catalogId(catalogId), _entry(entry) {} virtual void commit(boost::optional<Timestamp>) {} virtual void rollback() { - stdx::lock_guard<Latch> lk(_catalog->_identsLock); - _catalog->_idents[_ident] = _entry; + stdx::lock_guard<Latch> lk(_catalog->_catalogIdToEntryMapLock); + _catalog->_catalogIdToEntryMap[_catalogId] = _entry; } DurableCatalogImpl* const _catalog; - const std::string _ident; + const RecordId _catalogId; const Entry _entry; }; @@ -402,8 +402,8 @@ std::string DurableCatalogImpl::_newRand() { bool DurableCatalogImpl::_hasEntryCollidingWithRand() const { // Only called from init() so don't need to lock. - for (NSToIdentMap::const_iterator it = _idents.begin(); it != _idents.end(); ++it) { - if (StringData(it->first).endsWith(_rand)) + for (auto it = _catalogIdToEntryMap.begin(); it != _catalogIdToEntryMap.end(); ++it) { + if (StringData(it->second.ident).endsWith(_rand)) return true; } return false; @@ -424,7 +424,7 @@ std::string DurableCatalogImpl::getFilesystemPathForDb(const std::string& dbName } } -std::string DurableCatalogImpl::_newUniqueIdent(const NamespaceString& nss, const char* kind) { +std::string DurableCatalogImpl::_newUniqueIdent(NamespaceString nss, const char* kind) { // If this changes to not put _rand at the end, _hasEntryCollidingWithRand will need fixing. StringBuilder buf; if (_directoryPerDb) { @@ -453,9 +453,9 @@ void DurableCatalogImpl::init(OperationContext* opCtx) { } // No rollback since this is just loading already committed data. - string ns = obj["ns"].String(); string ident = obj["ident"].String(); - _idents[ns] = Entry(ident, record->id); + string ns = obj["ns"].String(); + _catalogIdToEntryMap[record->id] = Entry(record->id, ident, NamespaceString(ns)); } if (!_featureTracker) { @@ -470,31 +470,41 @@ void DurableCatalogImpl::init(OperationContext* opCtx) { } } -std::vector<NamespaceString> DurableCatalogImpl::getAllCollections() const { - stdx::lock_guard<Latch> lk(_identsLock); - std::vector<NamespaceString> result; - for (NSToIdentMap::const_iterator it = _idents.begin(); it != _idents.end(); ++it) { - result.push_back(NamespaceString(it->first)); +std::vector<DurableCatalog::Entry> DurableCatalogImpl::getAllCatalogEntries( + OperationContext* opCtx) const { + std::vector<DurableCatalog::Entry> ret; + + auto cursor = _rs->getCursor(opCtx); + while (auto record = cursor->next()) { + BSONObj obj = record->data.releaseToBson(); + if (FeatureTracker::isFeatureDocument(obj)) { + // Skip over the version document because it doesn't correspond to a collection. + continue; + } + string ident = obj["ident"].String(); + string collName = obj["ns"].String(); + + ret.emplace_back(record->id, ident, NamespaceString(collName)); } - return result; + + return ret; +} + +DurableCatalog::Entry DurableCatalogImpl::getEntry(RecordId catalogId) const { + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + auto it = _catalogIdToEntryMap.find(catalogId); + invariant(it != _catalogIdToEntryMap.end()); + return it->second; } -Status DurableCatalogImpl::_addEntry(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& options, - KVPrefix prefix) { +StatusWith<DurableCatalog::Entry> DurableCatalogImpl::_addEntry(OperationContext* opCtx, + NamespaceString nss, + const CollectionOptions& options, + KVPrefix prefix) { invariant(opCtx->lockState()->isDbLockedForMode(nss.db(), MODE_IX)); const string ident = _newUniqueIdent(nss, "collection"); - stdx::lock_guard<Latch> lk(_identsLock); - Entry& old = _idents[nss.toString()]; - if (!old.ident.empty()) { - return Status(ErrorCodes::NamespaceExists, "collection already exists"); - } - - opCtx->recoveryUnit()->registerChange(std::make_unique<AddIdentChange>(this, nss.ns())); - BSONObj obj; { BSONObjBuilder b; @@ -511,55 +521,39 @@ Status DurableCatalogImpl::_addEntry(OperationContext* opCtx, if (!res.isOK()) return res.getStatus(); - old = Entry(ident, res.getValue()); - LOG(1) << "stored meta data for " << nss.ns() << " @ " << res.getValue(); - return Status::OK(); -} + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + invariant(_catalogIdToEntryMap.find(res.getValue()) == _catalogIdToEntryMap.end()); + _catalogIdToEntryMap[res.getValue()] = {res.getValue(), ident, nss}; + opCtx->recoveryUnit()->registerChange(std::make_unique<AddIdentChange>(this, res.getValue())); -std::string DurableCatalogImpl::getCollectionIdent(const NamespaceString& nss) const { - stdx::lock_guard<Latch> lk(_identsLock); - NSToIdentMap::const_iterator it = _idents.find(nss.toString()); - invariant(it != _idents.end()); - return it->second.ident; + LOG(1) << "stored meta data for " << nss.ns() << " @ " << res.getValue(); + return {{res.getValue(), ident, nss}}; } std::string DurableCatalogImpl::getIndexIdent(OperationContext* opCtx, - const NamespaceString& nss, + RecordId catalogId, StringData idxName) const { - BSONObj obj = _findEntry(opCtx, nss); + BSONObj obj = _findEntry(opCtx, catalogId); BSONObj idxIdent = obj["idxIdent"].Obj(); return idxIdent[idxName].String(); } -BSONObj DurableCatalogImpl::_findEntry(OperationContext* opCtx, - const NamespaceString& nss, - RecordId* out) const { - RecordId dl; - { - stdx::lock_guard<Latch> lk(_identsLock); - NSToIdentMap::const_iterator it = _idents.find(nss.toString()); - invariant(it != _idents.end(), str::stream() << "Did not find collection. Ns: " << nss); - dl = it->second.storedLoc; - } - - LOG(3) << "looking up metadata for: " << nss << " @ " << dl; +BSONObj DurableCatalogImpl::_findEntry(OperationContext* opCtx, RecordId catalogId) const { + LOG(3) << "looking up metadata for: " << catalogId; RecordData data; - if (!_rs->findRecord(opCtx, dl, &data)) { + if (!_rs->findRecord(opCtx, catalogId, &data)) { // since the in memory meta data isn't managed with mvcc // its possible for different transactions to see slightly // different things, which is ok via the locking above. return BSONObj(); } - if (out) - *out = dl; - return data.releaseToBson().getOwned(); } -BSONCollectionCatalogEntry::MetaData DurableCatalogImpl::getMetaData( - OperationContext* opCtx, const NamespaceString& nss) const { - BSONObj obj = _findEntry(opCtx, nss); +BSONCollectionCatalogEntry::MetaData DurableCatalogImpl::getMetaData(OperationContext* opCtx, + RecordId catalogId) const { + BSONObj obj = _findEntry(opCtx, catalogId); LOG(3) << " fetched CCE metadata: " << obj; BSONCollectionCatalogEntry::MetaData md; const BSONElement mdElement = obj["md"]; @@ -571,10 +565,10 @@ BSONCollectionCatalogEntry::MetaData DurableCatalogImpl::getMetaData( } void DurableCatalogImpl::putMetaData(OperationContext* opCtx, - const NamespaceString& nss, + RecordId catalogId, BSONCollectionCatalogEntry::MetaData& md) { - RecordId loc; - BSONObj obj = _findEntry(opCtx, nss, &loc); + NamespaceString nss(md.ns); + BSONObj obj = _findEntry(opCtx, catalogId); { // Remove the index spec 'ns' field if FCV is set to 4.4. @@ -623,16 +617,15 @@ void DurableCatalogImpl::putMetaData(OperationContext* opCtx, } LOG(3) << "recording new metadata: " << obj; - Status status = _rs->updateRecord(opCtx, loc, obj.objdata(), obj.objsize()); + Status status = _rs->updateRecord(opCtx, catalogId, obj.objdata(), obj.objsize()); fassert(28521, status); } Status DurableCatalogImpl::_replaceEntry(OperationContext* opCtx, - const NamespaceString& fromNss, + RecordId catalogId, const NamespaceString& toNss, bool stayTemp) { - RecordId loc; - BSONObj old = _findEntry(opCtx, fromNss, &loc).getOwned(); + BSONObj old = _findEntry(opCtx, catalogId).getOwned(); { BSONObjBuilder b; @@ -648,21 +641,24 @@ Status DurableCatalogImpl::_replaceEntry(OperationContext* opCtx, b.appendElementsUnique(old); BSONObj obj = b.obj(); - Status status = _rs->updateRecord(opCtx, loc, obj.objdata(), obj.objsize()); + Status status = _rs->updateRecord(opCtx, catalogId, obj.objdata(), obj.objsize()); fassert(28522, status); } - stdx::lock_guard<Latch> lk(_identsLock); - const NSToIdentMap::iterator fromIt = _idents.find(fromNss.toString()); - invariant(fromIt != _idents.end()); - - opCtx->recoveryUnit()->registerChange( - std::make_unique<RemoveIdentChange>(this, fromNss.ns(), fromIt->second)); - opCtx->recoveryUnit()->registerChange(std::make_unique<AddIdentChange>(this, toNss.ns())); - - _idents.erase(fromIt); - _idents[toNss.toString()] = Entry(old["ident"].String(), loc); + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + const auto it = _catalogIdToEntryMap.find(catalogId); + invariant(it != _catalogIdToEntryMap.end()); + + NamespaceString fromName = it->second.nss; + it->second.nss = toNss; + opCtx->recoveryUnit()->onRollback([this, catalogId, fromName]() { + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + const auto it = _catalogIdToEntryMap.find(catalogId); + invariant(it != _catalogIdToEntryMap.end()); + it->second.nss = fromName; + }); + NamespaceString fromNss(fromName); if (IndexTimestampHelper::requiresGhostCommitTimestampForCatalogWrite(opCtx, fromNss) && !fromNss.isDropPendingNamespace()) { opCtx->recoveryUnit()->setMustBeTimestamped(); @@ -671,40 +667,23 @@ Status DurableCatalogImpl::_replaceEntry(OperationContext* opCtx, return Status::OK(); } -Status DurableCatalogImpl::_removeEntry(OperationContext* opCtx, const NamespaceString& nss) { - invariant(opCtx->lockState()->isCollectionLockedForMode(nss, MODE_X)); - stdx::lock_guard<Latch> lk(_identsLock); - const NSToIdentMap::iterator it = _idents.find(nss.toString()); - if (it == _idents.end()) { +Status DurableCatalogImpl::_removeEntry(OperationContext* opCtx, RecordId catalogId) { + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + const auto it = _catalogIdToEntryMap.find(catalogId); + if (it == _catalogIdToEntryMap.end()) { return Status(ErrorCodes::NamespaceNotFound, "collection not found"); } opCtx->recoveryUnit()->registerChange( - std::make_unique<RemoveIdentChange>(this, nss.ns(), it->second)); + std::make_unique<RemoveIdentChange>(this, catalogId, it->second)); - LOG(1) << "deleting metadata for " << nss << " @ " << it->second.storedLoc; - _rs->deleteRecord(opCtx, it->second.storedLoc); - _idents.erase(it); + LOG(1) << "deleting metadata for " << it->second.nss << " @ " << catalogId; + _rs->deleteRecord(opCtx, catalogId); + _catalogIdToEntryMap.erase(it); return Status::OK(); } -std::vector<std::string> DurableCatalogImpl::getAllIdentsForDB(StringData db) const { - std::vector<std::string> v; - - { - stdx::lock_guard<Latch> lk(_identsLock); - for (NSToIdentMap::const_iterator it = _idents.begin(); it != _idents.end(); ++it) { - NamespaceString ns(it->first); - if (ns.db() != db) - continue; - v.push_back(it->second.ident); - } - } - - return v; -} - std::vector<std::string> DurableCatalogImpl::getAllIdents(OperationContext* opCtx) const { std::vector<std::string> v; @@ -757,17 +736,8 @@ StatusWith<std::string> DurableCatalogImpl::newOrphanedIdent(OperationContext* o // The collection will be named local.orphan.xxxxx. std::string identNs = ident; std::replace(identNs.begin(), identNs.end(), '-', '_'); - std::string ns = NamespaceString(NamespaceString::kOrphanCollectionDb, - NamespaceString::kOrphanCollectionPrefix + identNs) - .ns(); - - stdx::lock_guard<Latch> lk(_identsLock); - Entry& old = _idents[ns]; - if (!old.ident.empty()) { - return Status(ErrorCodes::NamespaceExists, - str::stream() << ns << " already exists in the catalog"); - } - opCtx->recoveryUnit()->registerChange(std::make_unique<AddIdentChange>(this, ns)); + NamespaceString ns = NamespaceString(NamespaceString::kOrphanCollectionDb, + NamespaceString::kOrphanCollectionPrefix + identNs); // Generate a new UUID for the orphaned collection. CollectionOptions optionsWithUUID; @@ -775,10 +745,10 @@ StatusWith<std::string> DurableCatalogImpl::newOrphanedIdent(OperationContext* o BSONObj obj; { BSONObjBuilder b; - b.append("ns", ns); + b.append("ns", ns.ns()); b.append("ident", ident); BSONCollectionCatalogEntry::MetaData md; - md.ns = ns; + md.ns = ns.ns(); // Default options with newly generated UUID. md.options = optionsWithUUID; // Not Prefixed. @@ -790,12 +760,16 @@ StatusWith<std::string> DurableCatalogImpl::newOrphanedIdent(OperationContext* o if (!res.isOK()) return res.getStatus(); - old = Entry(ident, res.getValue()); + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + invariant(_catalogIdToEntryMap.find(res.getValue()) == _catalogIdToEntryMap.end()); + _catalogIdToEntryMap[res.getValue()] = Entry(res.getValue(), ident, ns); + opCtx->recoveryUnit()->registerChange(std::make_unique<AddIdentChange>(this, res.getValue())); + LOG(1) << "stored meta data for orphaned collection " << ns << " @ " << res.getValue(); - return StatusWith<std::string>(std::move(ns)); + return {ns.ns()}; } -StatusWith<std::unique_ptr<RecordStore>> DurableCatalogImpl::createCollection( +StatusWith<std::pair<RecordId, std::unique_ptr<RecordStore>>> DurableCatalogImpl::createCollection( OperationContext* opCtx, const NamespaceString& nss, const CollectionOptions& options, @@ -810,14 +784,13 @@ StatusWith<std::unique_ptr<RecordStore>> DurableCatalogImpl::createCollection( KVPrefix prefix = KVPrefix::getNextPrefix(nss); - Status status = _addEntry(opCtx, nss, options, prefix); - if (!status.isOK()) - return status; - - std::string ident = getCollectionIdent(nss); + StatusWith<Entry> swEntry = _addEntry(opCtx, nss, options, prefix); + if (!swEntry.isOK()) + return swEntry.getStatus(); + Entry& entry = swEntry.getValue(); - status = - _engine->getEngine()->createGroupedRecordStore(opCtx, nss.ns(), ident, options, prefix); + Status status = _engine->getEngine()->createGroupedRecordStore( + opCtx, nss.ns(), entry.ident, options, prefix); if (!status.isOK()) return status; @@ -830,85 +803,64 @@ StatusWith<std::unique_ptr<RecordStore>> DurableCatalogImpl::createCollection( } CollectionUUID uuid = options.uuid.get(); - opCtx->recoveryUnit()->onRollback([opCtx, catalog = this, nss, ident, uuid]() { + opCtx->recoveryUnit()->onRollback([opCtx, catalog = this, nss, ident = entry.ident, uuid]() { // Intentionally ignoring failure catalog->_engine->getEngine()->dropIdent(opCtx, ident).ignore(); }); - auto rs = _engine->getEngine()->getGroupedRecordStore(opCtx, nss.ns(), ident, options, prefix); + auto rs = + _engine->getEngine()->getGroupedRecordStore(opCtx, nss.ns(), entry.ident, options, prefix); invariant(rs); - return std::move(rs); + return std::pair<RecordId, std::unique_ptr<RecordStore>>(entry.catalogId, std::move(rs)); } Status DurableCatalogImpl::renameCollection(OperationContext* opCtx, - const NamespaceString& fromNss, + RecordId catalogId, const NamespaceString& toNss, bool stayTemp) { - invariant(opCtx->lockState()->isCollectionLockedForMode(fromNss, MODE_X)); - invariant(opCtx->lockState()->isCollectionLockedForMode(toNss, MODE_X)); - - const std::string identFrom = _engine->getCatalog()->getCollectionIdent(fromNss); - - Status status = - _engine->getEngine()->okToRename(opCtx, fromNss.ns(), toNss.ns(), identFrom, nullptr); - if (!status.isOK()) - return status; - - status = _replaceEntry(opCtx, fromNss, toNss, stayTemp); - if (!status.isOK()) - return status; - - const std::string identTo = getCollectionIdent(toNss); - invariant(identFrom == identTo); - - return Status::OK(); + return _replaceEntry(opCtx, catalogId, toNss, stayTemp); } -Status DurableCatalogImpl::dropCollection(OperationContext* opCtx, const NamespaceString& nss) { - invariant(opCtx->lockState()->isCollectionLockedForMode(nss, MODE_X)); - - if (!CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss)) { - return Status(ErrorCodes::NamespaceNotFound, "cannnot find collection to drop"); +Status DurableCatalogImpl::dropCollection(OperationContext* opCtx, RecordId catalogId) { + Entry entry; + { + stdx::lock_guard<Latch> lk(_catalogIdToEntryMapLock); + entry = _catalogIdToEntryMap[catalogId]; } - auto& catalog = CollectionCatalog::get(opCtx); - auto uuid = catalog.lookupUUIDByNSS(nss); - - invariant(getTotalIndexCount(opCtx, nss) == getCompletedIndexCount(opCtx, nss)); - + invariant(opCtx->lockState()->isCollectionLockedForMode(entry.nss, MODE_X)); + invariant(getTotalIndexCount(opCtx, catalogId) == getCompletedIndexCount(opCtx, catalogId)); { std::vector<std::string> indexNames; - getAllIndexes(opCtx, nss, &indexNames); + getAllIndexes(opCtx, catalogId, &indexNames); for (size_t i = 0; i < indexNames.size(); i++) { - Status status = removeIndex(opCtx, nss, indexNames[i]); + Status status = removeIndex(opCtx, catalogId, indexNames[i]); } } - invariant(getTotalIndexCount(opCtx, nss) == 0); - - const std::string ident = getCollectionIdent(nss); + invariant(getTotalIndexCount(opCtx, catalogId) == 0); // Remove metadata from mdb_catalog - Status status = _removeEntry(opCtx, nss); + Status status = _removeEntry(opCtx, catalogId); if (!status.isOK()) { return status; } // This will notify the storageEngine to drop the collection only on WUOW::commit(). opCtx->recoveryUnit()->onCommit( - [opCtx, catalog = this, nss, uuid, ident](boost::optional<Timestamp> commitTimestamp) { + [opCtx, catalog = this, entry](boost::optional<Timestamp> commitTimestamp) { StorageEngineInterface* engine = catalog->_engine; auto storageEngine = engine->getStorageEngine(); if (storageEngine->supportsPendingDrops() && commitTimestamp) { - log() << "Deferring table drop for collection '" << nss << "' (" << uuid << ")" - << ". Ident: " << ident << ", commit timestamp: " << commitTimestamp; - engine->addDropPendingIdent(*commitTimestamp, nss, ident); + log() << "Deferring table drop for collection '" << entry.nss + << "'. Ident: " << entry.ident << ", commit timestamp: " << commitTimestamp; + engine->addDropPendingIdent(*commitTimestamp, entry.nss, entry.ident); } else { // Intentionally ignoring failure here. Since we've removed the metadata pointing to // the collection, we should never see it again anyway. auto kvEngine = engine->getEngine(); - kvEngine->dropIdent(opCtx, ident).ignore(); + kvEngine->dropIdent(opCtx, entry.ident).ignore(); } }); @@ -916,85 +868,85 @@ Status DurableCatalogImpl::dropCollection(OperationContext* opCtx, const Namespa } void DurableCatalogImpl::updateCappedSize(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, long long size) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); md.options.cappedSize = size; - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } void DurableCatalogImpl::updateTTLSetting(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData idxName, long long newExpireSeconds) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(idxName); invariant(offset >= 0); md.indexes[offset].updateTTLSetting(newExpireSeconds); - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } bool DurableCatalogImpl::isEqualToMetadataUUID(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, OptionalCollectionUUID uuid) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); return md.options.uuid && md.options.uuid == uuid; } -void DurableCatalogImpl::setIsTemp(OperationContext* opCtx, NamespaceString ns, bool isTemp) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); +void DurableCatalogImpl::setIsTemp(OperationContext* opCtx, RecordId catalogId, bool isTemp) { + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); md.options.temp = isTemp; - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } boost::optional<std::string> DurableCatalogImpl::getSideWritesIdent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].sideWritesIdent; } void DurableCatalogImpl::updateValidator(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const BSONObj& validator, StringData validationLevel, StringData validationAction) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); md.options.validator = validator; md.options.validationLevel = validationLevel.toString(); md.options.validationAction = validationAction.toString(); - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } Status DurableCatalogImpl::removeIndex(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); if (md.findIndexOffset(indexName) < 0) return Status::OK(); // never had the index so nothing to do. - const string ident = getIndexIdent(opCtx, ns, indexName); + const string ident = getIndexIdent(opCtx, catalogId, indexName); md.eraseIndex(indexName); - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); // Lazily remove to isolate underlying engine from rollback. - opCtx->recoveryUnit()->registerChange( - std::make_unique<RemoveIndexChange>(opCtx, _engine, md.options.uuid, ns, indexName, ident)); + opCtx->recoveryUnit()->registerChange(std::make_unique<RemoveIndexChange>( + opCtx, _engine, md.options.uuid, NamespaceString(md.ns), indexName, ident)); return Status::OK(); } Status DurableCatalogImpl::prepareForIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const IndexDescriptor* spec, IndexBuildProtocol indexBuildProtocol, bool isBackgroundSecondaryBuild) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); - KVPrefix prefix = KVPrefix::getNextPrefix(ns); + KVPrefix prefix = KVPrefix::getNextPrefix(NamespaceString(md.ns)); BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = spec->infoObj(); imd.ready = false; @@ -1020,13 +972,13 @@ Status DurableCatalogImpl::prepareForIndexBuild(OperationContext* opCtx, } md.indexes.push_back(imd); - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); - string ident = getIndexIdent(opCtx, ns, spec->indexName()); + string ident = getIndexIdent(opCtx, catalogId, spec->indexName()); auto kvEngine = _engine->getEngine(); const Status status = kvEngine->createGroupedSortedDataInterface( - opCtx, getCollectionOptions(opCtx, ns), ident, spec, prefix); + opCtx, getCollectionOptions(opCtx, catalogId), ident, spec, prefix); if (status.isOK()) { opCtx->recoveryUnit()->registerChange( std::make_unique<AddIndexChange>(opCtx, _engine, ident)); @@ -1036,9 +988,9 @@ Status DurableCatalogImpl::prepareForIndexBuild(OperationContext* opCtx, } bool DurableCatalogImpl::isTwoPhaseIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].runTwoPhaseBuild; @@ -1046,11 +998,11 @@ bool DurableCatalogImpl::isTwoPhaseIndexBuild(OperationContext* opCtx, void DurableCatalogImpl::setIndexBuildScanning( OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, std::string sideWritesIdent, boost::optional<std::string> constraintViolationsIdent) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); invariant(!md.indexes[offset].ready); @@ -1060,13 +1012,13 @@ void DurableCatalogImpl::setIndexBuildScanning( md.indexes[offset].buildPhase = BSONCollectionCatalogEntry::kIndexBuildScanning.toString(); md.indexes[offset].sideWritesIdent = sideWritesIdent; md.indexes[offset].constraintViolationsIdent = constraintViolationsIdent; - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } bool DurableCatalogImpl::isIndexBuildScanning(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].buildPhase == @@ -1074,9 +1026,9 @@ bool DurableCatalogImpl::isIndexBuildScanning(OperationContext* opCtx, } void DurableCatalogImpl::setIndexBuildDraining(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); invariant(!md.indexes[offset].ready); @@ -1085,13 +1037,13 @@ void DurableCatalogImpl::setIndexBuildDraining(OperationContext* opCtx, BSONCollectionCatalogEntry::kIndexBuildScanning.toString()); md.indexes[offset].buildPhase = BSONCollectionCatalogEntry::kIndexBuildDraining.toString(); - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } bool DurableCatalogImpl::isIndexBuildDraining(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].buildPhase == @@ -1099,9 +1051,9 @@ bool DurableCatalogImpl::isIndexBuildDraining(OperationContext* opCtx, } void DurableCatalogImpl::indexBuildSuccess(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); md.indexes[offset].ready = true; @@ -1109,14 +1061,14 @@ void DurableCatalogImpl::indexBuildSuccess(OperationContext* opCtx, md.indexes[offset].buildPhase = boost::none; md.indexes[offset].sideWritesIdent = boost::none; md.indexes[offset].constraintViolationsIdent = boost::none; - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); } bool DurableCatalogImpl::isIndexMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, MultikeyPaths* multikeyPaths) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); @@ -1129,10 +1081,10 @@ bool DurableCatalogImpl::isIndexMultikey(OperationContext* opCtx, } bool DurableCatalogImpl::setIndexIsMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, const MultikeyPaths& multikeyPaths) { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); @@ -1179,41 +1131,41 @@ bool DurableCatalogImpl::setIndexIsMultikey(OperationContext* opCtx, } } - putMetaData(opCtx, ns, md); + putMetaData(opCtx, catalogId, md); return true; } boost::optional<std::string> DurableCatalogImpl::getConstraintViolationsIdent( - OperationContext* opCtx, NamespaceString ns, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + OperationContext* opCtx, RecordId catalogId, StringData indexName) const { + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].constraintViolationsIdent; } long DurableCatalogImpl::getIndexBuildVersion(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].versionOfBuild; } CollectionOptions DurableCatalogImpl::getCollectionOptions(OperationContext* opCtx, - NamespaceString ns) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + RecordId catalogId) const { + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); return md.options; } -int DurableCatalogImpl::getTotalIndexCount(OperationContext* opCtx, NamespaceString ns) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); +int DurableCatalogImpl::getTotalIndexCount(OperationContext* opCtx, RecordId catalogId) const { + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); return static_cast<int>(md.indexes.size()); } -int DurableCatalogImpl::getCompletedIndexCount(OperationContext* opCtx, NamespaceString ns) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); +int DurableCatalogImpl::getCompletedIndexCount(OperationContext* opCtx, RecordId catalogId) const { + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int num = 0; for (unsigned i = 0; i < md.indexes.size(); i++) { @@ -1224,9 +1176,9 @@ int DurableCatalogImpl::getCompletedIndexCount(OperationContext* opCtx, Namespac } BSONObj DurableCatalogImpl::getIndexSpec(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); @@ -1236,9 +1188,9 @@ BSONObj DurableCatalogImpl::getIndexSpec(OperationContext* opCtx, } void DurableCatalogImpl::getAllIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); for (unsigned i = 0; i < md.indexes.size(); i++) { names->push_back(md.indexes[i].spec["name"].String()); @@ -1246,9 +1198,9 @@ void DurableCatalogImpl::getAllIndexes(OperationContext* opCtx, } void DurableCatalogImpl::getReadyIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); for (unsigned i = 0; i < md.indexes.size(); i++) { if (md.indexes[i].ready) @@ -1257,17 +1209,17 @@ void DurableCatalogImpl::getReadyIndexes(OperationContext* opCtx, } bool DurableCatalogImpl::isIndexPresent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); return offset >= 0; } bool DurableCatalogImpl::isIndexReady(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); @@ -1275,9 +1227,9 @@ bool DurableCatalogImpl::isIndexReady(OperationContext* opCtx, } KVPrefix DurableCatalogImpl::getIndexPrefix(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const { - BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, ns); + BSONCollectionCatalogEntry::MetaData md = getMetaData(opCtx, catalogId); int offset = md.findIndexOffset(indexName); invariant(offset >= 0); return md.indexes[offset].prefix; diff --git a/src/mongo/db/storage/durable_catalog_impl.h b/src/mongo/db/storage/durable_catalog_impl.h index f99ff41da5b..9767f1bb637 100644 --- a/src/mongo/db/storage/durable_catalog_impl.h +++ b/src/mongo/db/storage/durable_catalog_impl.h @@ -65,21 +65,22 @@ public: void init(OperationContext* opCtx); - std::vector<NamespaceString> getAllCollections() const; + std::vector<Entry> getAllCatalogEntries(OperationContext* opCtx) const; - std::string getCollectionIdent(const NamespaceString& nss) const; + Entry getEntry(RecordId catalogId) const; + + std::string getCollectionIdent(RecordId catalogId) const; std::string getIndexIdent(OperationContext* opCtx, - const NamespaceString& nss, - StringData idName) const; + RecordId catalogId, + StringData idxName) const; BSONCollectionCatalogEntry::MetaData getMetaData(OperationContext* opCtx, - const NamespaceString& nss) const; + RecordId catalogId) const; void putMetaData(OperationContext* opCtx, - const NamespaceString& nss, + RecordId catalogId, BSONCollectionCatalogEntry::MetaData& md); - std::vector<std::string> getAllIdentsForDB(StringData db) const; std::vector<std::string> getAllIdents(OperationContext* opCtx) const; bool isUserDataIdent(StringData ident) const; @@ -103,112 +104,113 @@ public: std::string newInternalIdent(); - StatusWith<std::unique_ptr<RecordStore>> createCollection(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& options, - bool allocateDefaultSpace); + StatusWith<std::pair<RecordId, std::unique_ptr<RecordStore>>> createCollection( + OperationContext* opCtx, + const NamespaceString& nss, + const CollectionOptions& options, + bool allocateDefaultSpace); Status renameCollection(OperationContext* opCtx, - const NamespaceString& fromNss, + RecordId catalogId, const NamespaceString& toNss, bool stayTemp); - Status dropCollection(OperationContext* opCtx, const NamespaceString& nss); + Status dropCollection(OperationContext* opCtx, RecordId catalogId); - void updateCappedSize(OperationContext* opCtx, NamespaceString ns, long long size); + void updateCappedSize(OperationContext* opCtx, RecordId catalogId, long long size); void updateTTLSetting(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData idxName, long long newExpireSeconds); bool isEqualToMetadataUUID(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, OptionalCollectionUUID uuid); - void setIsTemp(OperationContext* opCtx, NamespaceString ns, bool isTemp); + void setIsTemp(OperationContext* opCtx, RecordId catalogId, bool isTemp); boost::optional<std::string> getSideWritesIdent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; void updateValidator(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const BSONObj& validator, StringData validationLevel, StringData validationAction); - Status removeIndex(OperationContext* opCtx, NamespaceString ns, StringData indexName); + Status removeIndex(OperationContext* opCtx, RecordId catalogId, StringData indexName); Status prepareForIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, const IndexDescriptor* spec, IndexBuildProtocol indexBuildProtocol, bool isBackgroundSecondaryBuild); bool isTwoPhaseIndexBuild(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; void setIndexBuildScanning(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, std::string sideWritesIdent, boost::optional<std::string> constraintViolationsIdent); bool isIndexBuildScanning(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; - void setIndexBuildDraining(OperationContext* opCtx, NamespaceString ns, StringData indexName); + void setIndexBuildDraining(OperationContext* opCtx, RecordId catalogId, StringData indexName); bool isIndexBuildDraining(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; - void indexBuildSuccess(OperationContext* opCtx, NamespaceString ns, StringData indexName); + void indexBuildSuccess(OperationContext* opCtx, RecordId catalogId, StringData indexName); bool isIndexMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, MultikeyPaths* multikeyPaths) const; bool setIndexIsMultikey(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName, const MultikeyPaths& multikeyPaths); boost::optional<std::string> getConstraintViolationsIdent(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; long getIndexBuildVersion(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; - CollectionOptions getCollectionOptions(OperationContext* opCtx, NamespaceString ns) const; + CollectionOptions getCollectionOptions(OperationContext* opCtx, RecordId catalogId) const; - int getTotalIndexCount(OperationContext* opCtx, NamespaceString ns) const; + int getTotalIndexCount(OperationContext* opCtx, RecordId catalogId) const; - int getCompletedIndexCount(OperationContext* opCtx, NamespaceString ns) const; + int getCompletedIndexCount(OperationContext* opCtx, RecordId catalogId) const; - BSONObj getIndexSpec(OperationContext* opCtx, NamespaceString ns, StringData indexName) const; + BSONObj getIndexSpec(OperationContext* opCtx, RecordId catalogId, StringData indexName) const; void getAllIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const; void getReadyIndexes(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, std::vector<std::string>* names) const; - bool isIndexPresent(OperationContext* opCtx, NamespaceString ns, StringData indexName) const; + bool isIndexPresent(OperationContext* opCtx, RecordId catalogId, StringData indexName) const; - bool isIndexReady(OperationContext* opCtx, NamespaceString ns, StringData indexName) const; + bool isIndexReady(OperationContext* opCtx, RecordId catalogId, StringData indexName) const; KVPrefix getIndexPrefix(OperationContext* opCtx, - NamespaceString ns, + RecordId catalogId, StringData indexName) const; private: @@ -221,25 +223,23 @@ private: friend class DurableCatalogImplTest; friend class StorageEngineTest; - BSONObj _findEntry(OperationContext* opCtx, - const NamespaceString& nss, - RecordId* out = nullptr) const; - Status _addEntry(OperationContext* opCtx, - const NamespaceString& nss, - const CollectionOptions& options, - KVPrefix prefix); + BSONObj _findEntry(OperationContext* opCtx, RecordId catalogId) const; + StatusWith<Entry> _addEntry(OperationContext* opCtx, + NamespaceString nss, + const CollectionOptions& options, + KVPrefix prefix); Status _replaceEntry(OperationContext* opCtx, - const NamespaceString& fromNss, + RecordId catalogId, const NamespaceString& toNss, bool stayTemp); - Status _removeEntry(OperationContext* opCtx, const NamespaceString& nss); + Status _removeEntry(OperationContext* opCtx, RecordId catalogId); /** * Generates a new unique identifier for a new "thing". * @param nss - the containing namespace * @param kind - what this "thing" is, likely collection or index */ - std::string _newUniqueIdent(const NamespaceString& nss, const char* kind); + std::string _newUniqueIdent(NamespaceString nss, const char* kind); // Helpers only used by constructor and init(). Don't call from elsewhere. static std::string _newRand(); @@ -253,15 +253,9 @@ private: std::string _rand; // effectively const after init() returns AtomicWord<unsigned long long> _next; - struct Entry { - Entry() {} - Entry(std::string i, RecordId l) : ident(i), storedLoc(l) {} - std::string ident; - RecordId storedLoc; - }; - typedef std::map<std::string, Entry> NSToIdentMap; - NSToIdentMap _idents; - mutable Mutex _identsLock = MONGO_MAKE_LATCH("DurableCatalogImpl::_identsLock"); + std::map<RecordId, Entry> _catalogIdToEntryMap; + mutable Mutex _catalogIdToEntryMapLock = + MONGO_MAKE_LATCH("DurableCatalogImpl::_catalogIdToEntryMap"); // Manages the feature document that may be present in the DurableCatalogImpl. '_featureTracker' // is guaranteed to be non-null after DurableCatalogImpl::init() is called. diff --git a/src/mongo/db/storage/durable_catalog_test_fixture.h b/src/mongo/db/storage/durable_catalog_test_fixture.h deleted file mode 100644 index 2c895bedef7..00000000000 --- a/src/mongo/db/storage/durable_catalog_test_fixture.h +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (C) 2019-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * <http://www.mongodb.com/licensing/server-side-public-license>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include "mongo/db/storage/durable_catalog_impl.h" -#include "mongo/unittest/unittest.h" - -namespace mongo { -class DurableCatalogImplTest : public unittest::Test { -protected: - Status newCollection(OperationContext* opCtx, - const NamespaceString& ns, - const CollectionOptions& options, - KVPrefix prefix, - DurableCatalogImpl* catalog) { - return catalog->_addEntry(opCtx, ns, options, prefix); - } - Status renameCollection(OperationContext* opCtx, - StringData fromNS, - StringData toNS, - bool stayTemp, - DurableCatalogImpl* catalog) { - return catalog->_replaceEntry( - opCtx, NamespaceString(fromNS), NamespaceString(toNS), stayTemp); - } - - Status dropCollection(OperationContext* opCtx, StringData ns, DurableCatalogImpl* catalog) { - return catalog->_removeEntry(opCtx, NamespaceString(ns)); - } -}; -} // namespace mongo diff --git a/src/mongo/db/storage/kv/durable_catalog_test.cpp b/src/mongo/db/storage/kv/durable_catalog_test.cpp index 2a93def21d7..d8c2be64ff2 100644 --- a/src/mongo/db/storage/kv/durable_catalog_test.cpp +++ b/src/mongo/db/storage/kv/durable_catalog_test.cpp @@ -83,9 +83,11 @@ public: const bool allocateDefaultSpace = true; CollectionOptions options; options.uuid = UUID::gen(); - auto statusWithRecordStore = _storageEngine.getCatalog()->createCollection( + auto swColl = _storageEngine.getCatalog()->createCollection( opCtx.get(), _nss, options, allocateDefaultSpace); - ASSERT_OK(statusWithRecordStore.getStatus()); + ASSERT_OK(swColl.getStatus()); + std::pair<RecordId, std::unique_ptr<RecordStore>> coll = std::move(swColl.getValue()); + _catalogId = coll.first; auto collection = std::make_unique<CollectionMock>(_nss); CollectionCatalog::get(opCtx.get()) .registerCollection(options.uuid.get(), std::move(collection)); @@ -101,6 +103,10 @@ public: return _storageEngine.getCatalog(); } + RecordId getCatalogId() { + return _catalogId; + } + std::string createIndex(BSONObj keyPattern, std::string indexType = IndexNames::BTREE, IndexBuildProtocol protocol = IndexBuildProtocol::kSinglePhase) { @@ -116,7 +122,7 @@ public: WriteUnitOfWork wuow(opCtx.get()); const bool isSecondaryBackgroundIndexBuild = false; ASSERT_OK(_storageEngine.getCatalog()->prepareForIndexBuild( - opCtx.get(), _nss, &desc, protocol, isSecondaryBackgroundIndexBuild)); + opCtx.get(), _catalogId, &desc, protocol, isSecondaryBackgroundIndexBuild)); wuow.commit(); } @@ -153,6 +159,7 @@ private: const NamespaceString _nss; StorageEngineImpl _storageEngine; size_t numIndexesCreated = 0; + RecordId _catalogId; }; TEST_F(DurableCatalogTest, MultikeyPathsForBtreeIndexInitializedToVectorOfEmptySets) { @@ -161,7 +168,7 @@ TEST_F(DurableCatalogTest, MultikeyPathsForBtreeIndexInitializedToVectorOfEmptyS DurableCatalog* catalog = getCatalog(); { MultikeyPaths multikeyPaths; - ASSERT(!catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(!catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {std::set<size_t>{}, std::set<size_t>{}}); } } @@ -170,11 +177,12 @@ TEST_F(DurableCatalogTest, CanSetIndividualPathComponentOfBtreeIndexAsMultikey) std::string indexName = createIndex(BSON("a" << 1 << "b" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {std::set<size_t>{}, {0U}})); + ASSERT(catalog->setIndexIsMultikey( + opCtx.get(), getCatalogId(), indexName, {std::set<size_t>{}, {0U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {std::set<size_t>{}, {0U}}); } } @@ -183,19 +191,21 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentFields) { std::string indexName = createIndex(BSON("a" << 1 << "b" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {std::set<size_t>{}, {0U}})); + ASSERT(catalog->setIndexIsMultikey( + opCtx.get(), getCatalogId(), indexName, {std::set<size_t>{}, {0U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {std::set<size_t>{}, {0U}}); } - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U}, std::set<size_t>{}})); + ASSERT(catalog->setIndexIsMultikey( + opCtx.get(), getCatalogId(), indexName, {{0U}, std::set<size_t>{}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}, {0U}}); } } @@ -204,19 +214,19 @@ TEST_F(DurableCatalogTest, MultikeyPathsAccumulateOnDifferentComponentsOfTheSame std::string indexName = createIndex(BSON("a.b" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U}})); + ASSERT(catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{1U}})); + ASSERT(catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{1U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U, 1U}}); } } @@ -225,19 +235,19 @@ TEST_F(DurableCatalogTest, NoOpWhenSpecifiedPathComponentsAlreadySetAsMultikey) std::string indexName = createIndex(BSON("a" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U}})); + ASSERT(catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } - ASSERT(!catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U}})); + ASSERT(!catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } } @@ -246,11 +256,12 @@ TEST_F(DurableCatalogTest, CanSetMultipleFieldsAndComponentsAsMultikey) { std::string indexName = createIndex(BSON("a.b.c" << 1 << "a.b.d" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U, 1U}, {0U, 1U}})); + ASSERT( + catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{0U, 1U}, {0U, 1U}})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U, 1U}, {0U, 1U}}); } } @@ -261,7 +272,7 @@ DEATH_TEST_F(DurableCatalogTest, std::string indexName = createIndex(BSON("a" << 1 << "b" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, MultikeyPaths{}); + catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, MultikeyPaths{}); } DEATH_TEST_F(DurableCatalogTest, @@ -271,7 +282,7 @@ DEATH_TEST_F(DurableCatalogTest, auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); catalog->setIndexIsMultikey( - opCtx.get(), ns(), indexName, {std::set<size_t>{}, std::set<size_t>{}}); + opCtx.get(), getCatalogId(), indexName, {std::set<size_t>{}, std::set<size_t>{}}); } TEST_F(DurableCatalogTest, PathLevelMultikeyTrackingIsSupportedBy2dsphereIndexes) { @@ -281,7 +292,7 @@ TEST_F(DurableCatalogTest, PathLevelMultikeyTrackingIsSupportedBy2dsphereIndexes DurableCatalog* catalog = getCatalog(); { MultikeyPaths multikeyPaths; - ASSERT(!catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(!catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {std::set<size_t>{}, std::set<size_t>{}}); } } @@ -296,7 +307,8 @@ TEST_F(DurableCatalogTest, PathLevelMultikeyTrackingIsNotSupportedByAllIndexType DurableCatalog* catalog = getCatalog(); { MultikeyPaths multikeyPaths; - ASSERT(!catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT( + !catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); ASSERT(multikeyPaths.empty()); } } @@ -307,11 +319,11 @@ TEST_F(DurableCatalogTest, CanSetEntireTextIndexAsMultikey) { std::string indexName = createIndex(BSON("a" << indexType << "b" << 1), indexType); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, MultikeyPaths{})); + ASSERT(catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, MultikeyPaths{})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); ASSERT(multikeyPaths.empty()); } } @@ -321,19 +333,19 @@ TEST_F(DurableCatalogTest, NoOpWhenEntireIndexAlreadySetAsMultikey) { std::string indexName = createIndex(BSON("a" << indexType << "b" << 1), indexType); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT(catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, MultikeyPaths{})); + ASSERT(catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, MultikeyPaths{})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); ASSERT(multikeyPaths.empty()); } - ASSERT(!catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, MultikeyPaths{})); + ASSERT(!catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, MultikeyPaths{})); { MultikeyPaths multikeyPaths; - ASSERT(catalog->isIndexMultikey(opCtx.get(), ns(), indexName, &multikeyPaths)); + ASSERT(catalog->isIndexMultikey(opCtx.get(), getCatalogId(), indexName, &multikeyPaths)); ASSERT(multikeyPaths.empty()); } } @@ -343,23 +355,25 @@ TEST_F(DurableCatalogTest, SinglePhaseIndexBuild) { auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); - - catalog->indexBuildSuccess(opCtx.get(), ns(), indexName); - - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); + + catalog->indexBuildSuccess(opCtx.get(), getCatalogId(), indexName); + + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); } TEST_F(DurableCatalogTest, TwoPhaseIndexBuild) { @@ -368,46 +382,55 @@ TEST_F(DurableCatalogTest, TwoPhaseIndexBuild) { auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); - - catalog->setIndexBuildScanning( - opCtx.get(), ns(), indexName, kSideWritesTableIdent, kConstraintViolationsTableIdent); - - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_EQ(kSideWritesTableIdent, catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); + + catalog->setIndexBuildScanning(opCtx.get(), + getCatalogId(), + indexName, + kSideWritesTableIdent, + kConstraintViolationsTableIdent); + + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_EQ(kSideWritesTableIdent, + catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); ASSERT_EQ(kConstraintViolationsTableIdent, - catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); - - catalog->setIndexBuildDraining(opCtx.get(), ns(), indexName); - - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_TRUE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_EQ(kSideWritesTableIdent, catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); + catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); + + catalog->setIndexBuildDraining(opCtx.get(), getCatalogId(), indexName); + + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_TRUE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_EQ(kSideWritesTableIdent, + catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); ASSERT_EQ(kConstraintViolationsTableIdent, - catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); - - catalog->indexBuildSuccess(opCtx.get(), ns(), indexName); - - ASSERT_EQ(kExpectedVersion, catalog->getIndexBuildVersion(opCtx.get(), ns(), indexName)); - ASSERT(catalog->isIndexReady(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), ns(), indexName)); - ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), ns(), indexName)); + catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); + + catalog->indexBuildSuccess(opCtx.get(), getCatalogId(), indexName); + + ASSERT_EQ(kExpectedVersion, + catalog->getIndexBuildVersion(opCtx.get(), getCatalogId(), indexName)); + ASSERT(catalog->isIndexReady(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildScanning(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isIndexBuildDraining(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->isTwoPhaseIndexBuild(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getSideWritesIdent(opCtx.get(), getCatalogId(), indexName)); + ASSERT_FALSE(catalog->getConstraintViolationsIdent(opCtx.get(), getCatalogId(), indexName)); } DEATH_TEST_F(DurableCatalogTest, @@ -417,8 +440,11 @@ DEATH_TEST_F(DurableCatalogTest, auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - catalog->setIndexBuildScanning( - opCtx.get(), ns(), indexName, kSideWritesTableIdent, kConstraintViolationsTableIdent); + catalog->setIndexBuildScanning(opCtx.get(), + getCatalogId(), + indexName, + kSideWritesTableIdent, + kConstraintViolationsTableIdent); } DEATH_TEST_F(DurableCatalogTest, @@ -427,7 +453,7 @@ DEATH_TEST_F(DurableCatalogTest, std::string indexName = createIndex(BSON("a" << 1)); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - catalog->setIndexBuildDraining(opCtx.get(), ns(), indexName); + catalog->setIndexBuildDraining(opCtx.get(), getCatalogId(), indexName); } DEATH_TEST_F(DurableCatalogTest, @@ -437,7 +463,7 @@ DEATH_TEST_F(DurableCatalogTest, std::string indexName = createIndex(BSON("a" << indexType << "b" << 1), indexType); auto opCtx = newOperationContext(); DurableCatalog* catalog = getCatalog(); - catalog->setIndexIsMultikey(opCtx.get(), ns(), indexName, {{0U}, {0U}}); + catalog->setIndexIsMultikey(opCtx.get(), getCatalogId(), indexName, {{0U}, {0U}}); } } // namespace diff --git a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp index 8cdd2610162..e9c07d7fdbd 100644 --- a/src/mongo/db/storage/kv/kv_engine_test_harness.cpp +++ b/src/mongo/db/storage/kv/kv_engine_test_harness.cpp @@ -32,7 +32,7 @@ #include "mongo/db/catalog/collection_impl.h" #include "mongo/db/index/index_descriptor.h" #include "mongo/db/operation_context_noop.h" -#include "mongo/db/storage/durable_catalog_test_fixture.h" +#include "mongo/db/storage/durable_catalog_impl.h" #include "mongo/db/storage/kv/kv_engine.h" #include "mongo/db/storage/kv/kv_prefix.h" #include "mongo/db/storage/record_store.h" @@ -44,6 +44,34 @@ #include "mongo/util/scopeguard.h" namespace mongo { + +class DurableCatalogImplTest : public unittest::Test { +protected: + RecordId newCollection(OperationContext* opCtx, + const NamespaceString& ns, + const CollectionOptions& options, + KVPrefix prefix, + DurableCatalogImpl* catalog) { + auto swEntry = catalog->_addEntry(opCtx, ns, options, prefix); + ASSERT_OK(swEntry.getStatus()); + return swEntry.getValue().catalogId; + } + + Status renameCollection(OperationContext* opCtx, + RecordId catalogId, + StringData toNS, + bool stayTemp, + DurableCatalogImpl* catalog) { + return catalog->_replaceEntry(opCtx, catalogId, NamespaceString(toNS), stayTemp); + } + + Status dropCollection(OperationContext* opCtx, + RecordId catalogId, + DurableCatalogImpl* catalog) { + return catalog->_removeEntry(opCtx, catalogId); + } +}; + namespace { std::function<std::unique_ptr<KVHarnessHelper>()> basicFactory = @@ -161,7 +189,8 @@ TEST(KVEngineTestHarness, SimpleSorted1) { { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - collection = std::make_unique<CollectionImpl>(&opCtx, ns, UUID::gen(), std::move(rs)); + collection = + std::make_unique<CollectionImpl>(&opCtx, ns, RecordId(0), UUID::gen(), std::move(rs)); uow.commit(); } @@ -318,19 +347,20 @@ TEST_F(DurableCatalogImplTest, Coll1) { uow.commit(); } + RecordId catalogId; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get())); - ASSERT_NOT_EQUALS("a.b", catalog->getCollectionIdent(NamespaceString("a.b"))); + catalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); + ASSERT_NOT_EQUALS("a.b", catalog->getEntry(catalogId).ident); uow.commit(); } - std::string ident = catalog->getCollectionIdent(NamespaceString("a.b")); + std::string ident = catalog->getEntry(catalogId).ident; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); @@ -338,21 +368,21 @@ TEST_F(DurableCatalogImplTest, Coll1) { catalog->init(&opCtx); uow.commit(); } - ASSERT_EQUALS(ident, catalog->getCollectionIdent(NamespaceString("a.b"))); + ASSERT_EQUALS(ident, catalog->getEntry(catalogId).ident); + RecordId newCatalogId; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - dropCollection(&opCtx, "a.b", catalog.get()).transitional_ignore(); - newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get()) - .transitional_ignore(); + dropCollection(&opCtx, catalogId, catalog.get()).transitional_ignore(); + newCatalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); uow.commit(); } - ASSERT_NOT_EQUALS(ident, catalog->getCollectionIdent(NamespaceString("a.b"))); + ASSERT_NOT_EQUALS(ident, catalog->getEntry(newCatalogId).ident); } TEST_F(DurableCatalogImplTest, Idx1) { @@ -370,16 +400,17 @@ TEST_F(DurableCatalogImplTest, Idx1) { uow.commit(); } + RecordId catalogId; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get())); - ASSERT_NOT_EQUALS("a.b", catalog->getCollectionIdent(NamespaceString("a.b"))); - ASSERT_TRUE(catalog->isUserDataIdent(catalog->getCollectionIdent(NamespaceString("a.b")))); + catalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); + ASSERT_NOT_EQUALS("a.b", catalog->getEntry(catalogId).ident); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getEntry(catalogId).ident)); uow.commit(); } @@ -398,21 +429,20 @@ TEST_F(DurableCatalogImplTest, Idx1) { imd.prefix = KVPrefix::kNotPrefixed; imd.isBackgroundSecondaryBuild = false; md.indexes.push_back(imd); - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); + catalog->putMetaData(&opCtx, catalogId, md); uow.commit(); } std::string idxIndent; { MyOperationContext opCtx(engine); - idxIndent = catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"); + idxIndent = catalog->getIndexIdent(&opCtx, catalogId, "foo"); } { MyOperationContext opCtx(engine); - ASSERT_EQUALS(idxIndent, catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo")); - ASSERT_TRUE(catalog->isUserDataIdent( - catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"))); + ASSERT_EQUALS(idxIndent, catalog->getIndexIdent(&opCtx, catalogId, "foo")); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getIndexIdent(&opCtx, catalogId, "foo"))); } { @@ -421,7 +451,7 @@ TEST_F(DurableCatalogImplTest, Idx1) { BSONCollectionCatalogEntry::MetaData md; md.ns = "a.b"; - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); // remove index + catalog->putMetaData(&opCtx, catalogId, md); // remove index BSONCollectionCatalogEntry::IndexMetaData imd; imd.spec = BSON("name" @@ -431,13 +461,13 @@ TEST_F(DurableCatalogImplTest, Idx1) { imd.prefix = KVPrefix::kNotPrefixed; imd.isBackgroundSecondaryBuild = false; md.indexes.push_back(imd); - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); + catalog->putMetaData(&opCtx, catalogId, md); uow.commit(); } { MyOperationContext opCtx(engine); - ASSERT_NOT_EQUALS(idxIndent, catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo")); + ASSERT_NOT_EQUALS(idxIndent, catalog->getIndexIdent(&opCtx, catalogId, "foo")); } } @@ -456,16 +486,17 @@ TEST_F(DurableCatalogImplTest, DirectoryPerDb1) { uow.commit(); } + RecordId catalogId; { // collection MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get())); - ASSERT_STRING_CONTAINS(catalog->getCollectionIdent(NamespaceString("a.b")), "a/"); - ASSERT_TRUE(catalog->isUserDataIdent(catalog->getCollectionIdent(NamespaceString("a.b")))); + catalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); + ASSERT_STRING_CONTAINS(catalog->getEntry(catalogId).ident, "a/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getEntry(catalogId).ident)); uow.commit(); } @@ -484,10 +515,9 @@ TEST_F(DurableCatalogImplTest, DirectoryPerDb1) { imd.prefix = KVPrefix::kNotPrefixed; imd.isBackgroundSecondaryBuild = false; md.indexes.push_back(imd); - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); - ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"), "a/"); - ASSERT_TRUE(catalog->isUserDataIdent( - catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"))); + catalog->putMetaData(&opCtx, catalogId, md); + ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, catalogId, "foo"), "a/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getIndexIdent(&opCtx, catalogId, "foo"))); uow.commit(); } } @@ -507,16 +537,17 @@ TEST_F(DurableCatalogImplTest, Split1) { uow.commit(); } + RecordId catalogId; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get())); - ASSERT_STRING_CONTAINS(catalog->getCollectionIdent(NamespaceString("a.b")), "collection/"); - ASSERT_TRUE(catalog->isUserDataIdent(catalog->getCollectionIdent(NamespaceString("a.b")))); + catalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); + ASSERT_STRING_CONTAINS(catalog->getEntry(catalogId).ident, "collection/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getEntry(catalogId).ident)); uow.commit(); } @@ -535,11 +566,9 @@ TEST_F(DurableCatalogImplTest, Split1) { imd.prefix = KVPrefix::kNotPrefixed; imd.isBackgroundSecondaryBuild = false; md.indexes.push_back(imd); - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); - ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"), - "index/"); - ASSERT_TRUE(catalog->isUserDataIdent( - catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"))); + catalog->putMetaData(&opCtx, catalogId, md); + ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, catalogId, "foo"), "index/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getIndexIdent(&opCtx, catalogId, "foo"))); uow.commit(); } } @@ -559,17 +588,17 @@ TEST_F(DurableCatalogImplTest, DirectoryPerAndSplit1) { uow.commit(); } + RecordId catalogId; { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection(&opCtx, - NamespaceString("a.b"), - CollectionOptions(), - KVPrefix::kNotPrefixed, - catalog.get())); - ASSERT_STRING_CONTAINS(catalog->getCollectionIdent(NamespaceString("a.b")), - "a/collection/"); - ASSERT_TRUE(catalog->isUserDataIdent(catalog->getCollectionIdent(NamespaceString("a.b")))); + catalogId = newCollection(&opCtx, + NamespaceString("a.b"), + CollectionOptions(), + KVPrefix::kNotPrefixed, + catalog.get()); + ASSERT_STRING_CONTAINS(catalog->getEntry(catalogId).ident, "a/collection/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getEntry(catalogId).ident)); uow.commit(); } @@ -588,85 +617,13 @@ TEST_F(DurableCatalogImplTest, DirectoryPerAndSplit1) { imd.prefix = KVPrefix::kNotPrefixed; imd.isBackgroundSecondaryBuild = false; md.indexes.push_back(imd); - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); - ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"), - "a/index/"); - ASSERT_TRUE(catalog->isUserDataIdent( - catalog->getIndexIdent(&opCtx, NamespaceString("a.b"), "foo"))); + catalog->putMetaData(&opCtx, catalogId, md); + ASSERT_STRING_CONTAINS(catalog->getIndexIdent(&opCtx, catalogId, "foo"), "a/index/"); + ASSERT_TRUE(catalog->isUserDataIdent(catalog->getIndexIdent(&opCtx, catalogId, "foo"))); uow.commit(); } } -TEST_F(DurableCatalogImplTest, RestartForPrefixes) { - storageGlobalParams.groupCollections = true; - ON_BLOCK_EXIT([&] { storageGlobalParams.groupCollections = false; }); - - KVPrefix abCollPrefix = KVPrefix::getNextPrefix(NamespaceString("a.b")); - KVPrefix fooIndexPrefix = KVPrefix::getNextPrefix(NamespaceString("a.b")); - - std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); - KVEngine* engine = helper->getEngine(); - { - std::unique_ptr<RecordStore> rs; - std::unique_ptr<DurableCatalogImpl> catalog; - { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - ASSERT_OK(engine->createRecordStore(&opCtx, "catalog", "catalog", CollectionOptions())); - rs = engine->getRecordStore(&opCtx, "catalog", "catalog", CollectionOptions()); - catalog = std::make_unique<DurableCatalogImpl>(rs.get(), false, false, nullptr); - uow.commit(); - } - - { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - ASSERT_OK(newCollection( - &opCtx, NamespaceString("a.b"), CollectionOptions(), abCollPrefix, catalog.get())); - ASSERT_NOT_EQUALS("a.b", catalog->getCollectionIdent(NamespaceString("a.b"))); - ASSERT_TRUE( - catalog->isUserDataIdent(catalog->getCollectionIdent(NamespaceString("a.b")))); - uow.commit(); - } - - { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - - BSONCollectionCatalogEntry::MetaData md; - md.ns = "a.b"; - - BSONCollectionCatalogEntry::IndexMetaData imd; - imd.spec = BSON("name" - << "foo"); - imd.ready = false; - imd.multikey = false; - imd.prefix = fooIndexPrefix; - imd.isBackgroundSecondaryBuild = false; - md.indexes.push_back(imd); - md.prefix = abCollPrefix; - catalog->putMetaData(&opCtx, NamespaceString("a.b"), md); - uow.commit(); - } - } - - engine = helper->restartEngine(); - { - MyOperationContext opCtx(engine); - WriteUnitOfWork uow(&opCtx); - std::unique_ptr<RecordStore> rs = - engine->getRecordStore(&opCtx, "catalog", "catalog", CollectionOptions()); - auto catalog = std::make_unique<DurableCatalogImpl>(rs.get(), false, false, nullptr); - catalog->init(&opCtx); - - const BSONCollectionCatalogEntry::MetaData md = - catalog->getMetaData(&opCtx, NamespaceString("a.b")); - ASSERT_EQ("a.b", md.ns); - ASSERT_EQ(abCollPrefix, md.prefix); - ASSERT_EQ(fooIndexPrefix, md.indexes[md.findIndexOffset("foo")].prefix); - } -} - TEST_F(DurableCatalogImplTest, BackupImplemented) { std::unique_ptr<KVHarnessHelper> helper(KVHarnessHelper::create()); KVEngine* engine = helper->getEngine(); @@ -701,7 +658,8 @@ DEATH_TEST_F(DurableCatalogImplTest, TerminateOnNonNumericIndexVersion, "Fatal A { MyOperationContext opCtx(engine); WriteUnitOfWork uow(&opCtx); - collection = std::make_unique<CollectionImpl>(&opCtx, ns, UUID::gen(), std::move(rs)); + collection = + std::make_unique<CollectionImpl>(&opCtx, ns, RecordId(0), UUID::gen(), std::move(rs)); uow.commit(); } diff --git a/src/mongo/db/storage/kv/storage_engine_test.cpp b/src/mongo/db/storage/kv/storage_engine_test.cpp index cf3f7d10b70..93423116d78 100644 --- a/src/mongo/db/storage/kv/storage_engine_test.cpp +++ b/src/mongo/db/storage/kv/storage_engine_test.cpp @@ -62,8 +62,8 @@ TEST_F(StorageEngineTest, ReconcileIdentsTest) { // Add a collection, `db.coll1` to both the DurableCatalog and KVEngine. The returned value is // the `ident` name given to the collection. - auto swIdentName = createCollection(opCtx.get(), NamespaceString("db.coll1")); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), NamespaceString("db.coll1")); + ASSERT_OK(swCollInfo.getStatus()); // Create a table in the KVEngine not reflected in the DurableCatalog. This should be dropped // when reconciling. ASSERT_OK(createCollTable(opCtx.get(), NamespaceString("db.coll2"))); @@ -72,7 +72,7 @@ TEST_F(StorageEngineTest, ReconcileIdentsTest) { auto idents = std::set<std::string>(identsVec.begin(), identsVec.end()); // There are two idents. `_mdb_catalog` and the ident for `db.coll1`. ASSERT_EQUALS(static_cast<const unsigned long>(2), idents.size()); - ASSERT_TRUE(idents.find(swIdentName.getValue()) != idents.end()); + ASSERT_TRUE(idents.find(swCollInfo.getValue().ident) != idents.end()); ASSERT_TRUE(idents.find("_mdb_catalog") != idents.end()); // Create a catalog entry for the `_id` index. Drop the created the table. @@ -83,12 +83,12 @@ TEST_F(StorageEngineTest, ReconcileIdentsTest) { auto reconcileStatus = reconcile(opCtx.get()); ASSERT_OK(reconcileStatus.getStatus()); ASSERT_EQUALS(static_cast<const unsigned long>(1), reconcileStatus.getValue().size()); - StorageEngine::CollectionIndexNamePair& toRebuild = reconcileStatus.getValue()[0]; - ASSERT_EQUALS("db.coll1", toRebuild.first); - ASSERT_EQUALS("_id", toRebuild.second); + StorageEngine::IndexIdentifier& toRebuild = reconcileStatus.getValue()[0]; + ASSERT_EQUALS("db.coll1", toRebuild.nss.ns()); + ASSERT_EQUALS("_id", toRebuild.indexName); // Now drop the `db.coll1` table, while leaving the DurableCatalog entry. - ASSERT_OK(dropIdent(opCtx.get(), swIdentName.getValue())); + ASSERT_OK(dropIdent(opCtx.get(), swCollInfo.getValue().ident)); ASSERT_EQUALS(static_cast<const unsigned long>(1), getAllKVEngineIdents(opCtx.get()).size()); // Reconciling this should result in an error. @@ -101,10 +101,10 @@ TEST_F(StorageEngineTest, LoadCatalogDropsOrphansAfterUncleanShutdown) { auto opCtx = cc().makeOperationContext(); const NamespaceString collNs("db.coll1"); - auto swIdentName = createCollection(opCtx.get(), collNs); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), collNs); + ASSERT_OK(swCollInfo.getStatus()); - ASSERT_OK(dropIdent(opCtx.get(), swIdentName.getValue())); + ASSERT_OK(dropIdent(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), collNs)); // After the catalog is reloaded, we expect that the collection has been dropped because the @@ -116,7 +116,7 @@ TEST_F(StorageEngineTest, LoadCatalogDropsOrphansAfterUncleanShutdown) { _storageEngine->loadCatalog(opCtx.get()); } - ASSERT(!identExists(opCtx.get(), swIdentName.getValue())); + ASSERT(!identExists(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(!collectionExists(opCtx.get(), collNs)); } @@ -167,8 +167,8 @@ TEST_F(StorageEngineTest, ReconcileDoesNotDropIndexBuildTempTables) { const NamespaceString ns("db.coll1"); const std::string indexName("a_1"); - auto swIdentName = createCollection(opCtx.get(), ns); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), ns); + ASSERT_OK(swCollInfo.getStatus()); const bool isBackgroundSecondaryBuild = false; ASSERT_OK(startIndexBuild(opCtx.get(), ns, indexName, isBackgroundSecondaryBuild)); @@ -176,7 +176,8 @@ TEST_F(StorageEngineTest, ReconcileDoesNotDropIndexBuildTempTables) { auto sideWrites = makeTemporary(opCtx.get()); auto constraintViolations = makeTemporary(opCtx.get()); - const auto indexIdent = _storageEngine->getCatalog()->getIndexIdent(opCtx.get(), ns, indexName); + const auto indexIdent = _storageEngine->getCatalog()->getIndexIdent( + opCtx.get(), swCollInfo.getValue().catalogId, indexName); indexBuildScan(opCtx.get(), ns, @@ -208,8 +209,8 @@ TEST_F(StorageEngineTest, ReconcileDoesNotDropIndexBuildTempTablesBackgroundSeco const NamespaceString ns("db.coll1"); const std::string indexName("a_1"); - auto swIdentName = createCollection(opCtx.get(), ns); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), ns); + ASSERT_OK(swCollInfo.getStatus()); const bool isBackgroundSecondaryBuild = true; ASSERT_OK(startIndexBuild(opCtx.get(), ns, indexName, isBackgroundSecondaryBuild)); @@ -217,7 +218,8 @@ TEST_F(StorageEngineTest, ReconcileDoesNotDropIndexBuildTempTablesBackgroundSeco auto sideWrites = makeTemporary(opCtx.get()); auto constraintViolations = makeTemporary(opCtx.get()); - const auto indexIdent = _storageEngine->getCatalog()->getIndexIdent(opCtx.get(), ns, indexName); + const auto indexIdent = _storageEngine->getCatalog()->getIndexIdent( + opCtx.get(), swCollInfo.getValue().catalogId, indexName); indexBuildScan(opCtx.get(), ns, @@ -233,9 +235,9 @@ TEST_F(StorageEngineTest, ReconcileDoesNotDropIndexBuildTempTablesBackgroundSeco // Because this backgroundSecondary index is unfinished, reconcile will identify that it should // be rebuilt. ASSERT_EQUALS(1UL, reconcileStatus.getValue().size()); - StorageEngine::CollectionIndexNamePair& toRebuild = reconcileStatus.getValue()[0]; - ASSERT_EQUALS(ns.toString(), toRebuild.first); - ASSERT_EQUALS(indexName, toRebuild.second); + StorageEngine::IndexIdentifier& toRebuild = reconcileStatus.getValue()[0]; + ASSERT_EQUALS(ns, toRebuild.nss); + ASSERT_EQUALS(indexName, toRebuild.indexName); // Because these temporary idents were associated with an in-progress index build, they are not // dropped. @@ -250,10 +252,10 @@ TEST_F(StorageEngineRepairTest, LoadCatalogRecoversOrphans) { auto opCtx = cc().makeOperationContext(); const NamespaceString collNs("db.coll1"); - auto swIdentName = createCollection(opCtx.get(), collNs); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), collNs); + ASSERT_OK(swCollInfo.getStatus()); - ASSERT_OK(dropIdent(opCtx.get(), swIdentName.getValue())); + ASSERT_OK(dropIdent(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), collNs)); // After the catalog is reloaded, we expect that the ident has been recovered because the @@ -264,7 +266,7 @@ TEST_F(StorageEngineRepairTest, LoadCatalogRecoversOrphans) { _storageEngine->loadCatalog(opCtx.get()); } - ASSERT(identExists(opCtx.get(), swIdentName.getValue())); + ASSERT(identExists(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), collNs)); StorageRepairObserver::get(getGlobalServiceContext())->onRepairDone(opCtx.get()); ASSERT_EQ(1U, StorageRepairObserver::get(getGlobalServiceContext())->getModifications().size()); @@ -274,17 +276,17 @@ TEST_F(StorageEngineRepairTest, ReconcileSucceeds) { auto opCtx = cc().makeOperationContext(); const NamespaceString collNs("db.coll1"); - auto swIdentName = createCollection(opCtx.get(), collNs); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), collNs); + ASSERT_OK(swCollInfo.getStatus()); - ASSERT_OK(dropIdent(opCtx.get(), swIdentName.getValue())); + ASSERT_OK(dropIdent(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), collNs)); // Reconcile would normally return an error if a collection existed with a missing ident in the // storage engine. When in a repair context, that should not be the case. ASSERT_OK(reconcile(opCtx.get()).getStatus()); - ASSERT(!identExists(opCtx.get(), swIdentName.getValue())); + ASSERT(!identExists(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), collNs)); StorageRepairObserver::get(getGlobalServiceContext())->onRepairDone(opCtx.get()); ASSERT_EQ(0U, StorageRepairObserver::get(getGlobalServiceContext())->getModifications().size()); @@ -294,8 +296,8 @@ TEST_F(StorageEngineRepairTest, LoadCatalogRecoversOrphansInCatalog) { auto opCtx = cc().makeOperationContext(); const NamespaceString collNs("db.coll1"); - auto swIdentName = createCollection(opCtx.get(), collNs); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), collNs); + ASSERT_OK(swCollInfo.getStatus()); ASSERT(collectionExists(opCtx.get(), collNs)); AutoGetDb db(opCtx.get(), collNs.db(), LockMode::MODE_X); @@ -307,11 +309,11 @@ TEST_F(StorageEngineRepairTest, LoadCatalogRecoversOrphansInCatalog) { // When in a repair context, loadCatalog() recreates catalog entries for orphaned idents. _storageEngine->loadCatalog(opCtx.get()); - auto identNs = swIdentName.getValue(); + auto identNs = swCollInfo.getValue().ident; std::replace(identNs.begin(), identNs.end(), '-', '_'); NamespaceString orphanNs = NamespaceString("local.orphan." + identNs); - ASSERT(identExists(opCtx.get(), swIdentName.getValue())); + ASSERT(identExists(opCtx.get(), swCollInfo.getValue().ident)); ASSERT(collectionExists(opCtx.get(), orphanNs)); StorageRepairObserver::get(getGlobalServiceContext())->onRepairDone(opCtx.get()); @@ -322,8 +324,8 @@ TEST_F(StorageEngineTest, LoadCatalogDropsOrphans) { auto opCtx = cc().makeOperationContext(); const NamespaceString collNs("db.coll1"); - auto swIdentName = createCollection(opCtx.get(), collNs); - ASSERT_OK(swIdentName); + auto swCollInfo = createCollection(opCtx.get(), collNs); + ASSERT_OK(swCollInfo.getStatus()); ASSERT(collectionExists(opCtx.get(), collNs)); AutoGetDb db(opCtx.get(), collNs.db(), LockMode::MODE_X); @@ -339,8 +341,8 @@ TEST_F(StorageEngineTest, LoadCatalogDropsOrphans) { // reconcileCatalogAndIdents() drops orphaned idents. ASSERT_OK(reconcile(opCtx.get()).getStatus()); - ASSERT(!identExists(opCtx.get(), swIdentName.getValue())); - auto identNs = swIdentName.getValue(); + ASSERT(!identExists(opCtx.get(), swCollInfo.getValue().ident)); + auto identNs = swCollInfo.getValue().ident; std::replace(identNs.begin(), identNs.end(), '-', '_'); NamespaceString orphanNs = NamespaceString("local.orphan." + identNs); ASSERT(!collectionExists(opCtx.get(), orphanNs)); diff --git a/src/mongo/db/storage/storage_engine.h b/src/mongo/db/storage/storage_engine.h index 28b9aeb5f59..6b156ce3de6 100644 --- a/src/mongo/db/storage/storage_engine.h +++ b/src/mongo/db/storage/storage_engine.h @@ -313,7 +313,9 @@ public: * Generally, this method should not be called directly except by the repairDatabase() * free function. */ - virtual Status repairRecordStore(OperationContext* opCtx, const NamespaceString& nss) = 0; + virtual Status repairRecordStore(OperationContext* opCtx, + RecordId catalogId, + const NamespaceString& nss) = 0; /** * Creates a temporary RecordStore on the storage engine. This record store will drop itself @@ -488,14 +490,17 @@ public: */ virtual void triggerJournalFlush() const = 0; - // (CollectionName, IndexName) - typedef std::pair<std::string, std::string> CollectionIndexNamePair; + struct IndexIdentifier { + const RecordId catalogId; + const NamespaceString nss; + const std::string indexName; + }; /** * Drop abandoned idents. In the successful case, returns a list of collection, index name * pairs to rebuild. */ - virtual StatusWith<std::vector<CollectionIndexNamePair>> reconcileCatalogAndIdents( + virtual StatusWith<std::vector<IndexIdentifier>> reconcileCatalogAndIdents( OperationContext* opCtx) = 0; /** diff --git a/src/mongo/db/storage/storage_engine_impl.cpp b/src/mongo/db/storage/storage_engine_impl.cpp index 1ab796a55ea..f7b203741a6 100644 --- a/src/mongo/db/storage/storage_engine_impl.cpp +++ b/src/mongo/db/storage/storage_engine_impl.cpp @@ -137,8 +137,7 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { std::sort(identsKnownToStorageEngine.begin(), identsKnownToStorageEngine.end()); } - auto collectionsKnownToCatalog = _catalog->getAllCollections(); - + std::vector<DurableCatalog::Entry> catalogEntries = _catalog->getAllCatalogEntries(opCtx); if (_options.forRepair) { // It's possible that there are collection files on disk that are unknown to the catalog. In // a repair context, if we can't find an ident in the catalog, we generate a catalog entry @@ -146,12 +145,10 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { // will be dropped in reconcileCatalogAndIdents(). for (const auto& ident : identsKnownToStorageEngine) { if (_catalog->isCollectionIdent(ident)) { - bool isOrphan = !std::any_of(collectionsKnownToCatalog.begin(), - collectionsKnownToCatalog.end(), - [this, &ident](const auto& coll) { - return _catalog->getCollectionIdent( - NamespaceString(coll)) == ident; - }); + bool isOrphan = !std::any_of( + catalogEntries.begin(), + catalogEntries.end(), + [this, &ident](DurableCatalog::Entry entry) { return entry.ident == ident; }); if (isOrphan) { // If the catalog does not have information about this // collection, we create an new entry for it. @@ -185,15 +182,13 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { } KVPrefix maxSeenPrefix = KVPrefix::kNotPrefixed; - for (const auto& nss : collectionsKnownToCatalog) { - std::string dbName = nss.db().toString(); - + for (DurableCatalog::Entry entry : catalogEntries) { if (loadingFromUncleanShutdownOrRepair) { // If we are loading the catalog after an unclean shutdown or during repair, it's // possible that there are collections in the catalog that are unknown to the storage // engine. If we can't find a table in the list of storage engine idents, either // attempt to recover the ident or drop it. - const auto collectionIdent = _catalog->getCollectionIdent(nss); + const auto collectionIdent = entry.ident; bool orphan = !std::binary_search(identsKnownToStorageEngine.begin(), identsKnownToStorageEngine.end(), collectionIdent); @@ -201,17 +196,18 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { // store, drop it from the catalog and skip initializing it by continuing past the // following logic. if (orphan) { - auto status = _recoverOrphanedCollection(opCtx, nss, collectionIdent); + auto status = + _recoverOrphanedCollection(opCtx, entry.catalogId, entry.nss, collectionIdent); if (!status.isOK()) { - warning() << "Failed to recover orphaned data file for collection '" << nss - << "': " << status; + warning() << "Failed to recover orphaned data file for collection '" + << entry.nss << "': " << status; WriteUnitOfWork wuow(opCtx); - fassert(50716, _catalog->_removeEntry(opCtx, nss)); + fassert(50716, _catalog->_removeEntry(opCtx, entry.catalogId)); if (_options.forRepair) { StorageRepairObserver::get(getGlobalServiceContext()) ->invalidatingModification(str::stream() - << "Collection " << nss + << "Collection " << entry.nss << " dropped: " << status.reason()); } wuow.commit(); @@ -220,12 +216,12 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { } } - _initCollection(opCtx, nss, _options.forRepair); - auto maxPrefixForCollection = _catalog->getMetaData(opCtx, nss).getMaxPrefix(); + _initCollection(opCtx, entry.catalogId, entry.nss, _options.forRepair); + auto maxPrefixForCollection = _catalog->getMetaData(opCtx, entry.catalogId).getMaxPrefix(); maxSeenPrefix = std::max(maxSeenPrefix, maxPrefixForCollection); - if (nss.isOrphanCollection()) { - log() << "Orphaned collection found: " << nss; + if (entry.nss.isOrphanCollection()) { + log() << "Orphaned collection found: " << entry.nss; } } @@ -238,14 +234,15 @@ void StorageEngineImpl::loadCatalog(OperationContext* opCtx) { } void StorageEngineImpl::_initCollection(OperationContext* opCtx, + RecordId catalogId, const NamespaceString& nss, bool forRepair) { - BSONCollectionCatalogEntry::MetaData md = _catalog->getMetaData(opCtx, nss); + BSONCollectionCatalogEntry::MetaData md = _catalog->getMetaData(opCtx, catalogId); uassert(ErrorCodes::MustDowngrade, str::stream() << "Collection does not have UUID in KVCatalog. Collection: " << nss, md.options.uuid); - auto ident = _catalog->getCollectionIdent(nss); + auto ident = _catalog->getEntry(catalogId).ident; std::unique_ptr<RecordStore> rs; if (forRepair) { @@ -257,10 +254,10 @@ void StorageEngineImpl::_initCollection(OperationContext* opCtx, invariant(rs); } - auto uuid = _catalog->getCollectionOptions(opCtx, nss).uuid.get(); + auto uuid = _catalog->getCollectionOptions(opCtx, catalogId).uuid.get(); auto collectionFactory = Collection::Factory::get(getGlobalServiceContext()); - auto collection = collectionFactory->make(opCtx, nss, uuid, std::move(rs)); + auto collection = collectionFactory->make(opCtx, nss, catalogId, uuid, std::move(rs)); auto& collectionCatalog = CollectionCatalog::get(getGlobalServiceContext()); collectionCatalog.registerCollection(uuid, std::move(collection)); @@ -279,6 +276,7 @@ void StorageEngineImpl::closeCatalog(OperationContext* opCtx) { } Status StorageEngineImpl::_recoverOrphanedCollection(OperationContext* opCtx, + RecordId catalogId, const NamespaceString& collectionName, StringData collectionIdent) { if (!_options.forRepair) { @@ -289,11 +287,10 @@ Status StorageEngineImpl::_recoverOrphanedCollection(OperationContext* opCtx, << collectionIdent; WriteUnitOfWork wuow(opCtx); - const auto metadata = _catalog->getMetaData(opCtx, collectionName); - auto status = + const auto metadata = _catalog->getMetaData(opCtx, catalogId); + Status status = _engine->recoverOrphanedIdent(opCtx, collectionName, collectionIdent, metadata.options); - bool dataModified = status.code() == ErrorCodes::DataModifiedByRepair; if (!status.isOK() && !dataModified) { return status; @@ -320,7 +317,7 @@ Status StorageEngineImpl::_recoverOrphanedCollection(OperationContext* opCtx, * Third, a DurableCatalog may have an index ident that the KVEngine does not. This method will * rebuild the index. */ -StatusWith<std::vector<StorageEngine::CollectionIndexNamePair>> +StatusWith<std::vector<StorageEngine::IndexIdentifier>> StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { // Gather all tables known to the storage engine and drop those that aren't cross-referenced // in the _mdb_catalog. This can happen for two reasons. @@ -392,14 +389,13 @@ StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { // engine. An omission here is fatal. A missing ident could mean a collection drop was rolled // back. Note that startup already attempts to open tables; this should only catch errors in // other contexts such as `recoverToStableTimestamp`. - auto collections = _catalog->getAllCollections(); + std::vector<DurableCatalog::Entry> catalogEntries = _catalog->getAllCatalogEntries(opCtx); if (!_options.forRepair) { - for (const auto& coll : collections) { - const auto& identForColl = _catalog->getCollectionIdent(coll); - if (engineIdents.find(identForColl) == engineIdents.end()) { + for (DurableCatalog::Entry entry : catalogEntries) { + if (engineIdents.find(entry.ident) == engineIdents.end()) { return {ErrorCodes::UnrecoverableRollbackError, - str::stream() << "Expected collection does not exist. Collection: " << coll - << " Ident: " << identForColl}; + str::stream() << "Expected collection does not exist. Collection: " + << entry.nss << " Ident: " << entry.ident}; } } } @@ -409,15 +405,17 @@ StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { // // Also, remove unfinished builds except those that were background index builds started on a // secondary. - std::vector<CollectionIndexNamePair> ret; - for (const auto& coll : collections) { - BSONCollectionCatalogEntry::MetaData metaData = _catalog->getMetaData(opCtx, coll); + std::vector<StorageEngine::IndexIdentifier> ret; + for (DurableCatalog::Entry entry : catalogEntries) { + BSONCollectionCatalogEntry::MetaData metaData = + _catalog->getMetaData(opCtx, entry.catalogId); + NamespaceString coll(metaData.ns); // Batch up the indexes to remove them from `metaData` outside of the iterator. std::vector<std::string> indexesToDrop; for (const auto& indexMetaData : metaData.indexes) { const std::string& indexName = indexMetaData.name(); - std::string indexIdent = _catalog->getIndexIdent(opCtx, coll, indexName); + std::string indexIdent = _catalog->getIndexIdent(opCtx, entry.catalogId, indexName); // Warn in case of incorrect "multikeyPath" information in catalog documents. This is // the result of a concurrency bug which has since been fixed, but may persist in @@ -442,7 +440,7 @@ StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { if (indexMetaData.ready && !foundIdent) { log() << "Expected index data is missing, rebuilding. Collection: " << coll << " Index: " << indexName; - ret.emplace_back(coll.ns(), indexName); + ret.push_back({entry.catalogId, coll, indexName}); continue; } @@ -488,7 +486,7 @@ StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { log() << "Expected background index build did not complete, rebuilding. " "Collection: " << coll << " Index: " << indexName; - ret.emplace_back(coll.ns(), indexName); + ret.push_back({entry.catalogId, coll, indexName}); continue; } @@ -515,7 +513,7 @@ StorageEngineImpl::reconcileCatalogAndIdents(OperationContext* opCtx) { } if (indexesToDrop.size() > 0) { WriteUnitOfWork wuow(opCtx); - _catalog->putMetaData(opCtx, coll, metaData); + _catalog->putMetaData(opCtx, entry.catalogId, metaData); wuow.commit(); } } @@ -629,17 +627,17 @@ Status StorageEngineImpl::_dropCollectionsNoTimestamp(OperationContext* opCtx, WriteUnitOfWork untimestampedDropWuow(opCtx); for (auto& nss : toDrop) { invariant(getCatalog()); - auto uuid = CollectionCatalog::get(opCtx).lookupUUIDByNSS(nss).get(); - Status result = getCatalog()->dropCollection(opCtx, nss); + auto coll = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss); + Status result = getCatalog()->dropCollection(opCtx, coll->getCatalogId()); if (!result.isOK() && firstError.isOK()) { firstError = result; } - auto removedColl = CollectionCatalog::get(opCtx).deregisterCollection(uuid); + auto removedColl = CollectionCatalog::get(opCtx).deregisterCollection(coll->uuid()); opCtx->recoveryUnit()->registerChange( CollectionCatalog::get(opCtx).makeFinishDropCollectionChange(std::move(removedColl), - uuid)); + coll->uuid())); } untimestampedDropWuow.commit(); @@ -697,11 +695,13 @@ SnapshotManager* StorageEngineImpl::getSnapshotManager() const { return _engine->getSnapshotManager(); } -Status StorageEngineImpl::repairRecordStore(OperationContext* opCtx, const NamespaceString& nss) { +Status StorageEngineImpl::repairRecordStore(OperationContext* opCtx, + RecordId catalogId, + const NamespaceString& nss) { auto repairObserver = StorageRepairObserver::get(getGlobalServiceContext()); invariant(repairObserver->isIncomplete()); - Status status = _engine->repairIdent(opCtx, _catalog->getCollectionIdent(nss)); + Status status = _engine->repairIdent(opCtx, _catalog->getEntry(catalogId).ident); bool dataModified = status.code() == ErrorCodes::DataModifiedByRepair; if (!status.isOK() && !dataModified) { return status; @@ -716,7 +716,7 @@ Status StorageEngineImpl::repairRecordStore(OperationContext* opCtx, const Names auto& collectionCatalog = CollectionCatalog::get(getGlobalServiceContext()); auto uuid = collectionCatalog.lookupUUIDByNSS(nss).get(); collectionCatalog.deregisterCollection(uuid); - _initCollection(opCtx, nss, false); + _initCollection(opCtx, catalogId, nss, false); return Status::OK(); } @@ -1012,10 +1012,11 @@ int64_t StorageEngineImpl::sizeOnDiskForDb(OperationContext* opCtx, StringData d size += collection->getRecordStore()->storageSize(opCtx); std::vector<std::string> indexNames; - _catalog->getAllIndexes(opCtx, collection->ns(), &indexNames); + _catalog->getAllIndexes(opCtx, collection->getCatalogId(), &indexNames); for (size_t i = 0; i < indexNames.size(); i++) { - std::string ident = _catalog->getIndexIdent(opCtx, collection->ns(), indexNames[i]); + std::string ident = + _catalog->getIndexIdent(opCtx, collection->getCatalogId(), indexNames[i]); size += _engine->getIdentSize(opCtx, ident); } diff --git a/src/mongo/db/storage/storage_engine_impl.h b/src/mongo/db/storage/storage_engine_impl.h index 461534cc28d..3dda7d220f6 100644 --- a/src/mongo/db/storage/storage_engine_impl.h +++ b/src/mongo/db/storage/storage_engine_impl.h @@ -111,7 +111,9 @@ public: virtual bool isEphemeral() const override; - virtual Status repairRecordStore(OperationContext* opCtx, const NamespaceString& nss) override; + virtual Status repairRecordStore(OperationContext* opCtx, + RecordId catalogId, + const NamespaceString& nss) override; virtual std::unique_ptr<TemporaryRecordStore> makeTemporaryRecordStore( OperationContext* opCtx) override; @@ -343,9 +345,9 @@ public: } /** - * Drop abandoned idents. Returns a parallel list of index name, index spec pairs to rebuild. + * Drop abandoned idents. Returns a list of indexes to rebuild. */ - StatusWith<std::vector<StorageEngine::CollectionIndexNamePair>> reconcileCatalogAndIdents( + StatusWith<std::vector<StorageEngine::IndexIdentifier>> reconcileCatalogAndIdents( OperationContext* opCtx) override; std::string getFilesystemPathForDb(const std::string& dbName) const override; @@ -376,7 +378,10 @@ public: private: using CollIter = std::list<std::string>::iterator; - void _initCollection(OperationContext* opCtx, const NamespaceString& nss, bool forRepair); + void _initCollection(OperationContext* opCtx, + RecordId catalogId, + const NamespaceString& nss, + bool forRepair); Status _dropCollectionsNoTimestamp(OperationContext* opCtx, std::vector<NamespaceString>& toDrop); @@ -392,6 +397,7 @@ private: * collection. */ Status _recoverOrphanedCollection(OperationContext* opCtx, + RecordId catalogId, const NamespaceString& collectionName, StringData collectionIdent); diff --git a/src/mongo/db/storage/storage_engine_test_fixture.h b/src/mongo/db/storage/storage_engine_test_fixture.h index 42afa6a0646..de657637577 100644 --- a/src/mongo/db/storage/storage_engine_test_fixture.h +++ b/src/mongo/db/storage/storage_engine_test_fixture.h @@ -48,19 +48,19 @@ public: StorageEngineTest() : StorageEngineTest(RepairAction::kNoRepair) {} - /** - * Create a collection in the catalog and in the KVEngine. Return the storage engine's `ident`. - */ - StatusWith<std::string> createCollection(OperationContext* opCtx, NamespaceString ns) { + StatusWith<DurableCatalog::Entry> createCollection(OperationContext* opCtx, + NamespaceString ns) { AutoGetDb db(opCtx, ns.db(), LockMode::MODE_X); CollectionOptions options; options.uuid = UUID::gen(); - auto rs = unittest::assertGet( + RecordId catalogId; + std::unique_ptr<RecordStore> rs; + std::tie(catalogId, rs) = unittest::assertGet( _storageEngine->getCatalog()->createCollection(opCtx, ns, options, true)); - CollectionCatalog::get(opCtx).registerCollection(options.uuid.get(), - std::make_unique<CollectionMock>(ns)); + CollectionCatalog::get(opCtx).registerCollection( + options.uuid.get(), std::make_unique<CollectionMock>(ns, catalogId)); - return _storageEngine->getCatalog()->getCollectionIdent(ns); + return {{_storageEngine->getCatalog()->getEntry(catalogId)}}; } std::unique_ptr<TemporaryRecordStore> makeTemporary(OperationContext* opCtx) { @@ -77,7 +77,10 @@ public: } Status dropIndexTable(OperationContext* opCtx, NamespaceString nss, std::string indexName) { - std::string indexIdent = _storageEngine->getCatalog()->getIndexIdent(opCtx, nss, indexName); + RecordId catalogId = + CollectionCatalog::get(opCtx).lookupCollectionByNamespace(nss)->getCatalogId(); + std::string indexIdent = + _storageEngine->getCatalog()->getIndexIdent(opCtx, catalogId, indexName); return dropIdent(opCtx, indexIdent); } @@ -85,8 +88,7 @@ public: return _storageEngine->getEngine()->dropIdent(opCtx, ident); } - StatusWith<std::vector<StorageEngine::CollectionIndexNamePair>> reconcile( - OperationContext* opCtx) { + StatusWith<std::vector<StorageEngine::IndexIdentifier>> reconcile(OperationContext* opCtx) { return _storageEngine->reconcileCatalogAndIdents(opCtx); } @@ -95,9 +97,13 @@ public: } bool collectionExists(OperationContext* opCtx, const NamespaceString& nss) { - auto allCollections = _storageEngine->getCatalog()->getAllCollections(); - return std::count(allCollections.begin(), allCollections.end(), nss); + std::vector<DurableCatalog::Entry> allCollections = + _storageEngine->getCatalog()->getAllCatalogEntries(opCtx); + return std::count_if(allCollections.begin(), allCollections.end(), [&](auto& entry) { + return nss == entry.nss; + }); } + bool identExists(OperationContext* opCtx, const std::string& ident) { auto idents = getAllKVEngineIdents(opCtx); return std::find(idents.begin(), idents.end(), ident) != idents.end(); @@ -130,13 +136,16 @@ public: } BSONObj spec = builder.append("name", key).append("v", 2).done(); - auto collection = std::make_unique<CollectionMock>(collNs); - auto descriptor = std::make_unique<IndexDescriptor>( - collection.get(), IndexNames::findPluginName(spec), spec); + Collection* collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(collNs); + auto descriptor = + std::make_unique<IndexDescriptor>(collection, IndexNames::findPluginName(spec), spec); const auto protocol = IndexBuildProtocol::kTwoPhase; - auto ret = DurableCatalog::get(opCtx)->prepareForIndexBuild( - opCtx, collNs, descriptor.get(), protocol, isBackgroundSecondaryBuild); + auto ret = DurableCatalog::get(opCtx)->prepareForIndexBuild(opCtx, + collection->getCatalogId(), + descriptor.get(), + protocol, + isBackgroundSecondaryBuild); return ret; } @@ -145,20 +154,26 @@ public: std::string key, std::string sideWritesIdent, std::string constraintViolationsIdent) { + Collection* collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(collNs); DurableCatalog::get(opCtx)->setIndexBuildScanning( - opCtx, collNs, key, sideWritesIdent, constraintViolationsIdent); + opCtx, collection->getCatalogId(), key, sideWritesIdent, constraintViolationsIdent); } void indexBuildDrain(OperationContext* opCtx, NamespaceString collNs, std::string key) { - DurableCatalog::get(opCtx)->setIndexBuildDraining(opCtx, collNs, key); + Collection* collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(collNs); + DurableCatalog::get(opCtx)->setIndexBuildDraining(opCtx, collection->getCatalogId(), key); } void indexBuildSuccess(OperationContext* opCtx, NamespaceString collNs, std::string key) { - DurableCatalog::get(opCtx)->indexBuildSuccess(opCtx, collNs, key); + Collection* collection = CollectionCatalog::get(opCtx).lookupCollectionByNamespace(collNs); + DurableCatalog::get(opCtx)->indexBuildSuccess(opCtx, collection->getCatalogId(), key); } - Status removeEntry(OperationContext* opCtx, StringData ns, DurableCatalog* catalog) { - return dynamic_cast<DurableCatalogImpl*>(catalog)->_removeEntry(opCtx, NamespaceString(ns)); + Status removeEntry(OperationContext* opCtx, StringData collNs, DurableCatalog* catalog) { + Collection* collection = + CollectionCatalog::get(opCtx).lookupCollectionByNamespace(NamespaceString(collNs)); + return dynamic_cast<DurableCatalogImpl*>(catalog)->_removeEntry(opCtx, + collection->getCatalogId()); } StorageEngine* _storageEngine; diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index 398ad6b1c8c..0e514afb651 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -157,19 +157,21 @@ private: if (!coll || coll->uuid() != uuid) continue; - if (!DurableCatalog::get(opCtxPtr.get())->isIndexPresent(&opCtx, *nss, indexName)) { + if (!DurableCatalog::get(opCtxPtr.get()) + ->isIndexPresent(&opCtx, coll->getCatalogId(), indexName)) { ttlCollectionCache.deregisterTTLInfo(ttlInfo); continue; } - BSONObj spec = - DurableCatalog::get(opCtxPtr.get())->getIndexSpec(&opCtx, *nss, indexName); + BSONObj spec = DurableCatalog::get(opCtxPtr.get()) + ->getIndexSpec(&opCtx, coll->getCatalogId(), indexName); if (!spec.hasField(secondsExpireField)) { ttlCollectionCache.deregisterTTLInfo(ttlInfo); continue; } - if (!DurableCatalog::get(opCtxPtr.get())->isIndexReady(&opCtx, *nss, indexName)) + if (!DurableCatalog::get(opCtxPtr.get()) + ->isIndexReady(&opCtx, coll->getCatalogId(), indexName)) continue; ttlIndexes.push_back(std::make_pair(*nss, spec.getOwned())); diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index 949b6bdd742..f7427a56063 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -206,7 +206,7 @@ public: { WriteUnitOfWork wuow(&opCtx); opCtx.getServiceContext()->getStorageEngine()->getCatalog()->updateTTLSetting( - &opCtx, _nss, "x_1", 10); + &opCtx, _coll->getCatalogId(), "x_1", 10); wuow.commit(); } diff --git a/src/mongo/dbtests/storage_timestamp_tests.cpp b/src/mongo/dbtests/storage_timestamp_tests.cpp index d89e89123cd..1c35aa31f09 100644 --- a/src/mongo/dbtests/storage_timestamp_tests.cpp +++ b/src/mongo/dbtests/storage_timestamp_tests.cpp @@ -316,10 +316,10 @@ public: } BSONCollectionCatalogEntry::MetaData getMetaDataAtTime(DurableCatalog* durableCatalog, - NamespaceString ns, + RecordId catalogId, const Timestamp& ts) { OneOffRead oor(_opCtx, ts); - return durableCatalog->getMetaData(_opCtx, ns); + return durableCatalog->getMetaData(_opCtx, catalogId); } StatusWith<BSONObj> doAtomicApplyOps(const std::string& dbName, @@ -479,7 +479,8 @@ public: // getAllIdents() actually looks in the RecordStore for a list of all idents, and is thus // versioned by timestamp. We can expect a namespace to have a consistent ident across // timestamps, provided the collection does not get renamed. - auto expectedIdent = durableCatalog->getCollectionIdent(nss); + auto expectedIdent = + durableCatalog->getEntry(autoColl.getCollection()->getCatalogId()).ident; auto idents = durableCatalog->getAllIdents(_opCtx); auto found = std::find(idents.begin(), idents.end(), expectedIdent); @@ -669,11 +670,11 @@ public: MultikeyPaths actualMultikeyPaths; if (!shouldBeMultikey) { ASSERT_FALSE(durableCatalog->isIndexMultikey( - opCtx, collection->ns(), indexName, &actualMultikeyPaths)) + opCtx, collection->getCatalogId(), indexName, &actualMultikeyPaths)) << "index " << indexName << " should not be multikey at timestamp " << ts; } else { ASSERT(durableCatalog->isIndexMultikey( - opCtx, collection->ns(), indexName, &actualMultikeyPaths)) + opCtx, collection->getCatalogId(), indexName, &actualMultikeyPaths)) << "index " << indexName << " should be multikey at timestamp " << ts; } @@ -1848,6 +1849,7 @@ public: reset(nss); AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_X); + RecordId catalogId = autoColl.getCollection()->getCatalogId(); const LogicalTime insertTimestamp = _clock->reserveTicks(1); { @@ -1937,15 +1939,16 @@ public: { ASSERT_FALSE( getIndexMetaData( - getMetaDataAtTime(durableCatalog, nss, afterIndexInit.asTimestamp()), "a_1") + getMetaDataAtTime(durableCatalog, catalogId, afterIndexInit.asTimestamp()), + "a_1") .ready); } // After the build completes, assert that the index is `ready: true` and multikey. assertIdentsExistAtTimestamp(durableCatalog, "", indexIdent, afterIndexBuild); { - auto indexMetaData = - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, afterIndexBuild), "a_1"); + auto indexMetaData = getIndexMetaData( + getMetaDataAtTime(durableCatalog, catalogId, afterIndexBuild), "a_1"); ASSERT(indexMetaData.ready); ASSERT(indexMetaData.multikey); @@ -2180,35 +2183,38 @@ public: const auto indexBComplete = commitIndexBuildTs; AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_S); + RecordId catalogId = autoColl.getCollection()->getCatalogId(); - // The idents are created and persisted with the "ready: false" write. There should be two - // new index idents visible at this time. + // The idents are created and persisted with the "ready: false" write. + // There should be two new index idents visible at this time. const std::vector<std::string> indexes = getNewIndexIdentsAtTime(durableCatalog, origIdents, indexCreateInitTs); ASSERT_EQ(static_cast<std::size_t>(2), indexes.size()) << " Num idents: " << indexes.size(); ASSERT_FALSE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexCreateInitTs), "a_1") + getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, indexCreateInitTs), "a_1") .ready); ASSERT_FALSE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexCreateInitTs), "b_1") + getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, indexCreateInitTs), "b_1") .ready); // Assert the `a_1` index becomes ready at the next oplog entry time. if (!indexAComplete.isNull()) { - ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexAComplete), "a_1") - .ready); - ASSERT_FALSE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexAComplete), "b_1") - .ready); + ASSERT_TRUE(getIndexMetaData( + getMetaDataAtTime(durableCatalog, catalogId, indexAComplete), "a_1") + .ready); + ASSERT_FALSE(getIndexMetaData( + getMetaDataAtTime(durableCatalog, catalogId, indexAComplete), "b_1") + .ready); } // Assert the `b_1` index becomes ready at the last oplog entry time. ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexBComplete), "a_1").ready); + getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, indexBComplete), "a_1") + .ready); ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexBComplete), "b_1").ready); + getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, indexBComplete), "b_1") + .ready); } }; @@ -2300,12 +2306,14 @@ public: durableCatalog, origIdents, /*expectedNewIndexIdents*/ 3, indexCommitTs); // Assert the 'a_1' and `b_1` indexes becomes ready at the last oplog entry time. - ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, renamedNss, indexCommitTs), "a_1") - .ready); - ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, renamedNss, indexCommitTs), "b_1") - .ready); + RecordId renamedCatalogId = + CollectionCatalog::get(_opCtx).lookupCollectionByNamespace(renamedNss)->getCatalogId(); + ASSERT_TRUE(getIndexMetaData( + getMetaDataAtTime(durableCatalog, renamedCatalogId, indexCommitTs), "a_1") + .ready); + ASSERT_TRUE(getIndexMetaData( + getMetaDataAtTime(durableCatalog, renamedCatalogId, indexCommitTs), "b_1") + .ready); } }; @@ -2379,17 +2387,20 @@ public: // Check index state in catalog at oplog entry times for both startIndexBuild and // abortIndexBuild. AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_X); + RecordId catalogId = autoColl.getCollection()->getCatalogId(); // We expect one new one new index ident during this index build. assertRenamedCollectionIdentsAtTimestamp( durableCatalog, origIdents, /*expectedNewIndexIdents*/ 1, indexStartTs); ASSERT_FALSE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexStartTs), "a_1").ready); + getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, indexStartTs), "a_1") + .ready); // We expect all new idents to be removed after the index build has aborted. assertRenamedCollectionIdentsAtTimestamp( durableCatalog, origIdents, /*expectedNewIndexIdents*/ 0, indexAbortTs); - assertIndexMetaDataMissing(getMetaDataAtTime(durableCatalog, nss, indexAbortTs), "a_1"); + assertIndexMetaDataMissing(getMetaDataAtTime(durableCatalog, catalogId, indexAbortTs), + "a_1"); } }; @@ -2684,6 +2695,7 @@ public: ASSERT_OK(doAtomicApplyOps(nss.db().toString(), {createIndexOp})); AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_IS); + RecordId catalogId = autoColl.getCollection()->getCatalogId(); const std::string indexIdent = getNewIndexIdentAtTime(durableCatalog, origIdents, Timestamp::min()); assertIdentsMissingAtTimestamp( @@ -2692,9 +2704,9 @@ public: // On a primary, the index build should start and finish at `startBuildTs` because it is // built in the foreground. - ASSERT_TRUE( - getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, startBuildTs), "field_1") - .ready); + ASSERT_TRUE(getIndexMetaData(getMetaDataAtTime(durableCatalog, catalogId, startBuildTs), + "field_1") + .ready); } } }; @@ -2730,16 +2742,18 @@ public: { Lock::GlobalRead read(_opCtx); + AutoGetCollection autoColl(_opCtx, systemViewsNss, LockMode::MODE_IS); + RecordId catalogId = autoColl.getCollection()->getCatalogId(); + auto systemViewsMd = getMetaDataAtTime( - durableCatalog, systemViewsNss, Timestamp(systemViewsCreateTs.asULL() - 1)); + durableCatalog, catalogId, Timestamp(systemViewsCreateTs.asULL() - 1)); ASSERT_EQ("", systemViewsMd.ns) << systemViewsNss << " incorrectly exists before creation. CreateTs: " << systemViewsCreateTs; - systemViewsMd = getMetaDataAtTime(durableCatalog, systemViewsNss, systemViewsCreateTs); + systemViewsMd = getMetaDataAtTime(durableCatalog, catalogId, systemViewsCreateTs); ASSERT_EQ(systemViewsNss.ns(), systemViewsMd.ns); - AutoGetCollection autoColl(_opCtx, systemViewsNss, LockMode::MODE_IS); assertDocumentAtTimestamp(autoColl.getCollection(), systemViewsCreateTs, BSONObj()); assertDocumentAtTimestamp(autoColl.getCollection(), viewCreateTs, @@ -2765,7 +2779,12 @@ public: ASSERT_OK(createCollection(_opCtx, nss.db().toString(), BSON("create" << nss.coll()))); - { ASSERT(AutoGetCollectionForReadCommand(_opCtx, nss).getCollection()); } + RecordId catalogId; + { + AutoGetCollectionForReadCommand coll(_opCtx, nss); + ASSERT(coll.getCollection()); + catalogId = coll.getCollection()->getCatalogId(); + } BSONObj result = queryOplog(BSON("op" << "c" @@ -2817,7 +2836,7 @@ public: AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_IS); auto storageEngine = _opCtx->getServiceContext()->getStorageEngine(); auto durableCatalog = storageEngine->getCatalog(); - auto indexIdent = durableCatalog->getIndexIdent(_opCtx, nss, "user_1_db_1"); + auto indexIdent = durableCatalog->getIndexIdent(_opCtx, catalogId, "user_1_db_1"); assertIdentsMissingAtTimestamp(durableCatalog, "", indexIdent, pastTs); assertIdentsMissingAtTimestamp(durableCatalog, "", indexIdent, presentTs); assertIdentsMissingAtTimestamp(durableCatalog, "", indexIdent, futureTs); |