diff options
-rw-r--r-- | jstests/replsets/get_more_before_initiate.js | 36 | ||||
-rw-r--r-- | src/mongo/db/commands/getmore_cmd.cpp | 6 |
2 files changed, 40 insertions, 2 deletions
diff --git a/jstests/replsets/get_more_before_initiate.js b/jstests/replsets/get_more_before_initiate.js new file mode 100644 index 00000000000..67d9013df9a --- /dev/null +++ b/jstests/replsets/get_more_before_initiate.js @@ -0,0 +1,36 @@ +/** + * SERVER-46365 In MongoDB v4.0, getMore commands check the featureCompatibilityVersion, but the + * featureCompatibiltyVersion does not get initialized in a replica set member until the replica set + * is initialized. The getMore command must not crash when it sees an uninitialized + * featureCompatibilityVersion, because it is possible to send a getMore to an uninitialized replica + * set member: for example, by reading the "local" database. + */ +(function() { + "use strict"; + + const rs = new ReplSetTest({name: "getMoreBeforeInitiateTest", nodes: 1}); + rs.startSet(); + + // Before replica set initialization finishes, members reject getMore commands for any database + // other than the "local" database. + const db = rs.nodes[0].getDB("local"); + const collName = "non_existent_collection"; + + // We use batch size 0 to ensure we get a cursor, even though there is no data in the + // collection. + const aggregateRes = assert.commandWorked( + db.runCommand({aggregate: collName, pipeline: [], cursor: {batchSize: 0}})); + assert(aggregateRes.hasOwnProperty("cursor"), aggregateRes); + + // This getMore command will check the featureCompatibiltyVersion. + const getMoreRes = assert.commandWorked( + db.runCommand({getMore: aggregateRes.cursor.id, collection: collName})); + + // This test is primarily testing that we don't crash, but we may as well also include a sanity + // check that we get back a correct (empty) result and exhausted cursor. + assert(getMoreRes.hasOwnProperty("cursor"), getMoreRes); + assert.eq(getMoreRes.cursor.id, 0, getMoreRes); + assert.eq(getMoreRes.cursor.nextBatch, [], getMoreRes); + + rs.stopSet(); +}());
\ No newline at end of file diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 8bfa36ea286..89d351baf86 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -337,13 +337,15 @@ public: << cursor->nss().ns()); } - if (serverGlobalParams.featureCompatibility.getVersion() == + if (serverGlobalParams.featureCompatibility.getVersionUnsafe() == ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo40) { // Ensure the lsid and txnNumber of the getMore match that of the originating command. // This is important to ensure that transactions are being used correctly, but exposes a // known issue where a 3.6 mongos can send a getMore without the appropriate session id. // To work around the bug on 3.6, we only enforce that the lsid and txnNumber match when - // we've upgraded to FCV 4.0. See SERVER-36212 for more details. + // we've upgraded to FCV 4.0. See SERVER-36212 for more details. Note that it is + // possible to reach this code path before the featureCompatibilityVersion has been + // created, so we must use getVersionUnsafe(). validateLSID(opCtx, request, cursor); validateTxnNumber(opCtx, request, cursor); } |