Skip to content

Commit 9471cc8

Browse files
benetyevergreen
authored andcommitted
SERVER-39002 write abortIndexBuild oplog entry in same WUOW as index build cleanup
1 parent 342d72a commit 9471cc8

File tree

2 files changed

+109
-19
lines changed

2 files changed

+109
-19
lines changed

src/mongo/db/index_builds_coordinator.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -933,12 +933,30 @@ void IndexBuildsCoordinator::_runIndexBuildInner(OperationContext* opCtx,
933933

934934
Lock::DBLock dbLock(opCtx, nss.db(), MODE_IX);
935935

936-
unlockRSTLForIndexCleanup(opCtx);
937-
938-
Lock::CollectionLock collLock(opCtx, nss, MODE_X);
939-
940-
_indexBuildsManager.tearDownIndexBuild(
941-
opCtx, collection, replState->buildUUID, MultiIndexBlock::kNoopOnCleanUpFn);
936+
if (!replSetAndNotPrimary) {
937+
auto replCoord = repl::ReplicationCoordinator::get(opCtx);
938+
if (replCoord->getSettings().usingReplSets() &&
939+
replCoord->canAcceptWritesFor(opCtx, nss)) {
940+
// We are currently a primary node. Notify downstream nodes to abort their index
941+
// builds with the same build UUID.
942+
Lock::CollectionLock collLock(opCtx, nss, MODE_X);
943+
auto onCleanUpFn = [&] { onAbortIndexBuild(opCtx, nss, *replState, status); };
944+
_indexBuildsManager.tearDownIndexBuild(
945+
opCtx, collection, replState->buildUUID, onCleanUpFn);
946+
} else {
947+
// This index build was aborted because we are stepping down from primary.
948+
unlockRSTLForIndexCleanup(opCtx);
949+
Lock::CollectionLock collLock(opCtx, nss, MODE_X);
950+
_indexBuildsManager.tearDownIndexBuild(
951+
opCtx, collection, replState->buildUUID, MultiIndexBlock::kNoopOnCleanUpFn);
952+
}
953+
} else {
954+
// We started this index build during oplog application as a secondary node.
955+
unlockRSTLForIndexCleanup(opCtx);
956+
Lock::CollectionLock collLock(opCtx, nss, MODE_X);
957+
_indexBuildsManager.tearDownIndexBuild(
958+
opCtx, collection, replState->buildUUID, MultiIndexBlock::kNoopOnCleanUpFn);
959+
}
942960
} else {
943961
_indexBuildsManager.tearDownIndexBuild(
944962
opCtx, collection, replState->buildUUID, MultiIndexBlock::kNoopOnCleanUpFn);
@@ -959,19 +977,6 @@ void IndexBuildsCoordinator::_runIndexBuildInner(OperationContext* opCtx,
959977
<< "; Database: " << replState->dbName));
960978
}
961979

962-
UninterruptibleLockGuard noInterrupt(opCtx->lockState());
963-
Lock::GlobalLock lock(opCtx, MODE_IX);
964-
965-
auto replCoord = repl::ReplicationCoordinator::get(opCtx);
966-
if (replCoord->getSettings().usingReplSets() && replCoord->canAcceptWritesFor(opCtx, nss)) {
967-
writeConflictRetry(
968-
opCtx, "onAbortIndexBuild", NamespaceString::kRsOplogNamespace.ns(), [&] {
969-
WriteUnitOfWork wuow(opCtx);
970-
onAbortIndexBuild(opCtx, nss, *replState, status);
971-
wuow.commit();
972-
});
973-
}
974-
975980
uassertStatusOK(status);
976981
MONGO_UNREACHABLE;
977982
}

src/mongo/dbtests/storage_timestamp_tests.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2298,6 +2298,90 @@ class TimestampMultiIndexBuildsDuringRename : public StorageTimestampTest {
22982298
}
22992299
};
23002300

