diff options
author | Eric Milkie <milkie@10gen.com> | 2019-07-16 10:43:08 -0400 |
---|---|---|
committer | Eric Milkie <milkie@10gen.com> | 2019-07-18 13:56:18 -0400 |
commit | 15cb55efacbb7be6d3bd65ea265b1c45da5decff (patch) | |
tree | abedbb7bd48d345b310a02785752874de3f1ba5f | |
parent | fbcb2b8123217d8055affc1bffae04c98396387c (diff) | |
download | mongo-15cb55efacbb7be6d3bd65ea265b1c45da5decff.tar.gz |
SERVER-42185 timestamp index build cancellation correctly, including at stepdown time
(cherry picked from commit a4f07aed5277cb31d2422b3dc658b5758d1773ed)
-rw-r--r-- | src/mongo/db/catalog/index_timestamp_helper.cpp | 5 | ||||
-rw-r--r-- | src/mongo/db/catalog/index_timestamp_helper.h | 4 | ||||
-rw-r--r-- | src/mongo/db/catalog/multi_index_block.cpp | 40 |
3 files changed, 33 insertions, 16 deletions
diff --git a/src/mongo/db/catalog/index_timestamp_helper.cpp b/src/mongo/db/catalog/index_timestamp_helper.cpp index 524d5bbc121..ceecf0b8380 100644 --- a/src/mongo/db/catalog/index_timestamp_helper.cpp +++ b/src/mongo/db/catalog/index_timestamp_helper.cpp @@ -146,11 +146,11 @@ bool requiresGhostCommitTimestampForCatalogWrite(OperationContext* opCtx, Namesp } } // namespace -void IndexTimestampHelper::setGhostCommitTimestampForCatalogWrite(OperationContext* opCtx, +bool IndexTimestampHelper::setGhostCommitTimestampForCatalogWrite(OperationContext* opCtx, const NamespaceString& nss) { invariant(opCtx->lockState()->inAWriteUnitOfWork()); if (!requiresGhostCommitTimestampForCatalogWrite(opCtx, nss)) { - return; + return false; } auto status = opCtx->recoveryUnit()->setTimestamp( LogicalClock::get(opCtx)->getClusterTime().asTimestamp()); @@ -160,5 +160,6 @@ void IndexTimestampHelper::setGhostCommitTimestampForCatalogWrite(OperationConte throw WriteConflictException(); } fassert(50701, status); + return true; } } // namespace mongo diff --git a/src/mongo/db/catalog/index_timestamp_helper.h b/src/mongo/db/catalog/index_timestamp_helper.h index af4a746a869..581b1bd4740 100644 --- a/src/mongo/db/catalog/index_timestamp_helper.h +++ b/src/mongo/db/catalog/index_timestamp_helper.h @@ -51,8 +51,10 @@ void setGhostCommitTimestampForWrite(OperationContext* opCtx, const NamespaceStr * is when the operation is not committed with an oplog entry, which may be necessary for * certain index catalog operations not associated with a unique optime. This implementation * uses the LogicalClock to timestamp operations. + * Returns true if a ghost timestamp was set, false if no timestamp was required to be set. Can + * also throw WriteConflictException. */ -void setGhostCommitTimestampForCatalogWrite(OperationContext* opCtx, const NamespaceString& nss); +bool setGhostCommitTimestampForCatalogWrite(OperationContext* opCtx, const NamespaceString& nss); }; } // mongo diff --git a/src/mongo/db/catalog/multi_index_block.cpp b/src/mongo/db/catalog/multi_index_block.cpp index 60f7107ddd9..287f34bb57e 100644 --- a/src/mongo/db/catalog/multi_index_block.cpp +++ b/src/mongo/db/catalog/multi_index_block.cpp @@ -38,6 +38,7 @@ #include "mongo/base/error_codes.h" #include "mongo/db/audit.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/catalog/index_timestamp_helper.h" #include "mongo/db/catalog/multi_index_block_gen.h" #include "mongo/db/client.h" #include "mongo/db/concurrency/write_conflict_exception.h" @@ -89,9 +90,12 @@ void MultiIndexBlock::cleanUpAfterBuild(OperationContext* opCtx, Collection* col // Lock the collection if it's not already locked. boost::optional<Lock::DBLock> dbLock; boost::optional<Lock::CollectionLock> collLock; - if (!opCtx->lockState()->isCollectionLockedForMode(collection->ns(), MODE_X)) { - dbLock.emplace(opCtx, collection->ns().db(), MODE_IX); - collLock.emplace(opCtx, collection->ns(), MODE_X); + + auto nss = collection->ns(); + + if (!opCtx->lockState()->isCollectionLockedForMode(nss, MODE_X)) { + dbLock.emplace(opCtx, nss.db(), MODE_IX); + collLock.emplace(opCtx, nss, MODE_X); } if (!_needToCleanup || _indexes.empty()) { @@ -118,18 +122,28 @@ void MultiIndexBlock::cleanUpAfterBuild(OperationContext* opCtx, Collection* col auto replCoord = repl::ReplicationCoordinator::get(opCtx); // Nodes building an index on behalf of a user (e.g: `createIndexes`, `applyOps`) may // fail, removing the existence of the index from the catalog. This update must be - // timestamped. A failure from `createIndexes` should not have a commit timestamp and - // instead write a noop entry. A foreground `applyOps` index build may have a commit - // timestamp already set. - if (opCtx->recoveryUnit()->getCommitTimestamp().isNull() && + // timestamped (unless the build is on an unreplicated collection). A failure from + // `createIndexes` should not have a commit timestamp and instead write a noop entry. A + // foreground `applyOps` index build may have a commit timestamp already set. + if (opCtx->recoveryUnit()->getCommitTimestamp().isNull()) { + // We must choose a timestamp to write with, as we don't have one handy in the + // recovery unit already. + // We need to avoid checking replication state if we do not hold the RSTL. If we do // not hold the RSTL, we must be a build started on a secondary via replication. - opCtx->lockState()->isRSTLLocked() && - replCoord->canAcceptWritesForDatabase(opCtx, "admin")) { - opCtx->getServiceContext()->getOpObserver()->onOpMessage( - opCtx, - BSON("msg" << std::string(str::stream() << "Failing index builds. Coll: " - << collection->ns()))); + if (opCtx->lockState()->isRSTLLocked() && + replCoord->canAcceptWritesForDatabase(opCtx, "admin")) { + opCtx->getServiceContext()->getOpObserver()->onOpMessage( + opCtx, + BSON("msg" << std::string(str::stream() << "Failing index builds. Coll: " + << nss))); + } else { + // Simply get a timestamp to write with here; we can't write to the oplog. + repl::UnreplicatedWritesBlock uwb(opCtx); + if (!IndexTimestampHelper::setGhostCommitTimestampForCatalogWrite(opCtx, nss)) { + log() << "Did not timestamp index abort write."; + } + } } wunit.commit(); _buildIsCleanedUp = true; |