mirror of https://github.com/mongodb/mongo
105 lines
3.7 KiB
JavaScript
105 lines
3.7 KiB
JavaScript
/**
|
|
* Tests replicated truncates on a clustered collection.
|
|
* Creates a clustered collection and inserts a number of documents.
|
|
* Triggers a replicated truncate via applyOps that injects a truncateRange oplog entry.
|
|
* Validates a consistent state between primary and secondary after the truncate.
|
|
* Tests different combinations of start and end bounds for the truncate range.
|
|
*
|
|
* @tags: [
|
|
* requires_replication,
|
|
* requires_fcv_83,
|
|
* featureFlagUseReplicatedTruncatesForDeletions,
|
|
* ]
|
|
*/
|
|
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
|
|
|
const rst = new ReplSetTest({nodes: 2});
|
|
rst.startSet();
|
|
rst.initiate();
|
|
rst.awaitSecondaryNodes();
|
|
|
|
const primary = rst.getPrimary();
|
|
const dbName = "test";
|
|
const collName = "coll";
|
|
const testDB = primary.getDB(dbName);
|
|
const coll = testDB.getCollection(collName);
|
|
const secondary = rst.getSecondary();
|
|
const secondaryDB = secondary.getDB(dbName);
|
|
const secondaryColl = secondaryDB.getCollection(collName);
|
|
|
|
function setup(numToInsert) {
|
|
jsTest.log.info("Creating clustered collection");
|
|
assert.commandWorked(testDB.createCollection(collName, {clusteredIndex: {key: {_id: 1}, unique: true}}));
|
|
|
|
jsTest.log.info(`Inserting ${numToInsert} documents`);
|
|
let docs = [];
|
|
for (let i = 1; i <= numToInsert; i++) {
|
|
docs.push({_id: i});
|
|
}
|
|
assert.commandWorked(coll.insertMany(docs));
|
|
|
|
jsTest.log.info("Waiting for replication after insert");
|
|
rst.awaitReplication();
|
|
}
|
|
|
|
function doTest(startIndex, endIndex, originalDocs, docsBeforeTruncate) {
|
|
const minId = originalDocs[startIndex]._id;
|
|
const maxId = originalDocs[endIndex]._id;
|
|
|
|
// Truncate the array
|
|
const expectedDocs = docsBeforeTruncate.filter((item) => item._id < minId || item._id > maxId);
|
|
const recordsDeleted = docsBeforeTruncate.length - expectedDocs.length;
|
|
|
|
jsTest.log.info(`Truncating ${recordsDeleted} documents from {_id: ${minId}} to {_id: ${maxId}}`);
|
|
const applyOpsCmd = {
|
|
applyOps: [
|
|
{
|
|
op: "c",
|
|
ns: `${dbName}.$cmd`,
|
|
o: {
|
|
"truncateRange": coll.getFullName(),
|
|
"minRecordId": originalDocs[startIndex].$recordId,
|
|
"maxRecordId": originalDocs[endIndex].$recordId,
|
|
"bytesDeleted": recordsDeleted, // just a placeholder
|
|
"docsDeleted": recordsDeleted,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
jsTest.log.info(`Applying applyOps: ${tojson(applyOpsCmd)}`);
|
|
assert.commandWorked(testDB.runCommand(applyOpsCmd));
|
|
|
|
jsTest.log.info("Waiting for replication after truncate");
|
|
rst.awaitReplication();
|
|
|
|
// Validate the collection contents match expected after truncate
|
|
const primaryDocs = coll.find().sort({_id: 1}).showRecordId().toArray();
|
|
assert.eq(primaryDocs, expectedDocs, "Primary documents not as expected after truncate");
|
|
|
|
const secondaryDocs = secondaryColl.find().sort({_id: 1}).showRecordId().toArray();
|
|
assert.eq(secondaryDocs, expectedDocs, "Secondary documents not as expected after truncate");
|
|
|
|
// Return docs for next iteration
|
|
return expectedDocs;
|
|
}
|
|
|
|
// Insert 100 documents
|
|
const numToInsert = 100;
|
|
setup(numToInsert);
|
|
const docs = coll.find().sort({_id: 1}).showRecordId().toArray();
|
|
assert.eq(docs.length, numToInsert, `Unexpected number of documents after insert: ${tojson(docs)}`);
|
|
|
|
// Truncate the front
|
|
let docsAfterTest = doTest(0, 10, docs, docs);
|
|
// Truncate the middle
|
|
docsAfterTest = doTest(50, 60, docs, docsAfterTest);
|
|
// Truncate the end
|
|
docsAfterTest = doTest(90, 99, docs, docsAfterTest);
|
|
// Truncate everything
|
|
docsAfterTest = doTest(0, 99, docs, docsAfterTest);
|
|
// Truncate again
|
|
docsAfterTest = doTest(0, 99, docs, docsAfterTest);
|
|
assert.eq(docsAfterTest.length, 0);
|
|
|
|
rst.stopSet();
|