summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Milkie <milkie@10gen.com>2019-07-16 10:43:08 -0400
committerEric Milkie <milkie@10gen.com>2019-07-18 13:56:18 -0400
commit15cb55efacbb7be6d3bd65ea265b1c45da5decff (patch)
treeabedbb7bd48d345b310a02785752874de3f1ba5f
parentfbcb2b8123217d8055affc1bffae04c98396387c (diff)
downloadmongo-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.cpp5
-rw-r--r--src/mongo/db/catalog/index_timestamp_helper.h4
-rw-r--r--src/mongo/db/catalog/multi_index_block.cpp40
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;