summaryrefslogtreecommitdiff
path: root/src/mongo/db/index
diff options
context:
space:
mode:
authorSamy Lanka <samy.lanka@mongodb.com>2020-07-31 07:20:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-08-04 08:33:16 +0000
commit2fc36d0b12d1c44893a5f3c1fe0ac8fb0125a071 (patch)
tree735ccccb879cd841d19f953282f1e74a27a21bd1 /src/mongo/db/index
parent4b967fd6c5e679b33922a4d287755ea987dc882c (diff)
downloadmongo-2fc36d0b12d1c44893a5f3c1fe0ac8fb0125a071.tar.gz
SERVER-48417 Reconstruct in-memory state when resuming index build
Diffstat (limited to 'src/mongo/db/index')
-rw-r--r--src/mongo/db/index/duplicate_key_tracker.cpp14
-rw-r--r--src/mongo/db/index/duplicate_key_tracker.h9
-rw-r--r--src/mongo/db/index/index_build_interceptor.cpp55
-rw-r--r--src/mongo/db/index/index_build_interceptor.h16
-rw-r--r--src/mongo/db/index/skipped_record_tracker.cpp19
-rw-r--r--src/mongo/db/index/skipped_record_tracker.h6
6 files changed, 108 insertions, 11 deletions
diff --git a/src/mongo/db/index/duplicate_key_tracker.cpp b/src/mongo/db/index/duplicate_key_tracker.cpp
index 0f997415068..4d3d88bd075 100644
--- a/src/mongo/db/index/duplicate_key_tracker.cpp
+++ b/src/mongo/db/index/duplicate_key_tracker.cpp
@@ -55,6 +55,20 @@ DuplicateKeyTracker::DuplicateKeyTracker(OperationContext* opCtx, const IndexCat
invariant(_indexCatalogEntry->descriptor()->unique());
}
+DuplicateKeyTracker::DuplicateKeyTracker(OperationContext* opCtx,
+ const IndexCatalogEntry* entry,
+ StringData ident)
+ : _indexCatalogEntry(entry) {
+ _keyConstraintsTable =
+ opCtx->getServiceContext()->getStorageEngine()->makeTemporaryRecordStoreFromExistingIdent(
+ opCtx, ident);
+
+ invariant(_indexCatalogEntry->descriptor()->unique(),
+ str::stream() << "Duplicate key tracker table exists on disk with ident: " << ident
+ << " but the index is not unique: "
+ << _indexCatalogEntry->descriptor());
+}
+
void DuplicateKeyTracker::finalizeTemporaryTable(OperationContext* opCtx,
TemporaryRecordStore::FinalizationAction action) {
_keyConstraintsTable->finalizeTemporaryTable(opCtx, action);
diff --git a/src/mongo/db/index/duplicate_key_tracker.h b/src/mongo/db/index/duplicate_key_tracker.h
index a30c5bc2487..1a384cc3d5c 100644
--- a/src/mongo/db/index/duplicate_key_tracker.h
+++ b/src/mongo/db/index/duplicate_key_tracker.h
@@ -58,6 +58,15 @@ public:
DuplicateKeyTracker(OperationContext* opCtx, const IndexCatalogEntry* indexCatalogEntry);
/**
+ * Finds the temporary table associated with storing any duplicate key constraint violations for
+ * this index build. Only used when resuming an index build and the temporary table already
+ * exists on disk. finalizeTemporaryTable() must be called before destruction.
+ */
+ DuplicateKeyTracker(OperationContext* opCtx,
+ const IndexCatalogEntry* indexCatalogEntry,
+ StringData ident);
+
+ /**
* Deletes or keeps the temporary table for the duplicate key constraint violations. Must be
* called before object destruction.
*/
diff --git a/src/mongo/db/index/index_build_interceptor.cpp b/src/mongo/db/index/index_build_interceptor.cpp
index 1ab952d3640..f569fc00e46 100644
--- a/src/mongo/db/index/index_build_interceptor.cpp
+++ b/src/mongo/db/index/index_build_interceptor.cpp
@@ -83,25 +83,62 @@ bool IndexBuildInterceptor::typeCanFastpathMultikeyUpdates(IndexType indexType)
return (indexType == INDEX_BTREE);
}
+void IndexBuildInterceptor::_initializeMultiKeyPaths(IndexCatalogEntry* entry) {
+ // `mergeMultikeyPaths` is sensitive to the two inputs having the same multikey
+ // "shape". Initialize `_multikeyPaths` with the right shape from the IndexCatalogEntry.
+ auto indexType = entry->descriptor()->getIndexType();
+ if (typeCanFastpathMultikeyUpdates(indexType)) {
+ auto numFields = entry->descriptor()->getNumFields();
+ _multikeyPaths = MultikeyPaths{};
+ auto it = _multikeyPaths->begin();
+ _multikeyPaths->insert(it, numFields, {});
+ }
+}
+
IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx, IndexCatalogEntry* entry)
: _indexCatalogEntry(entry),
_sideWritesTable(
opCtx->getServiceContext()->getStorageEngine()->makeTemporaryRecordStore(opCtx)),
- _skippedRecordTracker(entry),
+ _skippedRecordTracker(opCtx, entry, boost::none),
_sideWritesCounter(std::make_shared<AtomicWord<long long>>()) {
if (entry->descriptor()->unique()) {
_duplicateKeyTracker = std::make_unique<DuplicateKeyTracker>(opCtx, entry);
}
- // `mergeMultikeyPaths` is sensitive to the two inputs having the same multikey
- // "shape". Initialize `_multikeyPaths` with the right shape from the IndexCatalogEntry.
- auto indexType = entry->descriptor()->getIndexType();
- if (typeCanFastpathMultikeyUpdates(indexType)) {
- auto numFields = entry->descriptor()->getNumFields();
- _multikeyPaths = MultikeyPaths{};
- auto it = _multikeyPaths->begin();
- _multikeyPaths->insert(it, numFields, {});
+
+ _initializeMultiKeyPaths(entry);
+}
+
+IndexBuildInterceptor::IndexBuildInterceptor(OperationContext* opCtx,
+ IndexCatalogEntry* entry,
+ StringData sideWritesIdent,
+ boost::optional<StringData> duplicateKeyTrackerIdent,
+ boost::optional<StringData> skippedRecordTrackerIdent)
+ : _indexCatalogEntry(entry),
+ _skippedRecordTracker(opCtx, entry, skippedRecordTrackerIdent),
+ _sideWritesCounter(std::make_shared<AtomicWord<long long>>()) {
+
+ _sideWritesTable =
+ opCtx->getServiceContext()->getStorageEngine()->makeTemporaryRecordStoreFromExistingIdent(
+ opCtx, sideWritesIdent);
+ auto finalizeTableOnFailure = makeGuard([&] {
+ _sideWritesTable->finalizeTemporaryTable(opCtx,
+ TemporaryRecordStore::FinalizationAction::kDelete);
+ });
+
+ auto dupKeyTrackerIdentExists = duplicateKeyTrackerIdent ? true : false;
+ uassert(ErrorCodes::BadValue,
+ str::stream() << "Resume info must contain the duplicate key tracker ident ["
+ << duplicateKeyTrackerIdent
+ << "] if and only if the index is unique: " << entry->descriptor(),
+ entry->descriptor()->unique() == dupKeyTrackerIdentExists);
+ if (duplicateKeyTrackerIdent) {
+ _duplicateKeyTracker =
+ std::make_unique<DuplicateKeyTracker>(opCtx, entry, duplicateKeyTrackerIdent.get());
}
+
+ _initializeMultiKeyPaths(entry);
+ finalizeTableOnFailure.dismiss();
}
void IndexBuildInterceptor::finalizeTemporaryTables(
diff --git a/src/mongo/db/index/index_build_interceptor.h b/src/mongo/db/index/index_build_interceptor.h
index f82669c3392..a9215367feb 100644
--- a/src/mongo/db/index/index_build_interceptor.h
+++ b/src/mongo/db/index/index_build_interceptor.h
@@ -74,6 +74,20 @@ public:
IndexBuildInterceptor(OperationContext* opCtx, IndexCatalogEntry* entry);
/**
+ * Finds the temporary table associated with storing writes during this index build. Only used
+ * Only used when resuming an index build and the temporary table already exists on disk.
+ * Additionally will find the tmeporary table associated with storing duplicate key constraint
+ * violations found during the build, if the index being built has uniqueness constraints.
+ *
+ * finalizeTemporaryTable() must be called before destruction.
+ */
+ IndexBuildInterceptor(OperationContext* opCtx,
+ IndexCatalogEntry* entry,
+ StringData sideWritesIdent,
+ boost::optional<StringData> duplicateKeyTrackerIdent,
+ boost::optional<StringData> skippedRecordTrackerIdent);
+
+ /**
* Deletes or keeps the temporary side writes and duplicate key constraint violations tables.
* Must be called before object destruction.
*/
@@ -162,6 +176,8 @@ public:
private:
using SideWriteRecord = std::pair<RecordId, BSONObj>;
+
+ void _initializeMultiKeyPaths(IndexCatalogEntry* entry);
Status _applyWrite(OperationContext* opCtx,
const Collection* coll,
const BSONObj& doc,
diff --git a/src/mongo/db/index/skipped_record_tracker.cpp b/src/mongo/db/index/skipped_record_tracker.cpp
index 9fd39f158aa..0c32261e1d2 100644
--- a/src/mongo/db/index/skipped_record_tracker.cpp
+++ b/src/mongo/db/index/skipped_record_tracker.cpp
@@ -41,6 +41,25 @@ namespace {
static constexpr StringData kRecordIdField = "recordId"_sd;
}
+SkippedRecordTracker::SkippedRecordTracker(IndexCatalogEntry* indexCatalogEntry) {
+ SkippedRecordTracker(nullptr, indexCatalogEntry, boost::none);
+}
+
+SkippedRecordTracker::SkippedRecordTracker(OperationContext* opCtx,
+ IndexCatalogEntry* indexCatalogEntry,
+ boost::optional<StringData> ident)
+ : _indexCatalogEntry(indexCatalogEntry) {
+ if (!ident) {
+ return;
+ }
+
+ // Only initialize the table when resuming an index build if an ident already exists. Otherwise,
+ // lazily initialize table when we record the first document.
+ _skippedRecordsTable =
+ opCtx->getServiceContext()->getStorageEngine()->makeTemporaryRecordStoreFromExistingIdent(
+ opCtx, ident.get());
+}
+
void SkippedRecordTracker::finalizeTemporaryTable(OperationContext* opCtx,
TemporaryRecordStore::FinalizationAction action) {
if (_skippedRecordsTable) {
diff --git a/src/mongo/db/index/skipped_record_tracker.h b/src/mongo/db/index/skipped_record_tracker.h
index 16ea1a6106e..856ebed9197 100644
--- a/src/mongo/db/index/skipped_record_tracker.h
+++ b/src/mongo/db/index/skipped_record_tracker.h
@@ -46,8 +46,10 @@ class SkippedRecordTracker {
SkippedRecordTracker(const SkippedRecordTracker&) = delete;
public:
- SkippedRecordTracker(IndexCatalogEntry* indexCatalogEntry)
- : _indexCatalogEntry(indexCatalogEntry) {}
+ explicit SkippedRecordTracker(IndexCatalogEntry* indexCatalogEntry);
+ SkippedRecordTracker(OperationContext* opCtx,
+ IndexCatalogEntry* indexCatalogEntry,
+ boost::optional<StringData> ident);
/**
* Records a RecordId that was unable to be indexed due to a key generation error. At the