diff options
author | Samy Lanka <samy.lanka@mongodb.com> | 2020-07-31 07:20:47 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-08-04 08:33:16 +0000 |
commit | 2fc36d0b12d1c44893a5f3c1fe0ac8fb0125a071 (patch) | |
tree | 735ccccb879cd841d19f953282f1e74a27a21bd1 /src/mongo/db/index | |
parent | 4b967fd6c5e679b33922a4d287755ea987dc882c (diff) | |
download | mongo-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.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/index/duplicate_key_tracker.h | 9 | ||||
-rw-r--r-- | src/mongo/db/index/index_build_interceptor.cpp | 55 | ||||
-rw-r--r-- | src/mongo/db/index/index_build_interceptor.h | 16 | ||||
-rw-r--r-- | src/mongo/db/index/skipped_record_tracker.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/index/skipped_record_tracker.h | 6 |
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 |