2301+
/**
2302+
* This test asserts that the catalog updates that represent the beginning and end of an aborted
2303+
* index build are timestamped. The oplog should contain two entries startIndexBuild and
2304+
* abortIndexBuild. We will inspect the catalog at the timestamp corresponding to each of these
2305+
* oplog entries.
2306+
*/
2307+
class TimestampAbortIndexBuild : public StorageTimestampTest {
2308+
public:
2309+
void run() {
2310+
auto storageEngine = _opCtx->getServiceContext()->getStorageEngine();
2311+
auto durableCatalog = storageEngine->getCatalog();
2312+
2313+
NamespaceString nss("unittests.timestampAbortIndexBuild");
2314+
reset(nss);
2315+
2316+
std::vector<std::string> origIdents;
2317+
{
2318+
AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_X);
2319+
2320+
auto insertTimestamp1 = _clock->reserveTicks(1);
2321+
auto insertTimestamp2 = _clock->reserveTicks(1);
2322+
2323+
// Insert two documents with the same value for field 'a' so that
2324+
// we will fail to create a unique index.
2325+
WriteUnitOfWork wuow(_opCtx);
2326+
insertDocument(autoColl.getCollection(),
2327+
InsertStatement(BSON("_id" << 0 << "a" << 1),
2328+
insertTimestamp1.asTimestamp(),
2329+
presentTerm));
2330+
insertDocument(autoColl.getCollection(),
2331+
InsertStatement(BSON("_id" << 1 << "a" << 1),
2332+
insertTimestamp2.asTimestamp(),
2333+
presentTerm));
2334+
wuow.commit();
2335+
ASSERT_EQ(2, itCount(autoColl.getCollection()));
2336+
2337+
// Save the pre-state idents so we can capture the specific ident related to index
2338+
// creation.
2339+
origIdents = durableCatalog->getAllIdents(_opCtx);
2340+
}
2341+
2342+
{
2343+
DBDirectClient client(_opCtx);
2344+
2345+
IndexSpec index1;
2346+
// Name this index for easier querying.
2347+
index1.addKeys(BSON("a" << 1)).name("a_1").unique();
2348+
2349+
std::vector<const IndexSpec*> indexes;
2350+
indexes.push_back(&index1);
2351+
ASSERT_THROWS_CODE(
2352+
client.createIndexes(nss.ns(), indexes), DBException, ErrorCodes::DuplicateKey);
2353+
}
2354+
2355+
// Confirm that startIndexBuild and abortIndexBuild oplog entries have been written to the
2356+
// oplog.
2357+
auto indexStartDocument =
2358+
queryOplog(BSON("ns" << nss.db() + ".$cmd"
2359+
<< "o.startIndexBuild" << nss.coll() << "o.indexes.0.name"
2360+
<< "a_1"));
2361+
auto indexStartTs = indexStartDocument["ts"].timestamp();
2362+
auto indexAbortDocument =
2363+
queryOplog(BSON("ns" << nss.db() + ".$cmd"
2364+
<< "o.abortIndexBuild" << nss.coll() << "o.indexes.0.name"
2365+
<< "a_1"));
2366+
auto indexAbortTs = indexAbortDocument["ts"].timestamp();
2367+
2368+
// Check index state in catalog at oplog entry times for both startIndexBuild and
2369+
// abortIndexBuild.
2370+
AutoGetCollection autoColl(_opCtx, nss, LockMode::MODE_X);
2371+
2372+
// We expect one new one new index ident during this index build.
2373+
assertRenamedCollectionIdentsAtTimestamp(
2374+
durableCatalog, origIdents, /*expectedNewIndexIdents*/ 1, indexStartTs);
2375+
ASSERT_FALSE(
2376+
getIndexMetaData(getMetaDataAtTime(durableCatalog, nss, indexStartTs), "a_1").ready);
2377+
2378+
// We expect all new idents to be removed after the index build has aborted.
2379+
assertRenamedCollectionIdentsAtTimestamp(
2380+
durableCatalog, origIdents, /*expectedNewIndexIdents*/ 0, indexAbortTs);
2381+
assertIndexMetaDataMissing(getMetaDataAtTime(durableCatalog, nss, indexAbortTs), "a_1");
2382+
}
2383+
};
2384+
23012385
class TimestampIndexDrops : public StorageTimestampTest {
23022386
public:
23032387
void run() {
@@ -3480,6 +3564,7 @@ class AllStorageTimestampTests : public unittest::OldStyleSuiteSpecification {
34803564
// addIf<TimestampIndexBuildDrain<true>>();
34813565
addIf<TimestampMultiIndexBuilds>();
34823566
addIf<TimestampMultiIndexBuildsDuringRename>();
3567+
addIf<TimestampAbortIndexBuild>();
34833568
addIf<TimestampIndexDrops>();
34843569
addIf<TimestampIndexBuilderOnPrimary>();
34853570
addIf<SecondaryReadsDuringBatchApplicationAreAllowed>();

0 commit comments

Comments
 (0)