Files
mongo/jstests/replsets/change_stream_speculative_majority_optimized_wait.js
William Schultz ffb19c1792 SERVER-38754 Make speculative majority change stream reads wait on optimized optimes
Speculative majority change stream oplog reads now only wait on the latest scanned oplog timestamp when possible, as opposed to always waiting on the latest system-wide lastApplied optime. If a document post-image lookup occurs locally for a change stream read, then this optimization is not safe, since the document lookup may reflect data at some unknown timestamp. In this case, we revert to waiting on the node's lastApplied optime.
2019-01-23 14:38:08 -05:00

83 lines
3.3 KiB
JavaScript

/**
* Verify that speculative majority change stream oplog reads only wait on the latest scanned oplog
* optime, as opposed to the newest system-wide applied optime. This is an optimization to reduce
* unnecessary waiting on the server.
*
* @tags: [uses_speculative_majority]
*/
(function() {
"use strict";
load("jstests/libs/write_concern_util.js"); // for [stop|restart]ServerReplication.
const name = "change_stream_speculative_majority";
const replTest = new ReplSetTest({
name: name,
nodes: [{}, {rsConfig: {priority: 0}}],
nodeOptions: {enableMajorityReadConcern: 'false'}
});
replTest.startSet();
replTest.initiate();
const dbName = name;
const collName = "coll";
let primary = replTest.getPrimary();
let secondary = replTest.getSecondary();
let primaryDB = primary.getDB(dbName);
let primaryColl = primaryDB[collName];
// Receive 1 change to get an initial resume token.
let res = assert.commandWorked(
primaryDB.runCommand({aggregate: collName, pipeline: [{$changeStream: {}}], cursor: {}}));
let cursorId = res.cursor.id;
assert.commandWorked(primaryColl.insert({_id: 0}, {writeConcern: {w: "majority"}}));
res = primary.getDB(dbName).runCommand({getMore: cursorId, collection: collName});
assert.eq(res.cursor.nextBatch.length, 1);
let resumeToken = res.cursor.nextBatch[0]["_id"];
// Open a change stream.
res = assert.commandWorked(
primaryDB.runCommand({aggregate: collName, pipeline: [{$changeStream: {}}], cursor: {}}));
cursorId = res.cursor.id;
// Insert documents to fill one batch and let them majority commit.
let batchSize = 2;
assert.commandWorked(primaryColl.insert({_id: 1}, {writeConcern: {w: "majority"}}));
assert.commandWorked(primaryColl.insert({_id: 2}, {writeConcern: {w: "majority"}}));
// Pause replication on the secondary so that writes won't majority commit.
stopServerReplication(secondary);
// Do write on primary that won't majority commit but will advance the last applied optime.
assert.commandWorked(primaryColl.insert({_id: 3}));
// Receive one batch of change events. We should be able to read only the majority committed
// change events and no further in order to generate this batch.
res = assert.commandWorked(primary.getDB(dbName).runCommand(
{getMore: cursorId, collection: collName, batchSize: batchSize}));
let changes = res.cursor.nextBatch;
assert.eq(changes.length, 2);
assert.eq(changes[0]["fullDocument"], {_id: 1});
assert.eq(changes[0]["operationType"], "insert");
assert.eq(changes[1]["fullDocument"], {_id: 2});
assert.eq(changes[1]["operationType"], "insert");
// Make sure that 'aggregate' commands also utilize the optimization.
res = assert.commandWorked(primaryDB.runCommand({
aggregate: collName,
pipeline: [{$changeStream: {resumeAfter: resumeToken}}],
cursor: {batchSize: batchSize}
}));
changes = res.cursor.firstBatch;
assert.eq(changes.length, 2);
assert.eq(changes[0]["fullDocument"], {_id: 1});
assert.eq(changes[0]["operationType"], "insert");
assert.eq(changes[1]["fullDocument"], {_id: 2});
assert.eq(changes[1]["operationType"], "insert");
// Let the test finish.
restartServerReplication(secondary);
replTest.stopSet();
})();