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}});
    }
}
Example #2
0
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}});
    }
}
Example #5
0
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>{}});
}