summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-02-07 12:59:32 -0500
committerGregory Wlodarek <gregory.wlodarek@mongodb.com>2019-02-13 09:13:55 -0500
commit5c0be87432ba798f50cf6f14a65d24b6b3084838 (patch)
tree1473478e640e850a43c092d1327aef61abb0020f /src
parent87194fbe0c24525bc1f2d674012fe6978eca77d2 (diff)
downloadmongo-5c0be87432ba798f50cf6f14a65d24b6b3084838.tar.gz
SERVER-39086 Refactor startup index builds to use the IndexBuildsCoordinator
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/catalog/SConscript1
-rw-r--r--src/mongo/db/catalog/catalog_control.cpp5
-rw-r--r--src/mongo/db/catalog/index_builds_manager.cpp81
-rw-r--r--src/mongo/db/catalog/index_builds_manager.h20
-rw-r--r--src/mongo/db/index_builds_coordinator.cpp167
-rw-r--r--src/mongo/db/index_builds_coordinator.h25
-rw-r--r--src/mongo/db/repair_database.cpp128
-rw-r--r--src/mongo/db/repair_database.h9
-rw-r--r--src/mongo/db/repair_database_and_check_version.cpp5
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));
}
}