summaryrefslogtreecommitdiff
path: root/src/mongo/db/catalog
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/catalog')
-rw-r--r--src/mongo/db/catalog/SConscript1
-rw-r--r--src/mongo/db/catalog/collection_compact.cpp1
-rw-r--r--src/mongo/db/catalog/database_test.cpp3
-rw-r--r--src/mongo/db/catalog/index_build_block.cpp17
-rw-r--r--src/mongo/db/catalog/index_catalog.h24
-rw-r--r--src/mongo/db/catalog/index_catalog_entry.h2
-rw-r--r--src/mongo/db/catalog/index_catalog_entry_impl.h2
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.cpp28
-rw-r--r--src/mongo/db/catalog/index_catalog_impl.h6
-rw-r--r--src/mongo/db/catalog/index_catalog_noop.h4
-rw-r--r--src/mongo/db/catalog/multi_index_block.cpp104
-rw-r--r--src/mongo/db/catalog/multi_index_block.h29
-rw-r--r--src/mongo/db/catalog/multi_index_block.idl9
13 files changed, 151 insertions, 79 deletions
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript
index aa207774bc4..1d1a5868aae 100644
--- a/src/mongo/db/catalog/SConscript
+++ b/src/mongo/db/catalog/SConscript
@@ -249,6 +249,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/db/index/index_build_interceptor',
+ '$BUILD_DIR/mongo/db/storage/storage_options',
'$BUILD_DIR/mongo/idl/server_parameter',
]
)
diff --git a/src/mongo/db/catalog/collection_compact.cpp b/src/mongo/db/catalog/collection_compact.cpp
index 6170ac334d1..cb5e854c11a 100644
--- a/src/mongo/db/catalog/collection_compact.cpp
+++ b/src/mongo/db/catalog/collection_compact.cpp
@@ -118,7 +118,6 @@ StatusWith<CompactStats> compactCollection(OperationContext* opCtx,
CompactStats stats;
MultiIndexBlock indexer(opCtx, collection);
- indexer.allowInterruption();
indexer.ignoreUniqueConstraint(); // in compact we should be doing no checking
Status status = indexer.init(indexSpecs).getStatus();
diff --git a/src/mongo/db/catalog/database_test.cpp b/src/mongo/db/catalog/database_test.cpp
index 0e0205a0380..2237571c7e6 100644
--- a/src/mongo/db/catalog/database_test.cpp
+++ b/src/mongo/db/catalog/database_test.cpp
@@ -308,7 +308,8 @@ void _testDropCollectionThrowsExceptionIfThereAreIndexesInProgress(OperationCont
<< "ns"
<< nss.ns());
- auto indexBuildBlock = indexCatalog->createIndexBuildBlock(opCtx, indexInfoObj);
+ auto indexBuildBlock =
+ indexCatalog->createIndexBuildBlock(opCtx, indexInfoObj, IndexBuildMethod::kHybrid);
{
WriteUnitOfWork wuow(opCtx);
ASSERT_OK(indexBuildBlock->init());
diff --git a/src/mongo/db/catalog/index_build_block.cpp b/src/mongo/db/catalog/index_build_block.cpp
index 270b2f2d12b..51294456a36 100644
--- a/src/mongo/db/catalog/index_build_block.cpp
+++ b/src/mongo/db/catalog/index_build_block.cpp
@@ -49,11 +49,13 @@ namespace mongo {
IndexCatalogImpl::IndexBuildBlock::IndexBuildBlock(OperationContext* opCtx,
Collection* collection,
IndexCatalogImpl* catalog,
- const BSONObj& spec)
+ const BSONObj& spec,
+ IndexBuildMethod method)
: _collection(collection),
_catalog(catalog),
_ns(_collection->ns().ns()),
_spec(spec.getOwned()),
+ _method(method),
_entry(nullptr),
_opCtx(opCtx) {
invariant(collection);
@@ -71,7 +73,8 @@ Status IndexCatalogImpl::IndexBuildBlock::init() {
_indexName = descriptor->indexName();
_indexNamespace = descriptor->indexNamespace();
- bool isBackgroundIndex = _spec["background"].trueValue();
+ bool isBackgroundIndex =
+ _method == IndexBuildMethod::kHybrid || _method == IndexBuildMethod::kBackground;
bool isBackgroundSecondaryBuild = false;
if (auto replCoord = repl::ReplicationCoordinator::get(_opCtx)) {
isBackgroundSecondaryBuild =
@@ -91,15 +94,7 @@ Status IndexCatalogImpl::IndexBuildBlock::init() {
_entry = _catalog->_setupInMemoryStructures(
_opCtx, std::move(descriptor), initFromDisk, isReadyIndex);
- // Hybrid indexes are only enabled for background indexes.
- bool useHybrid = true;
- // TODO: Remove when SERVER-37270 is complete.
- useHybrid = useHybrid && isBackgroundIndex;
- // TODO: Remove when SERVER-38550 is complete. The mobile storage engine does not suport
- // dupsAllowed mode on bulk builders.
- useHybrid = useHybrid && storageGlobalParams.engine != "mobile";
-
- if (useHybrid) {
+ if (_method == IndexBuildMethod::kHybrid) {
_indexBuildInterceptor = stdx::make_unique<IndexBuildInterceptor>(_opCtx, _entry);
_entry->setIndexBuildInterceptor(_indexBuildInterceptor.get());
diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h
index e759efef753..55d5c79446a 100644
--- a/src/mongo/db/catalog/index_catalog.h
+++ b/src/mongo/db/catalog/index_catalog.h
@@ -54,6 +54,28 @@ struct BsonRecord {
const BSONObj* docPtr;
};
+enum class IndexBuildMethod {
+ /**
+ * Use a collection scan to dump all keys into an external sorter. During this process,
+ * concurrent client writes are accepted, and their generated keys are written into an
+ * interceptor. On completion, this interceptor is drained and used to verify uniqueness
+ * constraints on the index.
+ *
+ * This is the default for all index builds.
+ */
+ kHybrid,
+ /**
+ * Perform a collection scan by writing each document's generated key directly into the index.
+ * Accept writes in the background into the index as well.
+ */
+ kBackground,
+ /**
+ * Perform a collection scan to dump all keys into the exteral sorter, then into the index.
+ * During this process, callers guarantee that no writes will be accepted on this collection.
+ */
+ kForeground,
+};
+
/**
* The IndexCatalog is owned by the Collection and is responsible for the lookup and lifetimes of
* the indexes in a collection. Every collection has exactly one instance of this class.
@@ -429,7 +451,7 @@ public:
* spex and OperationContext.
*/
virtual std::unique_ptr<IndexBuildBlockInterface> createIndexBuildBlock(
- OperationContext* opCtx, const BSONObj& spec) = 0;
+ OperationContext* opCtx, const BSONObj& spec, IndexBuildMethod method) = 0;
// public helpers
diff --git a/src/mongo/db/catalog/index_catalog_entry.h b/src/mongo/db/catalog/index_catalog_entry.h
index 1e52a6ac447..ef6628cfffc 100644
--- a/src/mongo/db/catalog/index_catalog_entry.h
+++ b/src/mongo/db/catalog/index_catalog_entry.h
@@ -75,7 +75,7 @@ public:
virtual const IndexAccessMethod* accessMethod() const = 0;
- virtual bool isBuilding() const = 0;
+ virtual bool isHybridBuilding() const = 0;
virtual IndexBuildInterceptor* indexBuildInterceptor() = 0;
diff --git a/src/mongo/db/catalog/index_catalog_entry_impl.h b/src/mongo/db/catalog/index_catalog_entry_impl.h
index a5a53f2dff2..7460b765b34 100644
--- a/src/mongo/db/catalog/index_catalog_entry_impl.h
+++ b/src/mongo/db/catalog/index_catalog_entry_impl.h
@@ -90,7 +90,7 @@ public:
return _accessMethod.get();
}
- bool isBuilding() const final {
+ bool isHybridBuilding() const final {
return _indexBuildInterceptor != nullptr;
}
diff --git a/src/mongo/db/catalog/index_catalog_impl.cpp b/src/mongo/db/catalog/index_catalog_impl.cpp
index 02def7005d9..08498dd3d8b 100644
--- a/src/mongo/db/catalog/index_catalog_impl.cpp
+++ b/src/mongo/db/catalog/index_catalog_impl.cpp
@@ -310,7 +310,7 @@ StatusWith<BSONObj> IndexCatalogImpl::createIndexOnEmptyCollection(OperationCont
spec = statusWithSpec.getValue();
// now going to touch disk
- IndexBuildBlock indexBuildBlock(opCtx, _collection, this, spec);
+ IndexBuildBlock indexBuildBlock(opCtx, _collection, this, spec, IndexBuildMethod::kForeground);
status = indexBuildBlock.init();
if (!status.isOK())
return status;
@@ -1187,11 +1187,12 @@ Status IndexCatalogImpl::_indexFilteredRecords(OperationContext* opCtx,
}
Status status = Status::OK();
- if (index->isBuilding()) {
+ if (index->isHybridBuilding()) {
int64_t inserted;
status = index->indexBuildInterceptor()->sideWrite(opCtx,
index->accessMethod(),
bsonRecord.docPtr,
+ options,
bsonRecord.id,
IndexBuildInterceptor::Op::kInsert,
&inserted);
@@ -1237,10 +1238,19 @@ Status IndexCatalogImpl::_unindexRecord(OperationContext* opCtx,
const RecordId& loc,
bool logIfError,
int64_t* keysDeletedOut) {
- if (index->isBuilding()) {
+ InsertDeleteOptions options;
+ prepareInsertDeleteOptions(opCtx, index->descriptor(), &options);
+ options.logIfError = logIfError;
+
+ if (index->isHybridBuilding()) {
int64_t removed;
- auto status = index->indexBuildInterceptor()->sideWrite(
- opCtx, index->accessMethod(), &obj, loc, IndexBuildInterceptor::Op::kDelete, &removed);
+ auto status = index->indexBuildInterceptor()->sideWrite(opCtx,
+ index->accessMethod(),
+ &obj,
+ options,
+ loc,
+ IndexBuildInterceptor::Op::kDelete,
+ &removed);
if (status.isOK() && keysDeletedOut) {
*keysDeletedOut += removed;
}
@@ -1248,10 +1258,6 @@ Status IndexCatalogImpl::_unindexRecord(OperationContext* opCtx,
return status;
}
- InsertDeleteOptions options;
- prepareInsertDeleteOptions(opCtx, index->descriptor(), &options);
- options.logIfError = logIfError;
-
// On WiredTiger, we do blind unindexing of records for efficiency. However, when duplicates
// are allowed in unique indexes, WiredTiger does not do blind unindexing, and instead confirms
// that the recordid matches the element we are removing.
@@ -1399,8 +1405,8 @@ Status IndexCatalogImpl::compactIndexes(OperationContext* opCtx) {
}
std::unique_ptr<IndexCatalog::IndexBuildBlockInterface> IndexCatalogImpl::createIndexBuildBlock(
- OperationContext* opCtx, const BSONObj& spec) {
- return std::make_unique<IndexBuildBlock>(opCtx, _collection, this, spec);
+ OperationContext* opCtx, const BSONObj& spec, IndexBuildMethod method) {
+ return std::make_unique<IndexBuildBlock>(opCtx, _collection, this, spec, method);
}
std::string::size_type IndexCatalogImpl::getLongestIndexNameLength(OperationContext* opCtx) const {
diff --git a/src/mongo/db/catalog/index_catalog_impl.h b/src/mongo/db/catalog/index_catalog_impl.h
index da755206ba8..36d9e8c41e4 100644
--- a/src/mongo/db/catalog/index_catalog_impl.h
+++ b/src/mongo/db/catalog/index_catalog_impl.h
@@ -249,7 +249,8 @@ public:
IndexBuildBlock(OperationContext* opCtx,
Collection* collection,
IndexCatalogImpl* catalog,
- const BSONObj& spec);
+ const BSONObj& spec,
+ IndexBuildMethod method);
~IndexBuildBlock();
@@ -288,6 +289,7 @@ public:
const std::string _ns;
BSONObj _spec;
+ IndexBuildMethod _method;
std::string _indexName;
std::string _indexNamespace;
@@ -336,7 +338,7 @@ public:
}
std::unique_ptr<IndexCatalog::IndexBuildBlockInterface> createIndexBuildBlock(
- OperationContext* opCtx, const BSONObj& spec) override;
+ OperationContext* opCtx, const BSONObj& spec, IndexBuildMethod method) override;
std::string::size_type getLongestIndexNameLength(OperationContext* opCtx) const override;
diff --git a/src/mongo/db/catalog/index_catalog_noop.h b/src/mongo/db/catalog/index_catalog_noop.h
index 4331d8f4afc..0806f98773e 100644
--- a/src/mongo/db/catalog/index_catalog_noop.h
+++ b/src/mongo/db/catalog/index_catalog_noop.h
@@ -206,8 +206,8 @@ public:
return "";
}
- std::unique_ptr<IndexBuildBlockInterface> createIndexBuildBlock(OperationContext* opCtx,
- const BSONObj& spec) override {
+ std::unique_ptr<IndexBuildBlockInterface> createIndexBuildBlock(
+ OperationContext* opCtx, const BSONObj& spec, IndexBuildMethod method) override {
return {};
}
diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp
index b4fb4a481be..2dcfe29b4e3 100644
--- a/src/mongo/db/catalog/multi_index_block.cpp
+++ b/src/mongo/db/catalog/multi_index_block.cpp
@@ -51,6 +51,7 @@
#include "mongo/db/repl/repl_set_config.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/server_parameters.h"
+#include "mongo/db/storage/storage_options.h"
#include "mongo/db/storage/write_unit_of_work.h"
#include "mongo/logger/redaction.h"
#include "mongo/util/assert_util.h"
@@ -132,12 +133,16 @@ MultiIndexBlock::~MultiIndexBlock() {
}
}
-void MultiIndexBlock::allowBackgroundBuilding() {
- _buildInBackground = true;
-}
+bool MultiIndexBlock::areHybridIndexBuildsEnabled() {
+ // The mobile storage engine does not suport dupsAllowed mode on bulk builders, which means that
+ // it does not support hybrid builds. See SERVER-38550
+ if (storageGlobalParams.engine == "mobile") {
+ return false;
+ }
-void MultiIndexBlock::allowInterruption() {
- _allowInterruption = true;
+ // TODO: SERVER-37272 Disable hybrid if in FCV 4.0.
+
+ return enableHybridIndexBuilds.load();
}
void MultiIndexBlock::ignoreUniqueConstraint() {
@@ -183,11 +188,25 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj
if (!status.isOK())
return status;
+ const bool enableHybrid = areHybridIndexBuildsEnabled();
+
+ // Parse the specs if this builder is not building hybrid indexes, otherwise log a message.
for (size_t i = 0; i < indexSpecs.size(); i++) {
BSONObj info = indexSpecs[i];
+ if (enableHybrid) {
+ if (info["background"].isBoolean() && !info["background"].Bool()) {
+ log() << "ignoring obselete { background: false } index build option because all "
+ "indexes are built in the background with the hybrid method";
+ }
+ continue;
+ }
- // Any foreground indexes make all indexes be built in the foreground.
- _buildInBackground = (_buildInBackground && info["background"].trueValue());
+ // A single foreground build makes the entire builder foreground.
+ if (info["background"].trueValue() && _method != IndexBuildMethod::kForeground) {
+ _method = IndexBuildMethod::kBackground;
+ } else {
+ _method = IndexBuildMethod::kForeground;
+ }
}
std::vector<BSONObj> indexInfoObjs;
@@ -210,7 +229,7 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj
indexInfoObjs.push_back(info);
IndexToBuild index;
- index.block = _collection->getIndexCatalog()->createIndexBuildBlock(_opCtx, info);
+ index.block = _collection->getIndexCatalog()->createIndexBuildBlock(_opCtx, info, _method);
status = index.block->init();
if (!status.isOK())
return status;
@@ -220,9 +239,9 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj
if (!status.isOK())
return status;
- // Foreground builds and background builds using an interceptor can use the bulk builder.
+ // Hybrid builds and non-hybrid foreground builds use the bulk builder.
const bool useBulk =
- !_buildInBackground || index.block->getEntry()->indexBuildInterceptor();
+ _method == IndexBuildMethod::kHybrid || _method == IndexBuildMethod::kForeground;
if (useBulk) {
// Bulk build process requires foreground building as it assumes nothing is changing
// under it.
@@ -233,16 +252,18 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj
_collection->getIndexCatalog()->prepareInsertDeleteOptions(
_opCtx, descriptor, &index.options);
- // Allow duplicates when explicitly allowed or an interceptor is installed, which will
- // perform duplicate checking itself.
+
+ // Allow duplicates when explicitly allowed or when using hybrid builds, which will perform
+ // duplicate checking itself.
index.options.dupsAllowed = index.options.dupsAllowed || _ignoreUnique ||
- index.block->getEntry()->indexBuildInterceptor();
+ index.block->getEntry()->isHybridBuilding();
if (_ignoreUnique) {
index.options.getKeysMode = IndexAccessMethod::GetKeysMode::kRelaxConstraints;
}
index.options.fromIndexBuilder = true;
- log() << "index build: starting on " << ns << " properties: " << descriptor->toString();
+ log() << "index build: starting on " << ns << " properties: " << descriptor->toString()
+ << " using method: " << _method;
if (index.bulk)
log() << "build may temporarily use up to "
<< eachIndexBuildMaxMemoryUsageBytes / 1024 / 1024 << " megabytes of RAM";
@@ -255,7 +276,7 @@ StatusWith<std::vector<BSONObj>> MultiIndexBlock::init(const std::vector<BSONObj
_indexes.push_back(std::move(index));
}
- if (_buildInBackground)
+ if (isBackgroundBuilding())
_backgroundOperation.reset(new BackgroundOperation(ns));
auto replCoord = repl::ReplicationCoordinator::get(_opCtx);
@@ -321,8 +342,7 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
unsigned long long n = 0;
PlanExecutor::YieldPolicy yieldPolicy;
- if (_buildInBackground) {
- invariant(_allowInterruption);
+ if (isBackgroundBuilding()) {
yieldPolicy = PlanExecutor::YIELD_AUTO;
} else {
yieldPolicy = PlanExecutor::WRITE_CONFLICT_RETRY_ONLY;
@@ -335,8 +355,9 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
// with every insert into the index, which resets the collection scan cursor between every call
// to getNextSnapshotted(). With read-once cursors enabled, this can evict data we may need to
// read again, incurring a significant performance penalty.
- // TODO: Enable this for all index builds when SERVER-37268 is complete.
- bool readOnce = !_buildInBackground && useReadOnceCursorsForIndexBuilds.load();
+ // Note: This does not apply to hybrid builds because they write keys to the external sorter.
+ bool readOnce =
+ _method != IndexBuildMethod::kBackground && useReadOnceCursorsForIndexBuilds.load();
_opCtx->recoveryUnit()->setReadOnce(readOnce);
Snapshotted<BSONObj> objToIndex;
@@ -347,7 +368,8 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
(PlanExecutor::ADVANCED == (state = exec->getNextSnapshotted(&objToIndex, &loc))) ||
MONGO_FAIL_POINT(hangAfterStartingIndexBuild)) {
try {
- if (_allowInterruption && !_opCtx->checkForInterruptNoAssert().isOK())
+ auto interruptStatus = _opCtx->checkForInterruptNoAssert();
+ if (!interruptStatus.isOK())
return _opCtx->checkForInterruptNoAssert();
if (!retries && PlanExecutor::ADVANCED != state) {
@@ -369,14 +391,14 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
WriteUnitOfWork wunit(_opCtx);
Status ret = insert(objToIndex.value(), loc);
- if (_buildInBackground)
+ if (_method == IndexBuildMethod::kBackground)
exec->saveState();
if (!ret.isOK()) {
// Fail the index build hard.
return ret;
}
wunit.commit();
- if (_buildInBackground) {
+ if (_method == IndexBuildMethod::kBackground) {
try {
exec->restoreState(); // Handles any WCEs internally.
} catch (...) {
@@ -391,6 +413,10 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
n++;
retries = 0;
} catch (const WriteConflictException&) {
+ // Only background builds write inside transactions, and therefore should only ever
+ // generate WCEs.
+ invariant(_method == IndexBuildMethod::kBackground);
+
CurOp::get(_opCtx)->debug().additiveMetrics.incrementWriteConflicts(1);
retries++; // logAndBackoff expects this to be 1 on first call.
WriteConflictException::logAndBackoff(
@@ -421,7 +447,7 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
"'hangAfterStartingIndexBuildUnlocked' failpoint";
MONGO_FAIL_POINT_PAUSE_WHILE_SET(hangAfterStartingIndexBuildUnlocked);
- if (_buildInBackground) {
+ if (isBackgroundBuilding()) {
_opCtx->lockState()->restoreLockState(_opCtx, lockInfo);
_opCtx->recoveryUnit()->abandonSnapshot();
return Status(ErrorCodes::OperationFailed,
@@ -435,7 +461,7 @@ Status MultiIndexBlock::insertAllDocumentsInCollection() {
progress->finished();
log() << "index build: collection scan done. scanned " << n << " total records in "
- << t.seconds() << " secs";
+ << t.seconds() << " seconds";
Status ret = dumpInsertsFromBulk();
if (!ret.isOK())
@@ -500,13 +526,17 @@ Status MultiIndexBlock::dumpInsertsFromBulk(std::set<RecordId>* dupRecords) {
// when 'dupRecords' is not used because these two vectors are mutually incompatible.
std::vector<BSONObj> dupKeysInserted;
+ // When dupRecords is passed, 'dupsAllowed' should be passed to reflect whether or not the
+ // index is unique.
+ bool dupsAllowed = (dupRecords) ? !_indexes[i].block->getEntry()->descriptor()->unique()
+ : _indexes[i].options.dupsAllowed;
+
IndexCatalogEntry* entry = _indexes[i].block->getEntry();
LOG(1) << "index build: inserting from external sorter into index: "
<< entry->descriptor()->indexName();
Status status = _indexes[i].real->commitBulk(_opCtx,
_indexes[i].bulk.get(),
- _allowInterruption,
- _indexes[i].options.dupsAllowed,
+ dupsAllowed,
dupRecords,
(dupRecords) ? nullptr : &dupKeysInserted);
if (!status.isOK()) {
@@ -532,7 +562,7 @@ Status MultiIndexBlock::dumpInsertsFromBulk(std::set<RecordId>* dupRecords) {
return Status::OK();
}
-Status MultiIndexBlock::drainBackgroundWritesIfNeeded() {
+Status MultiIndexBlock::drainBackgroundWrites() {
if (State::kAborted == _getState()) {
return {ErrorCodes::IndexBuildAborted,
str::stream() << "Index build aborted: " << _abortReason
@@ -678,8 +708,8 @@ void MultiIndexBlock::abort(StringData reason) {
}
-bool MultiIndexBlock::getBuildInBackground() const {
- return _buildInBackground;
+bool MultiIndexBlock::isBackgroundBuilding() const {
+ return _method == IndexBuildMethod::kBackground || _method == IndexBuildMethod::kHybrid;
}
MultiIndexBlock::State MultiIndexBlock::getState_forTest() const {
@@ -755,4 +785,20 @@ std::ostream& operator<<(std::ostream& os, const MultiIndexBlock::State& state)
MONGO_UNREACHABLE;
}
+logger::LogstreamBuilder& operator<<(logger::LogstreamBuilder& out,
+ const IndexBuildMethod& method) {
+ switch (method) {
+ case IndexBuildMethod::kHybrid:
+ out.stream() << "Hybrid";
+ break;
+ case IndexBuildMethod::kBackground:
+ out.stream() << "Background";
+ break;
+ case IndexBuildMethod::kForeground:
+ out.stream() << "Foreground";
+ break;
+ }
+ return out;
+}
+
} // namespace mongo
diff --git a/src/mongo/db/catalog/multi_index_block.h b/src/mongo/db/catalog/multi_index_block.h
index 7b5b818ee06..525a193bfd5 100644
--- a/src/mongo/db/catalog/multi_index_block.h
+++ b/src/mongo/db/catalog/multi_index_block.h
@@ -71,21 +71,7 @@ public:
MultiIndexBlock(OperationContext* opCtx, Collection* collection);
~MultiIndexBlock();
- /**
- * By default we ignore the 'background' flag in specs when building an index. If this is
- * called before init(), we will build the indexes in the background as long as *all* specs
- * call for background indexing. If any spec calls for foreground indexing all indexes will
- * be built in the foreground, as there is no concurrency benefit to building a subset of
- * indexes in the background, but there is a performance benefit to building all in the
- * foreground.
- */
- void allowBackgroundBuilding();
-
- /**
- * Call this before init() to allow the index build to be interrupted.
- * This only affects builds using the insertAllDocumentsInCollection helper.
- */
- void allowInterruption();
+ static bool areHybridIndexBuildsEnabled();
/**
* By default we enforce the 'unique' flag in specs when building an index by failing.
@@ -157,7 +143,7 @@ public:
*
* Must not be in a WriteUnitOfWork.
*/
- Status drainBackgroundWritesIfNeeded();
+ Status drainBackgroundWrites();
/**
* Check any constraits that may have been temporarily violated during the index build for
@@ -225,7 +211,11 @@ public:
*/
void abortWithoutCleanup();
- bool getBuildInBackground() const;
+ /**
+ * Returns true if this build block supports background writes while building an index. This is
+ * true for the kHybrid and kBackground methods.
+ */
+ bool isBackgroundBuilding() const;
/**
* State transitions:
@@ -289,8 +279,8 @@ private:
Collection* _collection;
OperationContext* _opCtx;
- bool _buildInBackground = false;
- bool _allowInterruption = false;
+ IndexBuildMethod _method = IndexBuildMethod::kHybrid;
+
bool _ignoreUnique = false;
bool _needToCleanup = true;
@@ -306,4 +296,5 @@ private:
// The ASSERT_*() macros use this function to print the value of 'state' when the predicate fails.
std::ostream& operator<<(std::ostream& os, const MultiIndexBlock::State& state);
+logger::LogstreamBuilder& operator<<(logger::LogstreamBuilder& out, const IndexBuildMethod& method);
} // namespace mongo
diff --git a/src/mongo/db/catalog/multi_index_block.idl b/src/mongo/db/catalog/multi_index_block.idl
index 3d1d4a145d7..08b183e3560 100644
--- a/src/mongo/db/catalog/multi_index_block.idl
+++ b/src/mongo/db/catalog/multi_index_block.idl
@@ -42,6 +42,15 @@ server_parameters:
cpp_vartype: AtomicWord<bool>
default: true
+ enableHybridIndexBuilds:
+ description: "Build all indexes by performing external sorting while accepting concurrent client writes"
+ set_at:
+ - runtime
+ - startup
+ cpp_varname: enableHybridIndexBuilds
+ cpp_vartype: AtomicWord<bool>
+ default: true
+
maxIndexBuildMemoryUsageMegabytes:
description: "Limits the amount of memory that simultaneous foreground index builds on one collection may consume for the duration of the builds"
set_at: