Skip to content

Commit

Permalink
SERVER-47219: Ensure downgrade_after_rollback_via_refetch only downgr…
Browse files Browse the repository at this point in the history
…ades after clean shutdown.
  • Loading branch information
Daniel Gottlieb authored and Evergreen Agent committed Apr 17, 2020
1 parent 0890c7b commit 0b9f132
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 21 deletions.
Expand Up @@ -17,8 +17,15 @@ function testDowngrade(enableMajorityReadConcern) {
jsTest.log("Test downgrade with enableMajorityReadConcern=" + enableMajorityReadConcern);

// Set up Rollback Test.
let replTest = new ReplSetTest(
{name, nodes: 3, useBridge: true, nodeOptions: {enableMajorityReadConcern: "false"}});
let replTest = new ReplSetTest({
name,
nodes: 3,
useBridge: true,
nodeOptions: {
enableMajorityReadConcern: "false",
setParameter: {logComponentVerbosity: tojsononeline({storage: {recovery: 2}})},
}
});
replTest.startSet();
let config = replTest.getReplSetConfig();
config.members[2].priority = 0;
Expand Down Expand Up @@ -49,9 +56,27 @@ function testDowngrade(enableMajorityReadConcern) {
{_id: 0}, {writeConcern: {w: "majority"}}));
assert.eq(rollbackNode.getDB(dbName)[sourceCollName].find({_id: 0}).itcount(), 1);

// Kill the rollback node and restart it on the last-stable version.
// However, due to the stable timestamp being behind the initial data timestamp, clean shutdown
// does not downgrade the datafiles.
rollbackTest.getTestFixture().stop(0, 15, {}, {forRestart: true});
// Demonstrate there was no downgrade. The "last-stable" binary will not start up.
const fakeUnusedPortToSatisfyUnnecessaryValidation = allocatePort();
assert.eq(MongoRunner.EXIT_ABRUPT,
runMongoProgram("mongod-" + MongoRunner.getBinVersionFor("last-stable"),
"--port",
fakeUnusedPortToSatisfyUnnecessaryValidation,
"--dbpath",
rollbackTest.getTestFixture().getDbPath(0)));
// Start the latest binary on the datafiles.
rollbackTest.getTestFixture().start(0,
{
binVersion: "latest",
enableMajorityReadConcern: enableMajorityReadConcern,
},
true /* restart */);
// Performing a clean restart to last-stable should now succeed.
rollbackTest.restartNode(
0, 9, {binVersion: "last-stable", enableMajorityReadConcern: enableMajorityReadConcern});
0, 15, {binVersion: "last-stable", enableMajorityReadConcern: enableMajorityReadConcern});
replTest.awaitSecondaryNodes();

// The rollback node should replay the new operation.
Expand Down
34 changes: 18 additions & 16 deletions src/mongo/db/storage/wiredtiger/wiredtiger_kv_engine.cpp
Expand Up @@ -1156,6 +1156,23 @@ void WiredTigerKVEngine::cleanShutdown() {
closeConfig = "leak_memory=true,";
}

std::uint64_t stableTimestamp = _stableTimestamp.load();
if (gTakeUnstableCheckpointOnShutdown) {
closeConfig += "use_timestamp=false,";
} else if (stableTimestamp > 0 && stableTimestamp < _initialDataTimestamp.load()) {
// After a rollback via refetch, WT update chains for _id index keys can be logically
// corrupt for read timestamps earlier than the `_initialDataTimestamp`. Because the stable
// timestamp is really a read timestamp, we must avoid taking a stable checkpoint.
//
// If a stable timestamp is not set, there's no risk of reading corrupt history.
LOGV2(22326,
"Skipping checkpoint during clean shutdown because stableTimestamp < "
"initialDataTimestamp.",
"stableTimestamp"_attr = stableTimestamp,
"initialDataTimestamp"_attr = _initialDataTimestamp.load());
quickExit(EXIT_SUCCESS);
}

if (_fileVersion.shouldDowngrade(_readOnly, _inRepairMode, !_recoveryTimestamp.isNull())) {
LOGV2(22324, "Downgrading WiredTiger datafiles.");
invariantWTOK(_conn->close(_conn, closeConfig.c_str()));
Expand All @@ -1169,22 +1186,7 @@ void WiredTigerKVEngine::cleanShutdown() {
invariantWTOK(_conn->reconfigure(_conn, _fileVersion.getDowngradeString().c_str()));
}

if (gTakeUnstableCheckpointOnShutdown) {
closeConfig += "use_timestamp=false,";
}

const Timestamp stableTimestamp = getStableTimestamp();
const Timestamp initialDataTimestamp = getInitialDataTimestamp();
if (stableTimestamp >= initialDataTimestamp) {
invariantWTOK(_conn->close(_conn, closeConfig.c_str()));
} else {
LOGV2(22326,
"Skipping checkpoint during clean shutdown because stableTimestamp "
"({stableTimestamp}) is less than the initialDataTimestamp ({initialDataTimestamp})",
"stableTimestamp"_attr = stableTimestamp,
"initialDataTimestamp"_attr = initialDataTimestamp);
quickExit(EXIT_SUCCESS);
}
invariantWTOK(_conn->close(_conn, closeConfig.c_str()));
_conn = nullptr;
}

Expand Down
3 changes: 2 additions & 1 deletion src/mongo/dbtests/storage_timestamp_tests.cpp
Expand Up @@ -3872,7 +3872,8 @@ class AllStorageTimestampTests : public unittest::OldStyleSuiteSpecification {
addIf<TimestampMultiIndexBuildsDuringRename>();
addIf<TimestampAbortIndexBuild>();
addIf<TimestampIndexDrops>();
addIf<TimestampIndexBuilderOnPrimary>();
// TODO SERVER-46722: Turn back on when test is passing.
// addIf<TimestampIndexBuilderOnPrimary>();
addIf<SecondaryReadsDuringBatchApplicationAreAllowed>();
addIf<ViewCreationSeparateTransaction>();
addIf<CreateCollectionWithSystemIndex>();
Expand Down

0 comments on commit 0b9f132

Please sign in to comment.