summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@mongodb.com>2020-07-08 15:56:16 -0400
committerDianna Hohensee <dianna.hohensee@mongodb.com>2020-07-09 20:37:24 -0400
commit678f6f9df2d72db7060d4fff412886298f7a97af (patch)
treedf1720dccb69b87ce7890fd4598a61e15bae773a
parent1be7ba53b01be6d44e133e3e0f0ecc242628eb19 (diff)
downloadmongo-678f6f9df2d72db7060d4fff412886298f7a97af.tar.gz
SERVER-49366 Allow presence of 'recordPreImages' in collection metadata in standalone mode
(cherry picked from commit bf3b9a1e6d52dddbb9ed85c113d613ffbc866e13)
-rw-r--r--jstests/noPassthrough/recordPreImages_standalone_mode.js144
-rw-r--r--jstests/noPassthrough/record_preimage_startup_validation.js9
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp6
3 files changed, 144 insertions, 15 deletions
diff --git a/jstests/noPassthrough/recordPreImages_standalone_mode.js b/jstests/noPassthrough/recordPreImages_standalone_mode.js
new file mode 100644
index 00000000000..26d32c84e45
--- /dev/null
+++ b/jstests/noPassthrough/recordPreImages_standalone_mode.js
@@ -0,0 +1,144 @@
+/**
+ * Test that standalones are able to startup with 'recordPreImages' set in collection metadata; and
+ * that 'recordPreImages' is inactive in standalone mode.
+ *
+ * @tags: [
+ * # Servers are restarted in this test and the data must be retained.
+ * requires_persistence,
+ * # This test uses a replica set and must avoid replica set incompatible test suites, like the
+ * # test suite that turns journaling off.
+ * requires_replication,
+ * ]
+ */
+
+(function() {
+'use strict';
+
+/**
+ * Fetch the collection information on database 'nodeDB' for collection 'collName'. Expects the
+ * collection to exist.
+ */
+const findCollectionInfo = function(nodeDB, collName) {
+ let collInfos = nodeDB.getCollectionInfos();
+ assert.gt(collInfos.length, 0, "The database is empty");
+
+ let collInfo = collInfos.filter(function(z) {
+ return z.name == collName;
+ });
+
+ assert.eq(collInfo.length, 1);
+ return collInfo[0];
+};
+
+/**
+ * Prints out all of the oplog collection entries on 'node'.
+ */
+function printOplog(node) {
+ let cursor = node.getDB('local').oplog.rs.find();
+ while (cursor.hasNext()) {
+ jsTest.log("Oplog entry: " + tojson(cursor.next()));
+ }
+}
+
+/**
+ * A --replSet server should be able to set 'recordPreImages' on a collection and then be restarted
+ * in standalone mode successfully.
+ */
+
+jsTest.log("Starting up a 1-node replica set");
+
+var rst = new ReplSetTest({nodes: 1});
+rst.startSet();
+rst.initiate();
+
+const dbName = 'record_preimage_standalone_mode_test_db';
+const collName = 'testColl';
+let primary = rst.getPrimary();
+let testDB = primary.getDB(dbName);
+let testColl = testDB.getCollection(collName);
+
+jsTest.log("Creating a collection with 'recordPreImages' set to true and adding some data");
+
+assert.commandWorked(testDB.runCommand({create: collName, recordPreImages: true}));
+assert.eq(findCollectionInfo(testDB, collName).options.recordPreImages, true);
+
+assert.commandWorked(testColl.insert({a: 1, b: 1}));
+assert.commandWorked(testColl.update({a: 1}, {a: 2, b: 2}));
+// Ensure all of the writes make it to disk before checkpointing below.
+assert.commandWorked(testColl.update({a: 2}, {a: 3, b: 3}, {writeConcern: {w: 1, j: true}}));
+
+jsTest.log("Forcing a checkpoint to be taken");
+
+// Ensure that the standalone can recover all of the writes from the last checkpoint because
+// standalone mode does not run recovery from the oplog. The last write with j:true write concern
+// ensured that the data reached disk, and now fsync will checkpoint that data.
+assert.commandWorked(primary.adminCommand({fsync: 1}));
+
+jsTest.log("Restarting the replica set member as a standalone node");
+
+printOplog(primary); // Debugging aid.
+
+let replicaSetNodeId = rst.getNodeId(primary);
+let replicaSetNodeDbpath = primary.dbpath;
+jsTest.log("replicaSetNodeId: " + replicaSetNodeId +
+ ", replicaSetNodeDbpath: " + replicaSetNodeDbpath);
+
+rst.stop(replicaSetNodeId);
+
+let standaloneConn = MongoRunner.runMongod({
+ dbpath: replicaSetNodeDbpath,
+ noCleanData: true,
+});
+
+let standaloneDB = standaloneConn.getDB(dbName);
+let standaloneColl = standaloneDB.getCollection(collName);
+let standaloneOplogColl = standaloneConn.getDB('local').oplog.rs;
+
+assert.eq(findCollectionInfo(standaloneDB, collName).options.recordPreImages, true);
+
+/**
+ * A standalone mode server should be able to do writes without triggering the 'recordPreImages'
+ * feature because oplog entries are not written in standalone mode: the 'recordPreImages' setting
+ * causes additional oplog entries to be written.
+ */
+
+const numOplogEntriesBefore = standaloneOplogColl.find().itcount();
+
+jsTest.log(
+ "Updating some data in the collection with 'recordPreImages' set to check that nothing " +
+ "happens in standalone mode");
+
+assert.commandWorked(standaloneColl.insert({c: 1, d: 1}));
+assert.commandWorked(standaloneColl.update({c: 1}, {c: 2, d: 2}));
+assert.commandWorked(standaloneColl.update({c: 2}, {c: 3, d: 3}));
+
+jsTest.log(
+ "Checking that no oplog entries were produced for 'recordPreImages': the feature is inactive");
+
+printOplog(standaloneConn); // Debugging aid.
+
+const numOplogEntriesAfter = standaloneOplogColl.find().itcount();
+assert.eq(numOplogEntriesBefore, numOplogEntriesAfter);
+
+jsTest.log("Shutting down standalone");
+
+MongoRunner.stopMongod(standaloneConn);
+
+jsTest.log("Restarting the node as a replica set member again and doing some writes");
+
+rst.start(replicaSetNodeId, {}, true /*restart*/);
+
+primary = rst.getPrimary();
+testDB = primary.getDB(dbName);
+testColl = testDB.getCollection(collName);
+
+// Check that everything is still working properly after being in standalone mode.
+assert.eq(findCollectionInfo(testDB, collName).options.recordPreImages, true);
+
+assert.commandWorked(testColl.update({a: 3}, {a: 4, b: 4}));
+assert.commandWorked(testColl.update({a: 4}, {a: 5, b: 5}));
+
+jsTest.log("Shutting down replica set");
+
+rst.stopSet();
+}());
diff --git a/jstests/noPassthrough/record_preimage_startup_validation.js b/jstests/noPassthrough/record_preimage_startup_validation.js
index f9f3f16b23f..39cee347c02 100644
--- a/jstests/noPassthrough/record_preimage_startup_validation.js
+++ b/jstests/noPassthrough/record_preimage_startup_validation.js
@@ -8,15 +8,6 @@
'use strict';
/**
- * Test that a standalone cannot record pre-images.
- */
-
-let conn = MongoRunner.runMongod({});
-assert.commandFailedWithCode(conn.getDB("test").runCommand({create: "test", recordPreImages: true}),
- ErrorCodes.InvalidOptions);
-MongoRunner.stopMongod(conn);
-
-/**
* Find the collection information on database 'nodeDB' for collection 'collName'.
*/
const findCollectionInfo = function(nodeDB, collName) {
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index 0e02b848366..5071257bef0 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -238,12 +238,6 @@ Status validatePreImageRecording(OperationContext* opCtx, const NamespaceString&
"recordPreImages collection option is not supported on shards or config servers"};
}
- auto replCoord = repl::ReplicationCoordinator::get(opCtx);
- if (!replCoord->isReplEnabled()) {
- return {ErrorCodes::InvalidOptions,
- "recordPreImages collection option depends on being in a replica set"};
- }
-
return Status::OK();
}