diff options
| author | clarissecheah <65272339+clarissecheah@users.noreply.github.com> | 2024-09-06 00:23:45 +1000 |
|---|---|---|
| committer | MongoDB Bot <mongo-bot@mongodb.com> | 2024-09-05 15:10:59 +0000 |
| commit | 489dd5a994faf69f600684cc98acd6e5e5c74e91 (patch) | |
| tree | 82b92d31f0a21aa5eb563c908e4c6c2a03cfe02f /jstests | |
| parent | 3f530e5e26903b16233b0bcd03465e80aae46e21 (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.js | 86 |
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(); |
