0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00

SERVER-39672: default to local if no read concern specified for a multi-statment transaction

This commit is contained in:
Lingzhi Deng 2019-03-27 17:59:17 -04:00
parent 109129eb5f
commit 74fd169e88
6 changed files with 55 additions and 43 deletions

View File

@ -22,15 +22,21 @@
assert.commandWorked(testDB.createCollection(collName2, {writeConcern: {w: "majority"}}));
const sessionOptions = {causalConsistency: false};
const session = db.getMongo().startSession(sessionOptions);
const sessionDb = session.getDatabase(dbName);
const sessionColl = sessionDb.getCollection(collName);
const sessionColl2 = sessionDb.getCollection(collName2);
const session2 = db.getMongo().startSession(sessionOptions);
const session2Db = session2.getDatabase(dbName);
const session2Coll = session2Db.getCollection(collName);
const session2Coll2 = session2Db.getCollection(collName2);
function startSessionAndTransaction(readConcernLevel) {
let session = db.getMongo().startSession(sessionOptions);
jsTestLog("Start a transaction with readConcern " + readConcernLevel.level + ".");
session.startTransaction({readConcern: readConcernLevel});
return session;
};
let checkReads = (session, collExpected, coll2Expected) => {
let sessionDb = session.getDatabase(dbName);
let coll = sessionDb.getCollection(collName);
let coll2 = sessionDb.getCollection(collName2);
assert.sameMembers(collExpected, coll.find().toArray());
assert.sameMembers(coll2Expected, coll2.find().toArray());
};
// Clear ramlog so checkLog can't find log messages from previous times this fail point was
// enabled.
@ -63,21 +69,17 @@
// the prior uncommitted write is committed.
assert.commandWorked(testColl.insert([{_id: 1}]));
jsTestLog("Start a snapshot transaction.");
const snapshotSession = startSessionAndTransaction({level: "snapshot"});
checkReads(snapshotSession, [{_id: 0}], [{_id: "a"}]);
session.startTransaction({readConcern: {level: "snapshot"}});
const majoritySession = startSessionAndTransaction({level: "majority"});
checkReads(majoritySession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
assert.sameMembers([{_id: 0}], sessionColl.find().toArray());
const localSession = startSessionAndTransaction({level: "local"});
checkReads(localSession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
assert.sameMembers([{_id: "a"}], sessionColl2.find().toArray());
jsTestLog("Start a majority-read transaction.");
session2.startTransaction({readConcern: {level: "majority"}});
assert.sameMembers([{_id: 0}, {_id: 1}], session2Coll.find().toArray());
assert.sameMembers([{_id: "a"}], session2Coll2.find().toArray());
const defaultSession = startSessionAndTransaction({});
checkReads(defaultSession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
jsTestLog("Allow the uncommitted write to finish.");
assert.commandWorked(db.adminCommand({
@ -88,25 +90,25 @@
joinHungWrite();
jsTestLog("Double-checking that writes not committed at start of snapshot cannot appear.");
assert.sameMembers([{_id: 0}], sessionColl.find().toArray());
checkReads(snapshotSession, [{_id: 0}], [{_id: "a"}]);
assert.sameMembers([{_id: "a"}], sessionColl2.find().toArray());
assert.sameMembers([{_id: 0}, {_id: 1}], session2Coll.find().toArray());
assert.sameMembers([{_id: "a"}], session2Coll2.find().toArray());
jsTestLog(
"Double-checking that writes performed before the start of a transaction of 'majority' or lower must appear.");
checkReads(majoritySession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
checkReads(localSession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
checkReads(defaultSession, [{_id: 0}, {_id: 1}], [{_id: "a"}]);
jsTestLog("Committing transactions.");
session.commitTransaction();
session2.commitTransaction();
snapshotSession.commitTransaction();
majoritySession.commitTransaction();
localSession.commitTransaction();
defaultSession.commitTransaction();
assert.sameMembers([{_id: 0}, {_id: 1}], sessionColl.find().toArray());
jsTestLog("A new local read must see all committed writes.");
checkReads(defaultSession, [{_id: 0}, {_id: 1}], [{_id: "a"}, {_id: "b"}]);
assert.sameMembers([{_id: "a"}, {_id: "b"}], sessionColl2.find().toArray());
assert.sameMembers([{_id: 0}, {_id: 1}], session2Coll.find().toArray());
assert.sameMembers([{_id: "a"}, {_id: "b"}], session2Coll2.find().toArray());
session.endSession();
snapshotSession.endSession();
majoritySession.endSession();
localSession.endSession();
defaultSession.endSession();
}());

View File

@ -71,7 +71,7 @@
jsTest.log("Start a transaction and then commit it.");
// Compare server status after starting a transaction with the server status before.
session.startTransaction();
session.startTransaction({readConcern: {level: 'snapshot'}});
assert.commandWorked(sessionColl.insert({_id: "insert-1"}));
// Trigger the oldestOpenUnpreparedReadTimestamp to be set.
assert.eq(sessionColl.find({_id: "insert-1"}).itcount(), 1);
@ -110,7 +110,7 @@
jsTest.log("Start a transaction and then abort it.");
// Compare server status after starting a transaction with the server status before.
session.startTransaction();
session.startTransaction({readConcern: {level: 'snapshot'}});
assert.commandWorked(sessionColl.insert({_id: "insert-2"}));
// Trigger the oldestOpenUnpreparedReadTimestamp to be set.
assert.eq(sessionColl.find({_id: "insert-2"}).itcount(), 1);
@ -150,7 +150,7 @@
jsTest.log("Start a transaction that will abort on a duplicated key error.");
// Compare server status after starting a transaction with the server status before.
session.startTransaction();
session.startTransaction({readConcern: {level: 'snapshot'}});
// Inserting a new document will work fine, and the transaction starts.
assert.commandWorked(sessionColl.insert({_id: "insert-3"}));
// Trigger the oldestOpenUnpreparedReadTimestamp to be set.

View File

@ -69,7 +69,7 @@
const doc1 = {_id: 1, x: 1};
// Start transaction and prepare transaction.
session.startTransaction();
session.startTransaction({readConcern: {level: 'snapshot'}});
assert.commandWorked(sessionColl.insert(doc1));
// Trigger the oldestOpenUnpreparedReadTimestamp to be set.
@ -118,7 +118,7 @@
const doc2 = {_id: 2, x: 2};
// Start transaction and prepare transaction.
session.startTransaction();
session.startTransaction({readConcern: {level: 'snapshot'}});
assert.commandWorked(sessionColl.insert(doc2));
// Trigger the oldestOpenUnpreparedReadTimestamp to be set.

View File

@ -35,7 +35,7 @@
jsTestLog(
`Testing that SnapshotUnavailable during ${op} is labelled TransientTransactionError`);
session.startTransaction();
session.startTransaction({readConcern: {level: "snapshot"}});
assert.commandWorked(sessionDB.runCommand({insert: collName, documents: [{}]}));
// Create collection outside transaction, cannot write to it in the transaction
assert.commandWorked(primaryDB.getSiblingDB(dbNameB).runCommand({create: collNameB}));

View File

@ -106,7 +106,8 @@ ReadConcernLevel ReadConcernArgs::getLevel() const {
}
ReadConcernLevel ReadConcernArgs::getOriginalLevel() const {
return _originalLevel.value_or(getLevel());
// If no read concern specified, default to "local"
return _originalLevel.value_or(ReadConcernLevel::kLocalReadConcern);
}
bool ReadConcernArgs::hasLevel() const {

View File

@ -510,6 +510,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, EmptyLevel) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kLocalReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, LevelLocal) {
@ -522,6 +523,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelLocal) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kLocalReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, LevelMajority) {
@ -535,6 +537,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelMajority) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kMajorityReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, LevelSnapshot) {
@ -548,6 +551,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelSnapshot) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, LevelSnapshotWithAtClusterTime) {
@ -565,6 +569,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelSnapshotWithAtClusterTime) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getOriginalLevel());
ASSERT_TRUE(readConcern.getArgsAtClusterTime());
}
@ -581,6 +586,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, AfterClusterTime) {
ASSERT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kSnapshotReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kLocalReadConcern == readConcern.getOriginalLevel());
ASSERT_TRUE(readConcern.getArgsAfterClusterTime());
}
@ -595,6 +601,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelAvailable) {
ASSERT_NOT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kAvailableReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kAvailableReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, LevelLinearizable) {
@ -608,6 +615,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, LevelLinearizable) {
ASSERT_NOT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kLinearizableReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kLinearizableReadConcern == readConcern.getOriginalLevel());
}
TEST(UpconvertReadConcernLevelToSnapshot, AfterOpTime) {
@ -624,6 +632,7 @@ TEST(UpconvertReadConcernLevelToSnapshot, AfterOpTime) {
ASSERT_NOT_OK(readConcern.upconvertReadConcernLevelToSnapshot());
ASSERT(ReadConcernLevel::kLocalReadConcern == readConcern.getLevel());
ASSERT(ReadConcernLevel::kLocalReadConcern == readConcern.getOriginalLevel());
ASSERT_TRUE(readConcern.getArgsOpTime());
}