// @tags: [requires_replication, uses_transactions, uses_atclustertime] // Test the correct timestamping of insert, update, and delete writes along with their accompanying // index updates. // (function() { "use strict"; const dbName = "test"; const collName = "coll"; const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); const testDB = rst.getPrimary().getDB(dbName); const coll = testDB.getCollection(collName); if (!testDB.serverStatus().storageEngine.supportsSnapshotReadConcern) { rst.stopSet(); return; } // Turn off timestamp reaping. assert.commandWorked(testDB.adminCommand({ configureFailPoint: "WTPreserveSnapshotHistoryIndefinitely", mode: "alwaysOn", })); const session = testDB.getMongo().startSession({causalConsistency: false}); const sessionDb = session.getDatabase(dbName); const response = assert.commandWorked(testDB.createCollection("coll")); const startTime = response.operationTime; function check(atClusterTime, expected) { session.startTransaction({readConcern: {level: "snapshot", atClusterTime: atClusterTime}}); // Check both a collection scan and scanning the _id index. [{$natural: 1}, {_id: 1}].forEach(sort => { let response = assert.commandWorked( sessionDb.runCommand({find: collName, sort: sort, singleBatch: true})); assert.eq(expected, response.cursor.firstBatch); }); assert.commandWorked(session.commitTransaction_forTesting()); } // insert let request = {insert: coll.getName(), documents: [{_id: 1}, {_id: 2}], ordered: false}; assert.commandWorked(coll.runCommand(request)); const oplog = rst.getPrimary().getDB("local").getCollection("oplog.rs"); let ts1 = oplog.findOne({o: {_id: 1}}).ts; let ts2 = oplog.findOne({o: {_id: 2}}).ts; check(startTime, []); check(ts1, [{_id: 1}]); check(ts2, [{_id: 1}, {_id: 2}]); // upsert request = { update: coll.getName(), updates: [ {q: {_id: 3, a: 1}, u: {$set: {a: 2}}, upsert: true}, {q: {_id: 4, a: 1}, u: {$set: {a: 3}}, upsert: true} ], ordered: true }; assert.commandWorked(coll.runCommand(request)); ts1 = oplog.findOne({o: {_id: 3, a: 2}}).ts; ts2 = oplog.findOne({o: {_id: 4, a: 3}}).ts; check(ts1, [{_id: 1}, {_id: 2}, {_id: 3, a: 2}]); check(ts2, [{_id: 1}, {_id: 2}, {_id: 3, a: 2}, {_id: 4, a: 3}]); // update request = { update: coll.getName(), updates: [{q: {_id: 3, a: 2}, u: {$set: {a: 4}}}, {q: {_id: 4, a: 3}, u: {$set: {a: 5}}}], ordered: true }; assert.commandWorked(coll.runCommand(request)); ts1 = oplog.findOne({op: 'u', o2: {_id: 3}}).ts; ts2 = oplog.findOne({op: 'u', o2: {_id: 4}}).ts; check(ts1, [{_id: 1}, {_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 3}]); check(ts2, [{_id: 1}, {_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 5}]); // delete request = { delete: coll.getName(), deletes: [{q: {}, limit: 0}], ordered: false }; assert.commandWorked(coll.runCommand(request)); ts1 = oplog.findOne({op: 'd', o: {_id: 1}}).ts; ts2 = oplog.findOne({op: 'd', o: {_id: 2}}).ts; let ts3 = oplog.findOne({op: 'd', o: {_id: 3}}).ts; let ts4 = oplog.findOne({op: 'd', o: {_id: 4}}).ts; check(ts1, [{_id: 2}, {_id: 3, a: 4}, {_id: 4, a: 5}]); check(ts2, [{_id: 3, a: 4}, {_id: 4, a: 5}]); check(ts3, [{_id: 4, a: 5}]); check(ts4, []); session.endSession(); rst.stopSet(); }());