summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorclarissecheah <65272339+clarissecheah@users.noreply.github.com>2024-09-06 00:23:45 +1000
committerMongoDB Bot <mongo-bot@mongodb.com>2024-09-05 15:10:59 +0000
commit489dd5a994faf69f600684cc98acd6e5e5c74e91 (patch)
tree82b92d31f0a21aa5eb563c908e4c6c2a03cfe02f /jstests
parent3f530e5e26903b16233b0bcd03465e80aae46e21 (diff)
SERVER-94487 collMod refreshes catalog with index entry from older catalog state (#26764)r8.0.0-rc20
GitOrigin-RevId: 09707dd9a1fcd2429d10539a68ae30ce003aa712
Diffstat (limited to 'jstests')
-rw-r--r--jstests/noPassthrough/ttl_invalid_index_fixer_uses_writable_collection.js86
1 files changed, 86 insertions, 0 deletions
diff --git a/jstests/noPassthrough/ttl_invalid_index_fixer_uses_writable_collection.js b/jstests/noPassthrough/ttl_invalid_index_fixer_uses_writable_collection.js
new file mode 100644
index 00000000000..fbd415d7ea6
--- /dev/null
+++ b/jstests/noPassthrough/ttl_invalid_index_fixer_uses_writable_collection.js
@@ -0,0 +1,86 @@
+/**
+ * Reproduces a seg-fault caused by the InvalidTTLIndexFixer trying to 'fix' an invalid TTL index
+ * spec with both a non-int 'expireAfterSeconds' field and an unexpected additional field.
+ * Specifically, the behavior is caused by the additional field being an accepted field for text
+ * indexes, 'weights', but not indexes of other types.
+ *
+ * The original issue occured when trying to upgrade from an older version, so the first steps are
+ * to bypass validation checks and introduce an invalid ttl index spec.
+ *
+ * @tags: [
+ * requires_replication,
+ * ]
+ */
+import {configureFailPoint} from "jstests/libs/fail_point_util.js";
+
+const rst = new ReplSetTest({
+ nodes: [{}, {rsConfig: {votes: 0, priority: 0}}],
+ nodeOptions: {setParameter: {ttlMonitorSleepSecs: 1}},
+});
+rst.startSet();
+rst.initiate();
+
+let primary = rst.getPrimary();
+let secondary = rst.getSecondary();
+const db = primary.getDB('test');
+const expireAfterSecondsNonInt = 100.3;
+let coll = db.t;
+assert.commandWorked(coll.insert({_id: 0, t: ISODate()}));
+
+// Failpoints to circumvent validation when introducing the invalid index. It's possible we don't
+// need all of them. 'skipIndexCreateWeightsFieldValidation' is the most important.
+const fpNames = [
+ 'skipTTLIndexValidationOnCreateIndex',
+ 'skipTTLIndexExpireAfterSecondsValidation',
+ 'skipIndexCreateFieldNameValidation',
+ 'skipIndexCreateWeightsFieldValidation',
+];
+const fps = [];
+for (const fpName of fpNames) {
+ fps.push(configureFailPoint(primary, fpName));
+ fps.push(configureFailPoint(secondary, fpName));
+}
+try {
+ assert.commandWorked(
+ coll.createIndex({t: 1}, {expireAfterSeconds: expireAfterSecondsNonInt, weights: {}}));
+ const catalogContents = coll.aggregate([{$listCatalog: {}}]).toArray();
+ jsTestLog("Catalog contents: " + tojson(catalogContents));
+
+ rst.awaitReplication();
+ rst.awaitLastStableRecoveryTimestamp();
+} finally {
+ for (const fp of fps) {
+ fp.off();
+ }
+}
+
+// When the primary steps back up, we eventually trigger the seg-fault.
+jsTest.log(
+ `Forcing the primary to step down then step up again to trigger 'InvalidTTLIndexFixer' thread`);
+assert.commandWorked(primary.adminCommand({replSetStepDown: 5, force: true}));
+primary = rst.waitForPrimary();
+
+coll = primary.getDB(db.getName()).getCollection(coll.getName());
+jsTestLog("Catalog contents on primary: " + tojson(coll.aggregate([{$listCatalog: {}}]).toArray()));
+
+// Ensure the 'InvalidTTLIndexFixer' thread has time to run.
+assert.soon(
+ () => {
+ return 1 ==
+ rst.findOplog(primary,
+ {
+ op: 'c',
+ ns: coll.getDB().getCollection('$cmd').getFullName(),
+ 'o.collMod': coll.getName(),
+ 'o.index.name': 't_1',
+ 'o.index.expireAfterSeconds': Math.floor(expireAfterSecondsNonInt),
+ },
+ /*limit=*/ 1)
+ .toArray()
+ .length;
+ },
+ 'TTL index with ' + expireAfterSecondsNonInt +
+ ' expireAfterSeconds was not fixed using collMod during step-up: ' +
+ tojson(rst.findOplog(primary, {op: {$ne: 'n'}}, /*limit=*/ 10).toArray()));
+rst.awaitReplication();
+rst.stopSet();