summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Hirschhorn <max.hirschhorn@mongodb.com>2017-04-19 17:09:07 -0400
committerMax Hirschhorn <max.hirschhorn@mongodb.com>2017-04-19 17:09:07 -0400
commita08c37500816cae71a366570d8caebf157887f63 (patch)
tree9f320285e5262a5588b5c79e11591370600af163
parent71e41bc4935c8225ba14413900fcd69394b674da (diff)
downloadmongo-a08c37500816cae71a366570d8caebf157887f63.tar.gz
SERVER-26741 Retain temp collections when node restarted w/o --replSet.
Fixes an issue where temporary collections would be dropped after a replica set member was restarted as a stand-alone mongod. (cherry picked from commit 43e9c303c08f73b56490b662b3d11988cafafdf4)
-rw-r--r--jstests/replsets/temp_namespace_restart_as_standalone.js87
-rw-r--r--src/mongo/db/db.cpp13
2 files changed, 96 insertions, 4 deletions
diff --git a/jstests/replsets/temp_namespace_restart_as_standalone.js b/jstests/replsets/temp_namespace_restart_as_standalone.js
new file mode 100644
index 00000000000..063b1f3bbf4
--- /dev/null
+++ b/jstests/replsets/temp_namespace_restart_as_standalone.js
@@ -0,0 +1,87 @@
+/**
+ * Tests that temporary collections are not dropped when a member of a replica set is started up as
+ * a stand-alone mongod, i.e. without the --replSet parameter.
+ *
+ * @tags: [requires_persistence]
+ */
+(function() {
+ var rst = new ReplSetTest({nodes: 2});
+ rst.startSet();
+
+ // Rig the election so that the first node becomes the primary and remains primary despite the
+ // secondary being terminated during this test.
+ var replSetConfig = rst.getReplSetConfig();
+ replSetConfig.members[1].priority = 0;
+ replSetConfig.members[1].votes = 0;
+ rst.initiate(replSetConfig);
+
+ var primaryConn = rst.getPrimary();
+ var secondaryConn = rst.getSecondary();
+
+ var primaryDB = primaryConn.getDB("test");
+ var secondaryDB = secondaryConn.getDB("test");
+
+ // Create a temporary collection and wait until the operation has replicated to the secondary.
+ assert.commandWorked(primaryDB.runCommand({
+ create: "temp_collection",
+ temp: true,
+ }));
+
+ // Verify that the temporary collection exists on the primary and has temp=true.
+ var primaryCollectionInfos = primaryDB.getCollectionInfos({name: "temp_collection"});
+ assert.eq(1, primaryCollectionInfos.length, "'temp_collection' wasn't created on the primary");
+ assert.eq("temp_collection",
+ primaryCollectionInfos[0].name,
+ "'temp_collection' wasn't created on the primary");
+ assert.eq(true,
+ primaryCollectionInfos[0].options.temp,
+ "'temp_collection' wasn't created as temporary on the primary: " +
+ tojson(primaryCollectionInfos[0].options));
+
+ rst.awaitReplication();
+
+ // Verify that the temporary collection exists on the secondary and has temp=true.
+ var secondaryCollectionInfos = secondaryDB.getCollectionInfos({name: "temp_collection"});
+ assert.eq(
+ 1, secondaryCollectionInfos.length, "'temp_collection' wasn't created on the secondary");
+ assert.eq("temp_collection",
+ secondaryCollectionInfos[0].name,
+ "'temp_collection' wasn't created on the secondary");
+ assert.eq(true,
+ secondaryCollectionInfos[0].options.temp,
+ "'temp_collection' wasn't created as temporary on the secondary: " +
+ tojson(secondaryCollectionInfos[0].options));
+
+ // Shut down the secondary and restart it as a stand-alone mongod.
+ var secondaryNodeId = rst.getNodeId(secondaryDB.getMongo());
+ rst.stop(secondaryNodeId);
+
+ secondaryConn = MongoRunner.runMongod({dbpath: secondaryConn.dbpath, noCleanData: true});
+ assert.neq(null, secondaryConn, "secondary failed to start up as a stand-alone mongod");
+ secondaryDB = secondaryConn.getDB("test");
+
+ // Verify that the temporary collection still exists on the secondary and has temp=true.
+ secondaryCollectionInfos = secondaryDB.getCollectionInfos({name: "temp_collection"});
+ assert.eq(1,
+ secondaryCollectionInfos.length,
+ "'temp_collection' was dropped after restarting the secondary as a stand-alone");
+ assert.eq("temp_collection",
+ secondaryCollectionInfos[0].name,
+ "'temp_collection' was dropped after restarting the secondary as a stand-alone");
+ assert.eq(true,
+ secondaryCollectionInfos[0].options.temp,
+ "'temp_collection' is no longer temporary after restarting the secondary as a" +
+ " stand-alone: " + tojson(secondaryCollectionInfos[0].options));
+
+ // Shut down the secondary and restart it as a member of the replica set.
+ MongoRunner.stopMongod(secondaryConn);
+
+ var restart = true;
+ rst.start(secondaryNodeId, {}, restart);
+
+ // Verify that writes are replicated to the temporary collection and can successfully be applied
+ // by the secondary after having restarted it.
+ assert.writeOK(primaryDB.temp_collection.insert({}, {writeConcern: {w: 2, wtimeout: 60000}}));
+
+ rst.stopSet();
+})();
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index f5346915216..6b0dda65150 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -152,6 +152,7 @@ extern int diagLogging;
namespace {
const NamespaceString startupLogCollectionName("local.startup_log");
+const NamespaceString kSystemReplSetCollection("local.system.replset");
#ifdef _WIN32
ntservice::NtServiceDefaultStrings defaultServiceStrings = {
@@ -296,12 +297,9 @@ void checkForIdIndexes(OperationContext* txn, Database* db) {
* --replset.
*/
unsigned long long checkIfReplMissingFromCommandLine(OperationContext* txn) {
- // This is helpful for the query below to work as you can't open files when readlocked
- ScopedTransaction transaction(txn, MODE_X);
- Lock::GlobalWrite lk(txn->lockState());
if (!repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) {
DBDirectClient c(txn);
- return c.count("local.system.replset");
+ return c.count(kSystemReplSetCollection.ns());
}
return 0;
}
@@ -414,6 +412,13 @@ void repairDatabasesAndCheckVersion(OperationContext* txn) {
const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings();
+ // We open the "local" database before calling checkIfReplMissingFromCommandLine() to ensure the
+ // in-memory catalog entries for the 'kSystemReplSetCollection' collection have been populated
+ // if the collection exists. If the "local" database didn't exist at this point yet, then it
+ // will be created.
+ Lock::DBLock dbLock(txn->lockState(), kSystemReplSetCollection.db(), MODE_X);
+ dbHolder().openDb(txn, kSystemReplSetCollection.db());
+
// On replica set members we only clear temp collections on DBs other than "local" during
// promotion to primary. On pure slaves, they are only cleared when the oplog tells them
// to. The local DB is special because it is not replicated. See SERVER-10927 for more