summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Seyster <justin.seyster@mongodb.com>2020-03-06 16:02:53 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-03-09 16:28:39 +0000
commit0bc918c73390f6e4d6349660e4cd233f5900b69a (patch)
tree62a708fa49694f96f8a6c2fbb4c19d2b789ea75d
parent25d38642ed3beb47fd731e405f197ca6de820d6e (diff)
downloadmongo-r4.0.17-rc0.tar.gz
SERVER-46365 Do not trip invariant on FCV check in getMorer4.0.17-rc0r4.0.17
-rw-r--r--jstests/replsets/get_more_before_initiate.js36
-rw-r--r--src/mongo/db/commands/getmore_cmd.cpp6
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);
}