0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 17:10:48 +01:00

SERVER-41769 Pin _currentCommittedSnapshot to be <= the allCommitted timestamp when EMRC=false

This commit is contained in:
Jason Chan 2019-07-09 17:42:04 -04:00
parent 2dfbaadb85
commit 795b99ef36
4 changed files with 73 additions and 5 deletions

View File

@ -17,7 +17,8 @@
// Insert a document that gets deleted as part of the transaction.
const kDeletedDocumentId = 0;
coll.insert({_id: kDeletedDocumentId, a: "I was here before the transaction"});
coll.insert({_id: kDeletedDocumentId, a: "I was here before the transaction"},
{writeConcern: {w: "majority"}});
let cst = new ChangeStreamTest(db);
let changeStream = cst.startWatchingChanges({

View File

@ -47,7 +47,7 @@
// Insert a document unmodified by the transaction.
const otherDoc = {_id: 2, y: 2};
assert.commandWorked(testColl.insert(otherDoc));
assert.commandWorked(testColl.insert(otherDoc, {writeConcern: {w: "majority"}}));
// Create an index on 'y' to avoid conflicts on the field.
assert.commandWorked(testColl.createIndex({y: 1}));

View File

@ -0,0 +1,61 @@
/**
* This tests that writes with majority write concern will wait for at least the all committed
* timestamp to reach the timestamp of the write. This guarantees that once a write is majority
* committed, reading at the all committed timestamp will read that write.
*/
(function() {
"use strict";
load("jstests/libs/check_log.js");
function assertWriteConcernTimeout(result) {
assert.writeErrorWithCode(result, ErrorCodes.WriteConcernFailed);
assert(result.hasWriteConcernError(), tojson(result));
assert(result.getWriteConcernError().errInfo.wtimeout, tojson(result));
}
const rst = new ReplSetTest({name: "writes_wait_for_all_committed", nodes: 1});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
const dbName = "test";
const collName = "majority_writes_wait_for_all_committed";
const testDB = primary.getDB(dbName);
const testColl = testDB[collName];
TestData.dbName = dbName;
TestData.collName = collName;
testDB.runCommand({drop: collName, writeConcern: {w: "majority"}});
assert.commandWorked(testDB.createCollection(collName, {writeConcern: {w: "majority"}}));
assert.commandWorked(testDB.adminCommand({
configureFailPoint: "hangAfterCollectionInserts",
mode: "alwaysOn",
data: {collectionNS: testColl.getFullName(), first_id: "b"}
}));
jsTestLog(
"Insert a document to hang before the insert completes to hold back the all committed timestamp.");
const joinHungWrite = startParallelShell(() => {
assert.commandWorked(
db.getSiblingDB(TestData.dbName)[TestData.collName].insert({_id: "b"}));
}, primary.port);
jsTestLog("Checking that the log contains fail point enabled.");
checkLog.contains(
testDB.getMongo(),
"hangAfterCollectionInserts fail point enabled for " + testColl.getFullName());
try {
jsTest.log("Do a write with majority write concern that should time out.");
assertWriteConcernTimeout(
testColl.insert({_id: 0}, {writeConcern: {w: "majority", wtimeout: 2 * 1000}}));
} finally {
assert.commandWorked(
primary.adminCommand({configureFailPoint: 'hangAfterCollectionInserts', mode: 'off'}));
}
joinHungWrite();
rst.stopSet();
})();

View File

@ -3597,11 +3597,17 @@ void ReplicationCoordinatorImpl::_setStableTimestampForStorage(WithLock lk) {
stableOpTime->opTime.getTimestamp());
}
} else {
// When majority read concern is disabled, the stable optime may be ahead of the
// commit point, so we set the committed snapshot to the commit point.
const auto lastCommittedOpTime = _topCoord->getLastCommittedOpTimeAndWallTime();
if (!lastCommittedOpTime.opTime.isNull()) {
_updateCommittedSnapshot_inlock(lastCommittedOpTime);
// When majority read concern is disabled, we set the stable timestamp to
// be less than or equal to the all committed timestamp. This makes sure that
// the committed snapshot is not past the all committed timestamp to guarantee
// we can always read our own majority committed writes. This problem is
// specific to the case where we have a single node replica set and the
// lastCommittedOpTime is set to be the lastApplied which can be ahead of the
// allCommitted.
auto newCommittedSnapshot = std::min(lastCommittedOpTime, *stableOpTime);
_updateCommittedSnapshot_inlock(newCommittedSnapshot);
}
// Set the stable timestamp regardless of whether the majority commit point moved
// forward.