diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/catalog/catalog_control.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_builds_manager.cpp | 81 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_builds_manager.h | 20 | ||||
-rw-r--r-- | src/mongo/db/index_builds_coordinator.cpp | 167 | ||||
-rw-r--r-- | src/mongo/db/index_builds_coordinator.h | 25 | ||||
-rw-r--r-- | src/mongo/db/repair_database.cpp | 128 | ||||
-rw-r--r-- | src/mongo/db/repair_database.h | 9 | ||||
-rw-r--r-- | src/mongo/db/repair_database_and_check_version.cpp | 5 |
10 files changed, 326 insertions, 116 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 0d610ab5aa0..30b28e77459 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1092,6 +1092,7 @@ env.Library( 'logical_clock', ], LIBDEPS_PRIVATE=[ + 'index_builds_coordinator_interface', '$BUILD_DIR/mongo/db/catalog/document_validation', '$BUILD_DIR/mongo/db/catalog/index_key_validate', '$BUILD_DIR/mongo/db/catalog/multi_index_block', diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript index 6b99eceab39..8df3a14f64c 100644 --- a/src/mongo/db/catalog/SConscript +++ b/src/mongo/db/catalog/SConscript @@ -141,6 +141,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/concurrency/write_conflict_exception', + '$BUILD_DIR/mongo/db/query/query_knobs', ] ) diff --git a/src/mongo/db/catalog/catalog_control.cpp b/src/mongo/db/catalog/catalog_control.cpp index 151886c033c..aa306d2a293 100644 --- a/src/mongo/db/catalog/catalog_control.cpp +++ b/src/mongo/db/catalog/catalog_control.cpp @@ -160,9 +160,10 @@ void openCatalog(OperationContext* opCtx, const MinVisibleTimestampMap& minVisib log() << "openCatalog: rebuilding index: collection: " << collNss.toString() << ", index: " << indexName; } + + std::vector<BSONObj> indexSpecs = entry.second.second; fassert(40690, - rebuildIndexesOnCollection( - opCtx, dbCatalogEntry, collCatalogEntry, std::move(entry.second))); + rebuildIndexesOnCollection(opCtx, dbCatalogEntry, collCatalogEntry, indexSpecs)); } // Open all databases and repopulate the UUID catalog. diff --git a/src/mongo/db/catalog/index_builds_manager.cpp b/src/mongo/db/catalog/index_builds_manager.cpp index e14a03577cd..41a90c6ed16 100644 --- a/src/mongo/db/catalog/index_builds_manager.cpp +++ b/src/mongo/db/catalog/index_builds_manager.cpp @@ -34,6 +34,8 @@ #include "mongo/db/catalog/index_builds_manager.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/collection_catalog_entry.h" +#include "mongo/db/catalog/database_catalog_entry.h" #include "mongo/db/catalog/index_catalog.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/operation_context.h" @@ -115,6 +117,73 @@ Status IndexBuildsManager::startBuildingIndex(const UUID& buildUUID) { return builder->insertAllDocumentsInCollection(); } +StatusWith<std::pair<long long, long long>> IndexBuildsManager::startBuildingIndexForRecovery( + OperationContext* opCtx, NamespaceString ns, const UUID& buildUUID) { + auto builder = _getBuilder(buildUUID); + + auto const storageEngine = opCtx->getServiceContext()->getStorageEngine(); + auto dbCatalogEntry = storageEngine->getDatabaseCatalogEntry(opCtx, ns.db()); + auto rs = dbCatalogEntry->getRecordStore(ns.ns()); + + // Iterate all records in the collection. Delete them if they aren't valid BSON. Index them + // if they are. + long long numRecords = 0; + long long dataSize = 0; + + auto cursor = rs->getCursor(opCtx); + auto record = cursor->next(); + while (record) { + opCtx->checkForInterrupt(); + // Cursor is left one past the end of the batch inside writeConflictRetry + auto beginBatchId = record->id; + Status status = writeConflictRetry(opCtx, "repairDatabase", ns.ns(), [&] { + // In the case of WCE in a partial batch, we need to go back to the beginning + if (!record || (beginBatchId != record->id)) { + record = cursor->seekExact(beginBatchId); + } + WriteUnitOfWork wunit(opCtx); + for (int i = 0; record && i < internalInsertMaxBatchSize.load(); i++) { + RecordId id = record->id; + RecordData& data = record->data; + // Use the latest BSON validation version. We retain decimal data when repairing + // database even if decimal is disabled. + auto validStatus = validateBSON(data.data(), data.size(), BSONVersion::kLatest); + if (!validStatus.isOK()) { + warning() << "Invalid BSON detected at " << id << ": " << redact(validStatus) + << ". Deleting."; + rs->deleteRecord(opCtx, id); + } else { + numRecords++; + dataSize += data.size(); + auto insertStatus = builder->insert(data.releaseToBson(), id); + if (!insertStatus.isOK()) { + return insertStatus; + } + } + record = cursor->next(); + } + cursor->save(); // Can't fail per API definition + // When this exits via success or WCE, we need to restore the cursor + ON_BLOCK_EXIT([opCtx, ns, &cursor]() { + // restore CAN throw WCE per API + writeConflictRetry( + opCtx, "retryRestoreCursor", ns.ns(), [&cursor] { cursor->restore(); }); + }); + wunit.commit(); + return Status::OK(); + }); + if (!status.isOK()) { + return status; + } + } + + Status status = builder->dumpInsertsFromBulk(); + if (!status.isOK()) { + return status; + } + return std::make_pair(numRecords, dataSize); +} + Status IndexBuildsManager::drainBackgroundWrites(const UUID& buildUUID) { auto builder = _getBuilder(buildUUID); @@ -191,6 +260,18 @@ bool IndexBuildsManager::isBackgroundBuilding(const UUID& buildUUID) { return builder->isBackgroundBuilding(); } +void IndexBuildsManager::initializeIndexesWithoutCleanupForRecovery( + OperationContext* opCtx, Collection* collection, const std::vector<BSONObj>& indexSpecs) { + // Sanity check to ensure we're in recovery mode. + invariant(opCtx->lockState()->isW()); + invariant(indexSpecs.size() > 0); + + MultiIndexBlock indexer(opCtx, collection); + WriteUnitOfWork wuow(opCtx); + invariant(indexer.init(indexSpecs, MultiIndexBlock::kNoopOnInitFn).isOK()); + wuow.commit(); +} + void IndexBuildsManager::verifyNoIndexBuilds_forTestOnly() { invariant(_builders.empty()); } diff --git a/src/mongo/db/catalog/index_builds_manager.h b/src/mongo/db/catalog/index_builds_manager.h index 1aa735b371c..7ff487ef2d8 100644 --- a/src/mongo/db/catalog/index_builds_manager.h +++ b/src/mongo/db/catalog/index_builds_manager.h @@ -89,6 +89,15 @@ public: Status startBuildingIndex(const UUID& buildUUID); /** + * Iterates through every record in the collection to index it while also removing documents + * that are not valid BSON objects. + * + * Returns the number of records and the size of the data iterated over. + */ + StatusWith<std::pair<long long, long long>> startBuildingIndexForRecovery( + OperationContext* opCtx, NamespaceString ns, const UUID& buildUUID); + + /** * Document inserts observed during the scanning/insertion phase of an index build are not * added but are instead stored in a temporary buffer until this function is invoked. */ @@ -155,6 +164,17 @@ public: bool isBackgroundBuilding(const UUID& buildUUID); /** + * Initializes the 'indexSpecs' with a MultiIndexBlock on 'collection', then aborts them without + * cleaning them up. + * + * This is to be used only during recovery mode when the index build process fails to ensure + * that we don't lose any indexes. + */ + void initializeIndexesWithoutCleanupForRecovery(OperationContext* opCtx, + Collection* collection, + const std::vector<BSONObj>& indexSpecs); + + /** * Checks via invariant that the manager has no index builds presently. */ void verifyNoIndexBuilds_forTestOnly(); diff --git a/src/mongo/db/index_builds_coordinator.cpp b/src/mongo/db/index_builds_coordinator.cpp index 7d23e8122c8..c63cc40ecd8 100644 --- a/src/mongo/db/index_builds_coordinator.cpp +++ b/src/mongo/db/index_builds_coordinator.cpp @@ -156,6 +156,42 @@ IndexBuildsCoordinator::~IndexBuildsCoordinator() { invariant(_collectionIndexBuilds.empty()); } +StatusWith<std::pair<long long, long long>> IndexBuildsCoordinator::startIndexRebuildForRecovery( + OperationContext* opCtx, + std::unique_ptr<Collection> collection, + const std::vector<BSONObj>& specs, + const UUID& buildUUID) { + // Index builds in recovery mode have the global write lock. + invariant(opCtx->lockState()->isW()); + + std::vector<std::string> indexNames; + for (auto& spec : specs) { + std::string name = spec.getStringField(IndexDescriptor::kIndexNameFieldName); + if (name.empty()) { + return Status( + ErrorCodes::CannotCreateIndex, + str::stream() << "Cannot create an index for a spec '" << spec + << "' without a non-empty string value for the 'name' field"); + } + indexNames.push_back(name); + } + + auto collectionUUID = *collection->uuid(); + auto nss = collection->ns(); + auto dbName = nss.db().toString(); + // We run the index build using the single phase protocol as we already hold the global write + // lock. + auto replIndexBuildState = std::make_shared<ReplIndexBuildState>( + buildUUID, collectionUUID, dbName, indexNames, specs, IndexBuildProtocol::kSinglePhase); + + Status status = _registerIndexBuild(opCtx, replIndexBuildState); + if (!status.isOK()) { + return status; + } + + return _runIndexRebuildForRecovery(opCtx, collection.get(), buildUUID); +} + Future<void> IndexBuildsCoordinator::joinIndexBuilds(const NamespaceString& nss, const std::vector<BSONObj>& indexSpecs) { // TODO: implement. This code is just to make it compile. @@ -651,6 +687,137 @@ void IndexBuildsCoordinator::_buildIndex(OperationContext* opCtx, return; } +StatusWith<std::pair<long long, long long>> IndexBuildsCoordinator::_runIndexRebuildForRecovery( + OperationContext* opCtx, Collection* collection, const UUID& buildUUID) noexcept { + // Index builds in recovery mode have the global write lock. + invariant(opCtx->lockState()->isW()); + + auto replState = [&] { + stdx::unique_lock<stdx::mutex> lk(_mutex); + auto it = _allIndexBuilds.find(buildUUID); + invariant(it != _allIndexBuilds.end()); + return it->second; + }(); + + // We rely on 'collection' for any collection information because no databases are open during + // recovery. + auto collectionUUID = *collection->uuid(); + NamespaceString nss = collection->ns(); + invariant(!nss.isEmpty()); + + auto status = Status::OK(); + ReplIndexBuildState::IndexCatalogStats indexCatalogStats; + bool mustTearDown = false; + bool addIndexSpecsToCatalog = false; + + long long numRecords = 0; + long long dataSize = 0; + + try { + log() << "Index builds manager starting: " << buildUUID << ": " << nss << " (" + << collectionUUID << ")"; + + indexCatalogStats.numIndexesBefore = _getNumIndexesTotal(opCtx, collection); + + // First, drop all the indexes that we're going to be building. + { + auto indexCatalog = collection->getIndexCatalog(); + + WriteUnitOfWork wuow(opCtx); + // Clear the index catalog of all unfinished indexes. + std::vector<BSONObj> unfinishedIndexes = + indexCatalog->getAndClearUnfinishedIndexes(opCtx); + + // Drop any ready indexes if they have to be rebuilt. + for (const auto& indexSpec : replState->indexSpecs) { + std::string name = indexSpec.getStringField(IndexDescriptor::kIndexNameFieldName); + const IndexDescriptor* desc = + indexCatalog->findIndexByName(opCtx, name, /*includeUnfinishedIndexes=*/false); + if (!desc) { + continue; + } + + uassertStatusOK(indexCatalog->dropIndex(opCtx, desc)); + } + + wuow.commit(); + addIndexSpecsToCatalog = true; + } + + mustTearDown = true; + + uassertStatusOK(_indexBuildsManager.setUpIndexBuild( + opCtx, collection, replState->indexSpecs, buildUUID, MultiIndexBlock::kNoopOnInitFn)); + + std::tie(numRecords, dataSize) = uassertStatusOK( + _indexBuildsManager.startBuildingIndexForRecovery(opCtx, collection->ns(), buildUUID)); + + // Commit the index build. + uassertStatusOK(_indexBuildsManager.commitIndexBuild(opCtx, + nss, + buildUUID, + MultiIndexBlock::kNoopOnCreateEachFn, + MultiIndexBlock::kNoopOnCommitFn)); + + indexCatalogStats.numIndexesAfter = _getNumIndexesTotal(opCtx, collection); + + log() << "Index builds manager completed successfully: " << buildUUID << ": " << nss + << " ( " << collectionUUID + << " ). Index specs requested: " << replState->indexSpecs.size() + << ". Indexes in catalog before build: " << indexCatalogStats.numIndexesBefore + << ". Indexes in catalog after build: " << indexCatalogStats.numIndexesAfter; + } catch (const DBException& ex) { + status = ex.toStatus(); + invariant(status != ErrorCodes::IndexAlreadyExists); + log() << "Index builds manager failed: " << buildUUID << ": " << nss << " ( " + << collectionUUID << " ): " << status; + } + + // Index build is registered in manager regardless of IndexBuildsManager::setUpIndexBuild() + // result. + if (status.isOK()) { + // A successful index build means that all the requested indexes are now part of the + // catalog. + if (mustTearDown) { + _indexBuildsManager.tearDownIndexBuild(buildUUID); + } + } else if (mustTearDown) { + // In recovery mode, we need to add the indexes back to not lose them. + if (addIndexSpecsToCatalog) { + _indexBuildsManager.initializeIndexesWithoutCleanupForRecovery( + opCtx, collection, replState->indexSpecs); + } + + // If the index build fails, there's cleanup to do. + try { + _indexBuildsManager.tearDownIndexBuild(buildUUID); + } catch (DBException& ex) { + ex.addContext(str::stream() + << "Index builds manager failed to clean up partially built index: " + << buildUUID + << ": " + << nss + << " ( " + << collectionUUID + << " )"); + fassertNoTrace(51076, ex.toStatus()); + } + } + + // 'numIndexesBefore' was before we cleared any unfinished indexes, so it must be the same + // as 'numIndexesAfter', since we're going to be building any unfinished indexes too. + invariant(indexCatalogStats.numIndexesBefore == indexCatalogStats.numIndexesAfter); + + stdx::unique_lock<stdx::mutex> lk(_mutex); + + _unregisterIndexBuild(lk, opCtx, replState); + + if (status.isOK()) { + return std::make_pair(numRecords, dataSize); + } + return status; +} + void IndexBuildsCoordinator::_stopIndexBuildsOnDatabase(StringData dbName) { stdx::unique_lock<stdx::mutex> lk(_mutex); diff --git a/src/mongo/db/index_builds_coordinator.h b/src/mongo/db/index_builds_coordinator.h index 933aabbbfd6..458843b4b60 100644 --- a/src/mongo/db/index_builds_coordinator.h +++ b/src/mongo/db/index_builds_coordinator.h @@ -107,6 +107,21 @@ public: IndexBuildProtocol protocol) = 0; /** + * Sets up the in-memory and persisted state of the index build. + * + * This function should only be called when in recovery mode, because we use the DatabaseHolder + * to create a temporary collection using the collection catalog entry to allow us to rebuild + * the indexes on the collection without initializing it fully. + * + * Returns the number of records and the size of the data iterated over, if successful. + */ + StatusWith<std::pair<long long, long long>> startIndexRebuildForRecovery( + OperationContext* opCtx, + std::unique_ptr<Collection> collection, + const std::vector<BSONObj>& specs, + const UUID& buildUUID); + + /** * TODO: not yet implemented. */ Future<void> joinIndexBuilds(const NamespaceString& nss, @@ -346,6 +361,16 @@ protected: const NamespaceString& nss, const std::vector<BSONObj>& indexSpecs); + /** + * Runs the index build. + * Rebuilding an index in recovery mode verifies each document to ensure that it is a valid + * BSON object. It will remove any documents with invalid BSON. + * + * Returns the number of records and the size of the data iterated over, if successful. + */ + StatusWith<std::pair<long long, long long>> _runIndexRebuildForRecovery( + OperationContext* opCtx, Collection* collection, const UUID& buildUUID) noexcept; + // Protects the below state. mutable stdx::mutex _mutex; diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp index 22215db1fa4..9c7f6df9e65 100644 --- a/src/mongo/db/repair_database.cpp +++ b/src/mongo/db/repair_database.cpp @@ -53,6 +53,7 @@ #include "mongo/db/catalog/uuid_catalog.h" #include "mongo/db/concurrency/write_conflict_exception.h" #include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index_builds_coordinator.h" #include "mongo/db/logical_clock.h" #include "mongo/db/query/query_knobs_gen.h" #include "mongo/db/storage/storage_engine.h" @@ -113,10 +114,7 @@ StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, Status rebuildIndexesOnCollection(OperationContext* opCtx, DatabaseCatalogEntry* dbce, CollectionCatalogEntry* cce, - const IndexNameObjs& indexNameObjs) { - const std::vector<std::string>& indexNames = indexNameObjs.first; - const std::vector<BSONObj>& indexSpecs = indexNameObjs.second; - + const std::vector<BSONObj>& indexSpecs) { // Skip the rest if there are no indexes to rebuild. if (indexSpecs.empty()) return Status::OK(); @@ -124,110 +122,27 @@ Status rebuildIndexesOnCollection(OperationContext* opCtx, const auto& ns = cce->ns().ns(); auto rs = dbce->getRecordStore(ns); - std::unique_ptr<Collection> collection; - std::unique_ptr<MultiIndexBlock> indexer; - { - // These steps are combined into a single WUOW to ensure there are no commits without - // the indexes. - // 1) Drop all indexes. - // 2) Open the Collection - // 3) Start the index build process. - - WriteUnitOfWork wuow(opCtx); - - { // 1 - for (size_t i = 0; i < indexNames.size(); i++) { - Status s = cce->removeIndex(opCtx, indexNames[i]); - if (!s.isOK()) - return s; - } - } - - // Indexes must be dropped before we open the Collection otherwise we could attempt to - // open a bad index and fail. - // TODO see if MultiIndexBlock can be made to work without a Collection. - const auto uuid = cce->getCollectionOptions(opCtx).uuid; - auto databaseHolder = DatabaseHolder::get(opCtx); - collection = databaseHolder->makeCollection(opCtx, ns, uuid, cce, rs, dbce); - - indexer = std::make_unique<MultiIndexBlock>(opCtx, collection.get()); - Status status = indexer->init(indexSpecs, MultiIndexBlock::kNoopOnInitFn).getStatus(); - if (!status.isOK()) { - // The WUOW will handle cleanup, so the indexer shouldn't do its own. - indexer->abortWithoutCleanup(); - return status; - } - - wuow.commit(); - } - - // Iterate all records in the collection. Delete them if they aren't valid BSON. Index them - // if they are. - - long long numRecords = 0; - long long dataSize = 0; - - auto cursor = rs->getCursor(opCtx); - auto record = cursor->next(); - while (record) { - opCtx->checkForInterrupt(); - // Cursor is left one past the end of the batch inside writeConflictRetry - auto beginBatchId = record->id; - Status status = writeConflictRetry(opCtx, "repairDatabase", cce->ns().ns(), [&] { - // In the case of WCE in a partial batch, we need to go back to the beginning - if (!record || (beginBatchId != record->id)) { - record = cursor->seekExact(beginBatchId); - } - WriteUnitOfWork wunit(opCtx); - for (int i = 0; record && i < internalInsertMaxBatchSize.load(); i++) { - RecordId id = record->id; - RecordData& data = record->data; - // Use the latest BSON validation version. We retain decimal data when repairing - // database even if decimal is disabled. - auto validStatus = validateBSON(data.data(), data.size(), BSONVersion::kLatest); - if (!validStatus.isOK()) { - warning() << "Invalid BSON detected at " << id << ": " << redact(validStatus) - << ". Deleting."; - rs->deleteRecord(opCtx, id); - } else { - numRecords++; - dataSize += data.size(); - auto insertStatus = indexer->insert(data.releaseToBson(), id); - if (!insertStatus.isOK()) { - return insertStatus; - } - } - record = cursor->next(); - } - cursor->save(); // Can't fail per API definition - // When this exits via success or WCE, we need to restore the cursor - ON_BLOCK_EXIT([ opCtx, ns = cce->ns().ns(), &cursor ]() { - // restore CAN throw WCE per API - writeConflictRetry( - opCtx, "retryRestoreCursor", ns, [&cursor] { cursor->restore(); }); - }); - wunit.commit(); - return Status::OK(); - }); - if (!status.isOK()) { - return status; - } + // Open the collection. + const auto uuid = cce->getCollectionOptions(opCtx).uuid; + auto databaseHolder = DatabaseHolder::get(opCtx); + std::unique_ptr<Collection> collection = + databaseHolder->makeCollection(opCtx, ns, uuid, cce, rs, dbce); + + // Rebuild the indexes provided by 'indexSpecs'. + IndexBuildsCoordinator* indexBuildsCoord = IndexBuildsCoordinator::get(opCtx); + UUID buildUUID = UUID::gen(); + auto swRebuild = indexBuildsCoord->startIndexRebuildForRecovery( + opCtx, std::move(collection), indexSpecs, buildUUID); + if (!swRebuild.isOK()) { + return swRebuild.getStatus(); } - Status status = indexer->dumpInsertsFromBulk(); - if (!status.isOK()) - return status; + auto[numRecords, dataSize] = swRebuild.getValue(); - { - WriteUnitOfWork wunit(opCtx); - status = - indexer->commit(MultiIndexBlock::kNoopOnCreateEachFn, MultiIndexBlock::kNoopOnCommitFn); - if (!status.isOK()) { - return status; - } - rs->updateStatsAfterRepair(opCtx, numRecords, dataSize); - wunit.commit(); - } + // Update the record store stats after finishing and committing the index builds. + WriteUnitOfWork wuow(opCtx); + rs->updateStatsAfterRepair(opCtx, numRecords, dataSize); + wuow.commit(); return Status::OK(); } @@ -263,7 +178,8 @@ Status repairCollections(OperationContext* opCtx, if (!swIndexNameObjs.isOK()) return swIndexNameObjs.getStatus(); - Status status = rebuildIndexesOnCollection(opCtx, dbce, cce, swIndexNameObjs.getValue()); + std::vector<BSONObj> indexSpecs = swIndexNameObjs.getValue().second; + Status status = rebuildIndexesOnCollection(opCtx, dbce, cce, indexSpecs); if (!status.isOK()) return status; diff --git a/src/mongo/db/repair_database.h b/src/mongo/db/repair_database.h index c3c5d0ef423..84b63393f5d 100644 --- a/src/mongo/db/repair_database.h +++ b/src/mongo/db/repair_database.h @@ -59,16 +59,13 @@ StatusWith<IndexNameObjs> getIndexNameObjs(OperationContext* opCtx, [](const std::string& indexName) { return true; }); /** - * Selectively rebuild some indexes on a collection. Indexes will be built in parallel with a - * `MultiIndexBlock`. One example usage is when a `dropIndex` command is rolled back. The dropped - * index must be remade. - * - * @param indexNameObjs is expected to be the result of a call to `getIndexNameObjs`. + * Rebuilds the indexes provided by the 'indexSpecs' on the given collection. + * One example usage is when a 'dropIndex' command is rolled back. The dropped index must be remade. */ Status rebuildIndexesOnCollection(OperationContext* opCtx, DatabaseCatalogEntry* dbce, CollectionCatalogEntry* cce, - const IndexNameObjs& indexNameObjs); + const std::vector<BSONObj>& indexSpecs); /** * Repairs a database using a storage engine-specific, best-effort process. diff --git a/src/mongo/db/repair_database_and_check_version.cpp b/src/mongo/db/repair_database_and_check_version.cpp index d2a1be11e38..31717c26aaa 100644 --- a/src/mongo/db/repair_database_and_check_version.cpp +++ b/src/mongo/db/repair_database_and_check_version.cpp @@ -230,9 +230,10 @@ void rebuildIndexes(OperationContext* opCtx, StorageEngine* storageEngine) { for (const auto& indexName : entry.second.first) { log() << "Rebuilding index. Collection: " << collNss << " Index: " << indexName; } + + std::vector<BSONObj> indexSpecs = entry.second.second; fassert(40592, - rebuildIndexesOnCollection( - opCtx, dbCatalogEntry, collCatalogEntry, std::move(entry.second))); + rebuildIndexesOnCollection(opCtx, dbCatalogEntry, collCatalogEntry, indexSpecs)); } } |