summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDianna Hohensee <dianna.hohensee@mongodb.com>2020-07-08 15:56:16 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-07-09 20:16:42 +0000
commitbf3b9a1e6d52dddbb9ed85c113d613ffbc866e13 (patch)
tree25bbc1e3b100d08b01149a326befdb5b18a81774
parent64b48df7ee020d6ac68aaeda4523bfccf0d5b7cd (diff)
downloadmongo-bf3b9a1e6d52dddbb9ed85c113d613ffbc866e13.tar.gz
SERVER-49366 Allow presence of 'recordPreImages' in collection metadata in standalone mode
-rw-r--r--jstests/noPassthrough/recordPreImages_in_create_and_collmod.js54
-rw-r--r--jstests/noPassthrough/recordPreImages_standalone_mode.js144
-rw-r--r--jstests/noPassthrough/record_preimage_startup_validation.js68
-rw-r--r--src/mongo/db/catalog/collection_impl.cpp6
4 files changed, 198 insertions, 74 deletions
diff --git a/jstests/noPassthrough/recordPreImages_in_create_and_collmod.js b/jstests/noPassthrough/recordPreImages_in_create_and_collmod.js
new file mode 100644
index 00000000000..4807da95268
--- /dev/null
+++ b/jstests/noPassthrough/recordPreImages_in_create_and_collmod.js
@@ -0,0 +1,54 @@
+/*
+ * Tests the 'recordPreImage' flag is settable via the collMode and create commands. Also tests that
+ * this flag cannot be set on collections in the 'local' or 'admin' databases.
+ *
+ * @tags: [requires_replication]
+ */
+(function() {
+'use strict';
+
+const findCollectionInfo = function(collName) {
+ var all = testDB.getCollectionInfos();
+ if (all.length == 0) {
+ return {};
+ }
+ all = all.filter(function(z) {
+ return z.name == collName;
+ });
+ assert.eq(all.length, 1);
+ return all[0];
+};
+
+let rsTest = new ReplSetTest({nodes: 1});
+rsTest.startSet();
+rsTest.initiate();
+
+const dbName = 'testDB';
+const collName = 'recordPreImageColl';
+const collName2 = 'recordPreImageColl2';
+
+let primary = rsTest.getPrimary();
+let adminDB = primary.getDB("admin");
+let localDB = primary.getDB("local");
+let testDB = primary.getDB(dbName);
+
+// Check that we cannot set recordPreImages on the local or admin databases.
+assert.commandFailedWithCode(adminDB.runCommand({create: collName, recordPreImages: true}),
+ ErrorCodes.InvalidOptions);
+assert.commandFailedWithCode(localDB.runCommand({create: collName, recordPreImages: true}),
+ ErrorCodes.InvalidOptions);
+
+// We should be able to set the recordPreImages flag via create or collMod.
+assert.commandWorked(testDB.runCommand({create: collName, recordPreImages: true}));
+assert.eq(findCollectionInfo(collName).options.recordPreImages, true);
+
+assert.commandWorked(testDB.runCommand({create: collName2}));
+assert.commandWorked(testDB.runCommand({collMod: collName2, recordPreImages: true}));
+assert.eq(findCollectionInfo(collName2).options.recordPreImages, true);
+
+// Test that the recordPreImages flag can be unset successfully using the 'collMod' command.
+assert.commandWorked(testDB.runCommand({collMod: collName, recordPreImages: false}));
+assert.eq(findCollectionInfo(collName).options, {});
+
+rsTest.stopSet();
+}());
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
deleted file mode 100644
index 3e9804d0303..00000000000
--- a/jstests/noPassthrough/record_preimage_startup_validation.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * This test validates that we accept the 'recordPreImage' flag via the collMode and create commands
- * only if the node is a member of a replica set that is not a shard/config server. Also tests that
- * this flag cannot be set on collections in the 'local' or 'admin' databases.
- *
- * @tags: [requires_replication, requires_persistence]
- */
-(function() {
-'use strict';
-
-// Start a mongod that's not in a replica set
-let conn = MongoRunner.runMongod({});
-
-let testDB = conn.getDB("test");
-
-const findCollectionInfo = function(collName) {
- var all = testDB.getCollectionInfos();
- if (all.length == 0) {
- return {};
- }
- all = all.filter(function(z) {
- return z.name == collName;
- });
- assert.eq(all.length, 1);
- return all[0];
-};
-
-// Check that we cannot record pre-images on a standalone.
-assert.commandFailedWithCode(testDB.runCommand({create: "test", recordPreImages: true}),
- ErrorCodes.InvalidOptions);
-// Check that failing to set the option doesn't accidentally set it anyways.
-assert.eq(findCollectionInfo("test").options, undefined);
-
-MongoRunner.stopMongod(conn);
-
-// Start a 1-node repl set to be used for the rest of the test
-let rsTest = new ReplSetTest({nodes: 1});
-rsTest.startSet();
-rsTest.initiate();
-
-// Check that we cannot set recordPreImages on the local or admin databases.
-let adminDB = rsTest.getPrimary().getDB("admin");
-assert.commandFailedWithCode(adminDB.runCommand({create: "preimagecoll", recordPreImages: true}),
- ErrorCodes.InvalidOptions);
-let localDB = rsTest.getPrimary().getDB("local");
-assert.commandFailedWithCode(localDB.runCommand({create: "preimagecoll", recordPreImages: true}),
- ErrorCodes.InvalidOptions);
-
-testDB = rsTest.getPrimary().getDB("test");
-
-// Check the positive test cases. We should be able to set this flag via create or collMod.
-assert.commandWorked(testDB.runCommand({create: "test", recordPreImages: true}));
-assert.eq(findCollectionInfo("test").options.recordPreImages, true);
-
-assert.commandWorked(testDB.runCommand({create: "test2"}));
-assert.commandWorked(testDB.runCommand({collMod: "test2", recordPreImages: true}));
-assert.eq(findCollectionInfo("test2").options.recordPreImages, true);
-
-// Test that the flag can be unset successfully using the 'collMod' command.
-assert.commandWorked(testDB.runCommand({collMod: "test", recordPreImages: false}));
-assert.eq(findCollectionInfo("test").options, {});
-
-// Re-enable the flag and test that the replica set node can restart successfully.
-assert.commandWorked(testDB.runCommand({collMod: "test", recordPreImages: true}));
-rsTest.restart(rsTest.getPrimary());
-
-rsTest.stopSet();
-}());
diff --git a/src/mongo/db/catalog/collection_impl.cpp b/src/mongo/db/catalog/collection_impl.cpp
index 39a0ef9af1e..523edfe2718 100644
--- a/src/mongo/db/catalog/collection_impl.cpp
+++ b/src/mongo/db/catalog/collection_impl.cpp
@@ -230,12 +230,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();
}