mongo/jstests/replsets/replicate_record_ids.js

121 lines
4.7 KiB
JavaScript

/**
* Tests recordIds show up when inserting into a collection with the
* 'recordIdsReplicated' flag set.
*
* @tags: [
* featureFlagRecordIdsReplicated,
* # TODO (SERVER-89640): Remove tag.
* # Incompatible with the recordIdsReplicated:true builder, as it sets the option
* # on all collections.
* exclude_when_record_ids_replicated
* ]
*/
import {
getRidForDoc,
validateShowRecordIdReplicatesAcrossNodes,
} from "jstests/libs/collection_write_path/replicated_record_ids_utils.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
const replSet = new ReplSetTest({nodes: 2});
replSet.startSet();
replSet.initiate();
const primary = replSet.getPrimary();
const secondary = replSet.getSecondaries()[0];
const dbName = "test";
const unReplRidCollName = "unreplRecIdColl";
const replRidCollName = "replRecIdColl";
const primDB = primary.getDB(dbName);
const secDB = secondary.getDB(dbName);
const unReplRidNs = `${dbName}.${unReplRidCollName}`;
const replRidNs = `${dbName}.${replRidCollName}`;
const getOplogEntries = function (conn, oplogQuery) {
return replSet.findOplog(conn, oplogQuery).toArray();
};
const validateRidInOplogs = function (oplogQuery, expectedRid) {
const primOplogEntry = getOplogEntries(primary, oplogQuery)[0];
const secOplogEntry = getOplogEntries(secondary, oplogQuery)[0];
assert.eq(
primOplogEntry.rid,
expectedRid,
`Mismatching recordIds. Primary's oplog entry: ${tojson(primOplogEntry)}, on disk: ${tojson(
expectedRid,
)}. Oplog query ${tojson(oplogQuery)}`,
);
assert.eq(
secOplogEntry.rid,
expectedRid,
`Mismatching recordIds. Secondary's oplog entry: ${tojson(secOplogEntry)}, on disk: ${tojson(expectedRid)}`,
);
};
let docA = {"a": 1};
// Create a collection without the 'recordIdsReplicated' param set. This shouldn't
// insert the recordId (rid) into the oplog.
primDB[unReplRidCollName].insert(docA);
const oplogNoRid = replSet.findOplog(primary, {ns: `${unReplRidNs}`}).toArray()[0];
assert(!oplogNoRid.rid, `Unexpectedly found rid in entry: ${tojson(oplogNoRid)}`);
// Create a collection with the param set. This time the recordId should show up
// in the oplog.
primDB.runCommand({create: replRidCollName, recordIdsReplicated: true});
const docAInsertOpTime = assert.commandWorked(primDB.runCommand({insert: replRidCollName, documents: [docA]})).opTime;
replSet.awaitReplication();
const docAReplRid = getRidForDoc(primDB, replRidCollName, docA);
assert.eq(docAReplRid, getRidForDoc(secDB, replRidCollName, docA));
// For the replRecIdColl the recordId should be in the oplog, and should match
// the actual recordId on disk.
validateRidInOplogs({ns: `${replRidNs}`, ...docAInsertOpTime}, docAReplRid);
primDB.setLogLevel(3);
const newDocA = {
"a": 2,
};
const docAUpdateOpTime = assert.commandWorked(
primDB.runCommand({update: replRidCollName, updates: [{q: docA, u: {$set: {"a": 2}}}]}),
).opTime;
docA = newDocA;
replSet.awaitReplication();
validateRidInOplogs({ns: `${replRidNs}`, ...docAUpdateOpTime}, docAReplRid);
// The recordId should also be in the oplog entry for the delete.
const docARemoveOpTime = assert.commandWorked(
primDB.runCommand({delete: replRidCollName, deletes: [{q: docA, limit: 1}]}),
).opTime;
replSet.awaitReplication();
validateRidInOplogs({ns: `${replRidNs}`, ...docARemoveOpTime}, docAReplRid);
// On replication, secondaries apply oplog entries in parallel - a batch of oplog entries is
// distributed amongst several appliers, who apply the entries in parallel. Therefore, if we
// insert a single document at a time, it is likely that the replicated oplog batches will have
// just a single oplog entry each time, and therefore the secondary will basically be processing
// oplog entries in the same order that they appear on the primary. If processed in the same
// order, it is likely that the secondaries will generate the same recordIds as the primary,
// even with recordIdsReplicated:false.
//
// Therefore to ensure that recordIdsReplicated:true actually works we need to make sure that
// the appliers process oplog entries in parallel, and this is done by having a full batch of
// entries for the appliers to process. We can achieve this by performing an insertMany.
jsTestLog("Test inserting multiple documents at a time.");
const docs = [];
for (let i = 0; i < 500; i++) {
docs.push({_id: i});
}
assert.commandWorked(primDB[replRidCollName].insertMany(docs));
assert.eq(primDB[replRidCollName].count(), 500);
// Ensure that the on disk data on both nodes has the same recordIds.
replSet.awaitReplication();
validateShowRecordIdReplicatesAcrossNodes(replSet.nodes, dbName, replRidCollName);
replSet.stopSet();