mirror of
https://github.com/mongodb/mongo.git
synced 2024-11-30 00:56:44 +01:00
162 lines
5.3 KiB
JavaScript
162 lines
5.3 KiB
JavaScript
/**
|
|
* Test speculative majority reads using the 'find' command.
|
|
*
|
|
* Speculative majority reads allow the server to provide "majority" read guarantees without storage
|
|
* engine support for reading from a historical snapshot. Instead of reading historical, majority
|
|
* committed data, we just read the newest data available on a node, and then, before returning to a
|
|
* client, block until we know the data has become majority committed. Currently this is an internal
|
|
* feature used only by change streams.
|
|
*
|
|
* @tags: [uses_speculative_majority]
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
load("jstests/libs/write_concern_util.js"); // for [stop|restart]ServerReplication.
|
|
load("jstests/libs/parallelTester.js"); // for Thread.
|
|
|
|
let name = "speculative_majority_find";
|
|
let replTest = new ReplSetTest({
|
|
name: name,
|
|
nodes: [{}, {rsConfig: {priority: 0}}],
|
|
nodeOptions: {
|
|
enableMajorityReadConcern: 'false',
|
|
// Increase log verbosity so we can see all commands that run on the server.
|
|
setParameter: {logComponentVerbosity: tojson({command: 2})}
|
|
}
|
|
});
|
|
replTest.startSet();
|
|
replTest.initiate();
|
|
|
|
let dbName = name;
|
|
let collName = "coll";
|
|
|
|
let primary = replTest.getPrimary();
|
|
let secondary = replTest.getSecondary();
|
|
|
|
let primaryDB = primary.getDB(dbName);
|
|
let secondaryDB = secondary.getDB(dbName);
|
|
let primaryColl = primaryDB[collName];
|
|
// Create a collection.
|
|
assert.commandWorked(primaryColl.insert({}, {writeConcern: {w: "majority"}}));
|
|
|
|
//
|
|
// Test basic reads with speculative majority.
|
|
//
|
|
|
|
// Pause replication on the secondary so that writes won't majority commit.
|
|
stopServerReplication(secondary);
|
|
assert.commandWorked(primaryColl.insert({_id: 1}));
|
|
|
|
jsTestLog("Do a speculative majority read that should time out.");
|
|
let res = primaryDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority"},
|
|
filter: {_id: 1},
|
|
allowSpeculativeMajorityRead: true,
|
|
maxTimeMS: 5000
|
|
});
|
|
assert.commandFailedWithCode(res, ErrorCodes.MaxTimeMSExpired);
|
|
|
|
restartServerReplication(secondary);
|
|
replTest.awaitReplication();
|
|
|
|
jsTestLog("Do a speculative majority read that should succeed.");
|
|
res = primaryDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority"},
|
|
filter: {_id: 1},
|
|
allowSpeculativeMajorityRead: true
|
|
});
|
|
assert.commandWorked(res);
|
|
assert.eq(res.cursor.firstBatch.length, 1);
|
|
assert.eq(res.cursor.firstBatch[0], {_id: 1});
|
|
|
|
//
|
|
// Test that blocked reads can succeed when a write majority commits.
|
|
//
|
|
|
|
// Pause replication on the secondary so that writes won't majority commit.
|
|
stopServerReplication(secondary);
|
|
assert.commandWorked(primaryColl.insert({_id: 2}));
|
|
|
|
jsTestLog("Do a speculative majority that should block until write commits.");
|
|
let speculativeRead = new Thread(function(host, dbName, collName) {
|
|
const nodeDB = new Mongo(host).getDB(dbName);
|
|
return nodeDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority"},
|
|
filter: {_id: 2},
|
|
allowSpeculativeMajorityRead: true
|
|
});
|
|
}, primary.host, dbName, collName);
|
|
speculativeRead.start();
|
|
|
|
// Wait for the read to start on the server.
|
|
assert.soon(() => primaryDB.currentOp({ns: primaryColl.getFullName(), "command.find": collName})
|
|
.inprog.length === 1);
|
|
|
|
// Let the previous write commit.
|
|
restartServerReplication(secondary);
|
|
assert.commandWorked(
|
|
primaryColl.insert({_id: "commit_last_write"}, {writeConcern: {w: "majority"}}));
|
|
|
|
// Make sure the read finished and returned correct results.
|
|
speculativeRead.join();
|
|
res = speculativeRead.returnData();
|
|
assert.commandWorked(res);
|
|
assert.eq(res.cursor.firstBatch.length, 1);
|
|
assert.eq(res.cursor.firstBatch[0], {_id: 2});
|
|
|
|
//
|
|
// Test 'afterClusterTime' reads with speculative majority.
|
|
//
|
|
stopServerReplication(secondary);
|
|
|
|
// Insert a document on the primary and record the response.
|
|
let writeRes = primaryDB.runCommand({insert: collName, documents: [{_id: 3}]});
|
|
assert.commandWorked(writeRes);
|
|
|
|
jsTestLog(
|
|
"Do a speculative majority read on primary with 'afterClusterTime' that should time out.");
|
|
res = primaryDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority", afterClusterTime: writeRes.operationTime},
|
|
filter: {_id: 3},
|
|
$clusterTime: writeRes.$clusterTime,
|
|
allowSpeculativeMajorityRead: true,
|
|
maxTimeMS: 5000
|
|
});
|
|
assert.commandFailedWithCode(res, ErrorCodes.MaxTimeMSExpired);
|
|
|
|
jsTestLog(
|
|
"Do a speculative majority read on secondary with 'afterClusterTime' that should time out.");
|
|
res = secondaryDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority", afterClusterTime: writeRes.operationTime},
|
|
filter: {_id: 3},
|
|
$clusterTime: writeRes.$clusterTime,
|
|
allowSpeculativeMajorityRead: true,
|
|
maxTimeMS: 5000
|
|
});
|
|
assert.commandFailedWithCode(res, ErrorCodes.MaxTimeMSExpired);
|
|
|
|
// Let the previous write majority commit.
|
|
restartServerReplication(secondary);
|
|
replTest.awaitReplication();
|
|
|
|
jsTestLog("Do a speculative majority read with 'afterClusterTime' that should succeed.");
|
|
res = primaryDB.runCommand({
|
|
find: collName,
|
|
readConcern: {level: "majority", afterClusterTime: writeRes.operationTime},
|
|
filter: {_id: 3},
|
|
$clusterTime: res.$clusterTime,
|
|
allowSpeculativeMajorityRead: true
|
|
});
|
|
assert.commandWorked(res);
|
|
assert.eq(res.cursor.firstBatch.length, 1);
|
|
assert.eq(res.cursor.firstBatch[0], {_id: 3});
|
|
|
|
replTest.stopSet();
|
|
})();
|