2016-04-12 19:11:23 -04:00
|
|
|
/**
|
|
|
|
|
* Utilities for testing writeConcern.
|
|
|
|
|
*/
|
|
|
|
|
|
2020-09-25 17:49:25 +00:00
|
|
|
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
|
2024-08-20 17:54:15 -04:00
|
|
|
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
2020-09-25 17:49:25 +00:00
|
|
|
|
2017-02-07 17:02:34 -05:00
|
|
|
// Shards a collection with 'numDocs' documents and creates 2 chunks, one on each of two shards.
|
|
|
|
|
export function shardCollectionWithChunks(st, coll, numDocs) {
|
2025-08-28 15:11:44 -04:00
|
|
|
let _db = coll.getDB();
|
|
|
|
|
let numberDoc = numDocs || 20;
|
2020-11-17 13:45:05 +00:00
|
|
|
coll.createIndex({x: 1}, {unique: true});
|
2023-09-28 07:55:39 +00:00
|
|
|
|
2025-08-21 10:17:44 -07:00
|
|
|
st.shardColl(coll.getName(), {x: 1}, {x: numberDoc / 2}, {x: numberDoc / 2}, _db.toString(), true);
|
2016-04-12 19:11:23 -04:00
|
|
|
|
2025-08-28 15:11:44 -04:00
|
|
|
for (let i = 0; i < numberDoc; i++) {
|
2016-04-12 19:11:23 -04:00
|
|
|
coll.insert({x: i});
|
|
|
|
|
}
|
|
|
|
|
assert.eq(coll.count(), numberDoc);
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 18:07:51 -05:00
|
|
|
// Stops replication on the given server(s).
|
2020-04-27 12:17:43 -04:00
|
|
|
export function stopServerReplication(conn) {
|
2016-12-15 18:07:51 -05:00
|
|
|
if (conn.length) {
|
2025-08-21 10:17:44 -07:00
|
|
|
conn.forEach(function (n) {
|
2016-12-15 18:07:51 -05:00
|
|
|
stopServerReplication(n);
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
2025-08-21 10:17:44 -07:00
|
|
|
const stopReplProducerFailPoint = configureFailPoint(conn, "stopReplProducer");
|
2017-01-17 17:06:52 -05:00
|
|
|
|
2017-07-05 15:18:06 -04:00
|
|
|
// Wait until the fail point is actually hit. Don't wait if the node is the primary, because
|
|
|
|
|
// the fail point won't be hit until the node transitions from being the primary.
|
2025-08-21 10:17:44 -07:00
|
|
|
if (assert.commandWorked(conn.adminCommand("replSetGetStatus")).myState != ReplSetTest.State.PRIMARY) {
|
2020-09-25 17:49:25 +00:00
|
|
|
stopReplProducerFailPoint.wait();
|
2017-07-05 15:18:06 -04:00
|
|
|
}
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-21 21:25:38 +00:00
|
|
|
// Stops replication at all replicaset secondaries. However, it might wait for replication before
|
|
|
|
|
// stopping it.
|
2021-05-04 21:59:34 +00:00
|
|
|
export function stopReplicationOnSecondaries(rs, changeReplicaSetDefaultWCToLocal = true) {
|
|
|
|
|
if (changeReplicaSetDefaultWCToLocal == true) {
|
|
|
|
|
// The default WC is majority and this test can't satisfy majority writes.
|
2025-08-21 10:17:44 -07:00
|
|
|
assert.commandWorked(
|
|
|
|
|
rs
|
|
|
|
|
.getPrimary()
|
|
|
|
|
.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}, writeConcern: {w: "majority"}}),
|
|
|
|
|
);
|
2021-06-21 21:25:38 +00:00
|
|
|
rs.awaitReplication();
|
2021-05-04 21:59:34 +00:00
|
|
|
}
|
2016-12-15 18:07:51 -05:00
|
|
|
stopServerReplication(rs.getSecondaries());
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stops replication at all shard secondaries.
|
|
|
|
|
export function stopReplicationOnSecondariesOfAllShards(st) {
|
2021-05-04 21:59:34 +00:00
|
|
|
// The default WC is majority and this test can't satisfy majority writes.
|
2025-08-21 10:17:44 -07:00
|
|
|
assert.commandWorked(
|
|
|
|
|
st.s.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}, writeConcern: {w: "majority"}}),
|
|
|
|
|
);
|
|
|
|
|
st._rsObjects.forEach((rs) => stopReplicationOnSecondaries(rs, false));
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
2016-12-15 18:07:51 -05:00
|
|
|
// Restarts replication on the given server(s).
|
2016-04-12 19:11:23 -04:00
|
|
|
export function restartServerReplication(conn) {
|
2016-12-15 18:07:51 -05:00
|
|
|
if (conn.length) {
|
2025-08-21 10:17:44 -07:00
|
|
|
conn.forEach(function (n) {
|
2016-12-15 18:07:51 -05:00
|
|
|
restartServerReplication(n);
|
|
|
|
|
});
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-28 15:11:44 -04:00
|
|
|
let errMsg = "Failed to disable stopReplProducer failpoint.";
|
2025-08-21 10:17:44 -07:00
|
|
|
assert.commandWorked(conn.getDB("admin").runCommand({configureFailPoint: "stopReplProducer", mode: "off"}), errMsg);
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restarts replication at all nodes in a replicaset.
|
|
|
|
|
export function restartReplSetReplication(rs) {
|
2016-12-15 18:07:51 -05:00
|
|
|
restartServerReplication(rs.nodes);
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
2016-12-29 17:53:37 -05:00
|
|
|
// Restarts replication at all replicaset secondaries.
|
|
|
|
|
export function restartReplicationOnSecondaries(rs) {
|
2016-12-15 18:07:51 -05:00
|
|
|
restartServerReplication(rs.getSecondaries());
|
2016-12-29 17:53:37 -05:00
|
|
|
}
|
|
|
|
|
|
2016-04-12 19:11:23 -04:00
|
|
|
// Restarts replication at all nodes in a sharded cluster.
|
|
|
|
|
export function restartReplicationOnAllShards(st) {
|
|
|
|
|
st._rsObjects.forEach(restartReplSetReplication);
|
|
|
|
|
restartReplSetReplication(st.configRS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Asserts that a writeConcernError was received.
|
|
|
|
|
export function assertWriteConcernError(res) {
|
|
|
|
|
assert(res.writeConcernError, "No writeConcernError received, got: " + tojson(res));
|
2018-08-23 13:13:02 -04:00
|
|
|
assert(res.writeConcernError.code, "No writeConcernError code, got: " + tojson(res));
|
|
|
|
|
assert(res.writeConcernError.errmsg, "No writeConcernError errmsg, got: " + tojson(res));
|
2016-04-12 19:11:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the specified command, on the admin database if specified.
|
|
|
|
|
export function runCommandCheckAdmin(db, cmd) {
|
|
|
|
|
if (cmd.admin) {
|
|
|
|
|
return db.adminCommand(cmd.req);
|
|
|
|
|
} else {
|
|
|
|
|
return db.runCommand(cmd.req);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-23 13:13:02 -04:00
|
|
|
|
|
|
|
|
// Asserts that writeConcern timed out.
|
|
|
|
|
export function checkWriteConcernTimedOut(res) {
|
|
|
|
|
assertWriteConcernError(res);
|
|
|
|
|
const errInfo = res.writeConcernError.errInfo;
|
|
|
|
|
assert(errInfo, "No writeConcernError errInfo, got: " + tojson(res));
|
|
|
|
|
assert(errInfo.wtimeout, "No errInfo wtimeout, got: " + tojson(res));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tests that a command properly waits for writeConcern on retry. Takes an optional
|
|
|
|
|
* 'setupFunc' that sets up the database state. 'setupFunc' accepts a connection to the
|
|
|
|
|
* primary.
|
|
|
|
|
*/
|
|
|
|
|
export function runWriteConcernRetryabilityTest(priConn, secConn, cmd, kNodes, dbName, setupFunc) {
|
|
|
|
|
dbName = dbName || "test";
|
|
|
|
|
jsTestLog(`Testing ${tojson(cmd)} on ${dbName}.`);
|
|
|
|
|
|
2021-05-04 21:59:34 +00:00
|
|
|
// The default WC is majority and stopServerReplication will prevent the replica set from
|
|
|
|
|
// fulfilling any majority writes
|
2025-08-21 10:17:44 -07:00
|
|
|
assert.commandWorked(
|
|
|
|
|
priConn.adminCommand({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}, writeConcern: {w: "majority"}}),
|
|
|
|
|
);
|
2021-05-04 21:59:34 +00:00
|
|
|
|
2018-08-23 13:13:02 -04:00
|
|
|
// Send a dummy write to this connection so it will have the Client object initialized.
|
|
|
|
|
const secondPriConn = new Mongo(priConn.host);
|
|
|
|
|
const testDB2 = secondPriConn.getDB(dbName);
|
2019-06-25 13:14:41 -04:00
|
|
|
assert.commandWorked(testDB2.dummy.insert({x: 1}, {writeConcern: {w: kNodes}}));
|
2018-08-23 13:13:02 -04:00
|
|
|
|
|
|
|
|
if (setupFunc) {
|
|
|
|
|
setupFunc(priConn);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stopServerReplication(secConn);
|
|
|
|
|
|
|
|
|
|
const testDB = priConn.getDB(dbName);
|
|
|
|
|
checkWriteConcernTimedOut(testDB.runCommand(cmd));
|
2019-06-25 13:14:41 -04:00
|
|
|
|
|
|
|
|
// Retry the command on the new connection whose lastOp will be less than the main connection.
|
|
|
|
|
checkWriteConcernTimedOut(testDB2.runCommand(cmd));
|
|
|
|
|
|
|
|
|
|
// Retry the command on the main connection whose lastOp will not have changed.
|
|
|
|
|
checkWriteConcernTimedOut(testDB.runCommand(cmd));
|
|
|
|
|
|
|
|
|
|
// Bump forward the client lastOp on both connections and try again on both.
|
|
|
|
|
assert.commandWorked(testDB.dummy.insert({x: 2}));
|
|
|
|
|
assert.commandWorked(testDB2.dummy.insert({x: 3}));
|
|
|
|
|
checkWriteConcernTimedOut(testDB.runCommand(cmd));
|
2018-08-23 13:13:02 -04:00
|
|
|
checkWriteConcernTimedOut(testDB2.runCommand(cmd));
|
|
|
|
|
|
|
|
|
|
restartServerReplication(secConn);
|
2023-04-26 17:50:58 +00:00
|
|
|
}
|