TEST_F(KVCollectionCatalogEntryTest, CanSetMultipleFieldsAndComponentsAsMultikey) { std::string indexName = createIndex(BSON("a.b.c" << 1 << "a.b.d" << 1)); CollectionCatalogEntry* collEntry = getCollectionCatalogEntry(); auto opCtx = newOperationContext(); ASSERT(collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{0U, 1U}, {0U, 1U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U, 1U}, {0U, 1U}}); } }
void handleSERVER23299ForDb(OperationContext* txn, Database* db) { log() << "Scanning " << db->name() << " db for SERVER-23299 eligibility"; const auto dbEntry = db->getDatabaseCatalogEntry(); list<string> collNames; dbEntry->getCollectionNamespaces(&collNames); for (const auto& collName : collNames) { const auto collEntry = dbEntry->getCollectionCatalogEntry(collName); const auto collOptions = collEntry->getCollectionOptions(txn); if (!collOptions.temp) continue; log() << "Marking collection " << collName << " as permanent per SERVER-23299"; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wuow(txn); collEntry->clearTempFlag(txn); wuow.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "repair SERVER-23299", collEntry->ns().ns()); } log() << "Done scanning " << db->name() << " for SERVER-23299 eligibility"; }
TEST_F(KVCollectionCatalogEntryTest, NoOpWhenSpecifiedPathComponentsAlreadySetAsMultikey) { std::string indexName = createIndex(BSON("a" << 1)); CollectionCatalogEntry* collEntry = getCollectionCatalogEntry(); auto opCtx = newOperationContext(); ASSERT(collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } ASSERT(!collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } }
TEST_F(KVCollectionCatalogEntryTest, MultikeyPathsAccumulateOnDifferentComponentsOfTheSameField) { std::string indexName = createIndex(BSON("a.b" << 1)); CollectionCatalogEntry* collEntry = getCollectionCatalogEntry(); auto opCtx = newOperationContext(); ASSERT(collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{0U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U}}); } ASSERT(collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{1U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U, 1U}}); } }
void openCatalog(OperationContext* opCtx, const MinVisibleTimestampMap& minVisibleTimestampMap) { invariant(opCtx->lockState()->isW()); // Load the catalog in the storage engine. log() << "openCatalog: loading storage engine catalog"; auto storageEngine = opCtx->getServiceContext()->getStorageEngine(); storageEngine->loadCatalog(opCtx); log() << "openCatalog: reconciling catalog and idents"; auto indexesToRebuild = storageEngine->reconcileCatalogAndIdents(opCtx); fassert(40688, indexesToRebuild.getStatus()); // 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 dbCatalogEntry = storageEngine->getDatabaseCatalogEntry(opCtx, collNss.db()); invariant(dbCatalogEntry, str::stream() << "couldn't get database catalog entry for database " << collNss.db()); auto collCatalogEntry = dbCatalogEntry->getCollectionCatalogEntry(collNss.toString()); invariant(collCatalogEntry, str::stream() << "couldn't get collection catalog entry for collection " << collNss.toString()); auto indexSpecs = getIndexNameObjs( opCtx, dbCatalogEntry, collCatalogEntry, [&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()}); } auto indexesToRebuild = indexSpecs.getValue(); invariant( indexesToRebuild.first.size() == 1, str::stream() << "expected to find a list containing exactly 1 index name, but found " << indexesToRebuild.first.size()); invariant( indexesToRebuild.second.size() == 1, str::stream() << "expected to find a list containing exactly 1 index spec, but found " << indexesToRebuild.second.size()); auto& ino = nsToIndexNameObjMap[collNss.ns()]; ino.first.emplace_back(std::move(indexesToRebuild.first.back())); ino.second.emplace_back(std::move(indexesToRebuild.second.back())); } for (const auto& entry : nsToIndexNameObjMap) { NamespaceString collNss(entry.first); auto dbCatalogEntry = storageEngine->getDatabaseCatalogEntry(opCtx, collNss.db()); invariant(dbCatalogEntry, str::stream() << "couldn't get database catalog entry for database " << collNss.db()); auto collCatalogEntry = dbCatalogEntry->getCollectionCatalogEntry(collNss.toString()); invariant(collCatalogEntry, str::stream() << "couldn't get collection catalog entry for collection " << collNss.toString()); for (const auto& indexName : entry.second.first) { log() << "openCatalog: rebuilding index: collection: " << collNss.toString() << ", index: " << indexName; } std::vector<BSONObj> indexSpecs = entry.second.second; fassert(40690, rebuildIndexesOnCollection(opCtx, dbCatalogEntry, collCatalogEntry, indexSpecs)); } // Open all databases and repopulate the UUID catalog. log() << "openCatalog: reopening all databases"; auto databaseHolder = DatabaseHolder::get(opCtx); std::vector<std::string> databasesToOpen; storageEngine->listDatabases(&databasesToOpen); for (auto&& dbName : databasesToOpen) { LOG(1) << "openCatalog: dbholder reopening database " << dbName; auto db = databaseHolder->openDb(opCtx, dbName); invariant(db, str::stream() << "failed to reopen database " << dbName); std::list<std::string> collections; db->getDatabaseCatalogEntry()->getCollectionNamespaces(&collections); for (auto&& collName : collections) { // Note that the collection name already includes the database component. NamespaceString collNss(collName); auto collection = db->getCollection(opCtx, collName); invariant(collection, str::stream() << "failed to get valid collection pointer for namespace " << collName); auto uuid = collection->uuid(); invariant(uuid); if (minVisibleTimestampMap.count(*uuid) > 0) { collection->setMinimumVisibleSnapshot(minVisibleTimestampMap.find(*uuid)->second); } // If this is the oplog collection, re-establish the replication system's cached pointer // to the oplog. if (collNss.isOplog()) { log() << "openCatalog: updating cached oplog pointer"; collection->establishOplogCollectionForLogging(opCtx); } } } // Opening UUID Catalog: The UUID catalog is now in sync with the storage engine catalog. Clear // the pre-closing state. UUIDCatalog::get(opCtx).onOpenCatalog(opCtx); LOG(1) << "openCatalog: finished reloading UUID catalog"; }
auto opCtx = newOperationContext(); ASSERT(collEntry->setIndexIsMultikey(opCtx.get(), indexName, {{0U, 1U}, {0U, 1U}})); { MultikeyPaths multikeyPaths; ASSERT(collEntry->isIndexMultikey(opCtx.get(), indexName, &multikeyPaths)); assertMultikeyPathsAreEqual(multikeyPaths, {{0U, 1U}, {0U, 1U}}); } } DEATH_TEST_F(KVCollectionCatalogEntryTest, CannotOmitPathLevelMultikeyInfoWithBtreeIndex, "Invariant failure !multikeyPaths.empty()") { std::string indexName = createIndex(BSON("a" << 1 << "b" << 1)); CollectionCatalogEntry* collEntry = getCollectionCatalogEntry(); auto opCtx = newOperationContext(); collEntry->setIndexIsMultikey(opCtx.get(), indexName, MultikeyPaths{}); } DEATH_TEST_F(KVCollectionCatalogEntryTest, AtLeastOnePathComponentMustCauseIndexToBeMultikey, "Invariant failure somePathIsMultikey") { std::string indexName = createIndex(BSON("a" << 1 << "b" << 1)); CollectionCatalogEntry* collEntry = getCollectionCatalogEntry(); auto opCtx = newOperationContext(); collEntry->setIndexIsMultikey(opCtx.get(), indexName, {std::set<size_t>{}, std::set<size_t>{}}); }