summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Hirschhorn <max.hirschhorn@mongodb.com>2015-07-07 17:36:31 -0400
committerRamon Fernandez <ramon.fernandez@mongodb.com>2015-09-25 11:29:36 -0400
commit8612f5af228ea853087a82453b14b81c629afb30 (patch)
treecd1324ee35444ad33b458e1b49ce129092f05a29
parent6bb726540cde2cd0942bf3c9b08bea52355afbef (diff)
downloadmongo-8612f5af228ea853087a82453b14b81c629afb30.tar.gz
SERVER-18250 Add tests for toggling between --journal and --nojournal.
(cherry picked from commit 87201c5db22901f103dc5e1de1dc3a67aab36257)
-rw-r--r--jstests/noPassthrough/wt_nojournal_skip_recovery.js91
-rw-r--r--jstests/noPassthrough/wt_nojournal_toggle.js113
2 files changed, 204 insertions, 0 deletions
diff --git a/jstests/noPassthrough/wt_nojournal_skip_recovery.js b/jstests/noPassthrough/wt_nojournal_skip_recovery.js
new file mode 100644
index 00000000000..e742c2eabf9
--- /dev/null
+++ b/jstests/noPassthrough/wt_nojournal_skip_recovery.js
@@ -0,0 +1,91 @@
+/**
+ * Tests that having journaled write operations since the last checkpoint triggers an error when
+ * --wiredTigerEngineConfigString log=(recover=error) is specified in combination with --nojournal.
+ * Also verifies that deleting the journal/ directory allows those operations to safely be ignored.
+ */
+(function() {
+ 'use strict';
+
+ // Skip this test if not running with the "wiredTiger" storage engine.
+ if (jsTest.options().storageEngine && jsTest.options().storageEngine !== 'wiredTiger') {
+ jsTest.log('Skipping test because storageEngine is not "wiredTiger"');
+ return;
+ }
+
+ var dbpath = MongoRunner.dataPath + 'wt_nojournal_skip_recovery';
+ resetDbpath(dbpath);
+
+ // Start a mongod with journaling enabled.
+ var conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ journal: '',
+ // Wait an hour between checkpoints to ensure one isn't created after the fsync command is
+ // executed and before the mongod is terminated. This is necessary to ensure that exactly 90
+ // documents with the 'journaled' field exist in the collection.
+ wiredTigerEngineConfigString: 'checkpoint=(wait=3600)'
+ });
+ assert.neq(null, conn, 'mongod was unable to start up');
+
+ // Execute unjournaled inserts, but periodically do a journaled insert. Triggers a checkpoint
+ // prior to the mongod being terminated.
+ var awaitShell = startParallelShell(function() {
+ for (var iter = 1; iter <= 1000; ++iter) {
+ var bulk = db.nojournal.initializeUnorderedBulkOp();
+ for (var i = 0; i < 100; ++i) {
+ bulk.insert({unjournaled: i});
+ }
+ assert.writeOK(bulk.execute({j: false}));
+ assert.writeOK(db.nojournal.insert({journaled: iter}, {writeConcern: {j: true}}));
+
+ // Create a checkpoint slightly before the mongod is terminated.
+ if (iter === 90) {
+ assert.commandWorked(db.adminCommand({fsync: 1}));
+ }
+ }
+ }, conn.port);
+
+ // After some journaled write operations have been performed against the mongod, send a SIGKILL
+ // to the process to trigger an unclean shutdown.
+ assert.soon(function() {
+ var count = conn.getDB('test').nojournal.count({journaled: {$exists: true}});
+ if (count >= 100) {
+ MongoRunner.stopMongod(conn, 9);
+ return true;
+ }
+ return false;
+ }, 'the parallel shell did not perform at least 100 journaled inserts');
+
+ var exitCode = awaitShell({checkExitSuccess: false});
+ assert.neq(0, exitCode, 'expected shell to exit abnormally due to mongod being terminated');
+
+ // Restart the mongod with journaling disabled, but configure it to error if the database needs
+ // recovery.
+ conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ nojournal: '',
+ wiredTigerEngineConfigString: 'log=(recover=error)',
+ });
+ assert.eq(null, conn, 'mongod should not have started up because it requires recovery');
+
+ // Remove the journal files.
+ assert(removeFile(dbpath + '/journal'), 'failed to remove the journal directory');
+
+ // Restart the mongod with journaling disabled again.
+ conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ nojournal: '',
+ wiredTigerEngineConfigString: 'log=(recover=error)',
+ });
+ assert.neq(null, conn, 'mongod was unable to start up after removing the journal directory');
+
+ var count = conn.getDB('test').nojournal.count({journaled: {$exists: true}});
+ assert.lte(90, count, 'missing documents that were present in the last checkpoint');
+ assert.gte(90, count,
+ 'journaled write operations since the last checkpoint should not have been' +
+ ' replayed');
+
+ MongoRunner.stopMongod(conn);
+})();
diff --git a/jstests/noPassthrough/wt_nojournal_toggle.js b/jstests/noPassthrough/wt_nojournal_toggle.js
new file mode 100644
index 00000000000..60cada8b484
--- /dev/null
+++ b/jstests/noPassthrough/wt_nojournal_toggle.js
@@ -0,0 +1,113 @@
+/**
+ * Tests that journaled write operations that have occurred since the last checkpoint are replayed
+ * when the mongod is killed and restarted with --nojournal.
+ */
+(function() {
+ 'use strict';
+
+ // Skip this test if not running with the "wiredTiger" storage engine.
+ if (jsTest.options().storageEngine && jsTest.options().storageEngine !== 'wiredTiger') {
+ jsTest.log('Skipping test because storageEngine is not "wiredTiger"');
+ return;
+ }
+
+ // Returns a function that primarily executes unjournaled inserts, but periodically does a
+ // journaled insert. If 'checkpoint' is true, then the fsync command is run to create a
+ // checkpoint prior to the mongod being terminated.
+ function insertFunctionFactory(checkpoint) {
+ var insertFunction = function() {
+ for (var iter = 0; iter < 1000; ++iter) {
+ var bulk = db.nojournal.initializeUnorderedBulkOp();
+ for (var i = 0; i < 100; ++i) {
+ bulk.insert({unjournaled: i});
+ }
+ assert.writeOK(bulk.execute({j: false}));
+ assert.writeOK(db.nojournal.insert({journaled: iter}, {writeConcern: {j: true}}));
+ if (__checkpoint_template_placeholder__ && iter === 50) {
+ assert.commandWorked(db.adminCommand({fsync: 1}));
+ }
+ }
+ };
+
+ return '(' + insertFunction.toString().replace('__checkpoint_template_placeholder__',
+ checkpoint.toString()) +
+ ')();';
+ }
+
+ function runTest(options) {
+ var dbpath = MongoRunner.dataPath + 'wt_nojournal_toggle';
+ resetDbpath(dbpath);
+
+ // Start a mongod with journaling enabled.
+ var conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ journal: '',
+ });
+ assert.neq(null, conn, 'mongod was unable to start up');
+
+ // Run a mixture of journaled and unjournaled write operations against the mongod.
+ var awaitShell = startParallelShell(insertFunctionFactory(options.checkpoint), conn.port);
+
+ // After some journaled write operations have been performed against the mongod, send a
+ // SIGKILL to the process to trigger an unclean shutdown.
+ assert.soon(function() {
+ var count = conn.getDB('test').nojournal.count({journaled: {$exists: true}});
+ if (count >= 100) {
+ MongoRunner.stopMongod(conn, 9);
+ return true;
+ }
+ return false;
+ }, 'the parallel shell did not perform at least 100 journaled inserts');
+
+ var exitCode = awaitShell({checkExitSuccess: false});
+ assert.neq(0, exitCode, 'expected shell to exit abnormally due to mongod being terminated');
+
+ // Restart the mongod with journaling disabled.
+ conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ nojournal: '',
+ });
+ assert.neq(null, conn, 'mongod was unable to restart after receiving a SIGKILL');
+
+ var testDB = conn.getDB('test');
+ assert.lte(100, testDB.nojournal.count({journaled: {$exists: true}}),
+ 'journaled write operations since the last checkpoint were not replayed');
+
+ var initialNumLogWrites = testDB.serverStatus().wiredTiger.log['log write operations'];
+ assert.writeOK(testDB.nojournal.insert({a: 1}, {writeConcern: {fsync: true}}));
+ assert.eq(initialNumLogWrites, testDB.serverStatus().wiredTiger.log['log write operations'],
+ 'journaling is still enabled even though --nojournal was specified');
+
+ MongoRunner.stopMongod(conn);
+
+ // Restart the mongod with journaling enabled.
+ conn = MongoRunner.runMongod({
+ dbpath: dbpath,
+ noCleanData: true,
+ journal: '',
+ });
+ assert.neq(null, conn, 'mongod was unable to start up after re-enabling journaling');
+
+ // Change the database object to connect to the restarted mongod.
+ testDB = conn.getDB('test');
+ initialNumLogWrites = testDB.serverStatus().wiredTiger.log['log write operations'];
+
+ assert.writeOK(testDB.nojournal.insert({a: 1}, {writeConcern: {fsync: true}}));
+ assert.lt(initialNumLogWrites, testDB.serverStatus().wiredTiger.log['log write operations'],
+ 'journaling is still disabled even though --journal was specified');
+
+ MongoRunner.stopMongod(conn);
+ }
+
+ // Operations from the journal should be replayed even when the mongod is terminated before
+ // anything is written to disk.
+ jsTest.log('Running the test without ever creating a checkpoint');
+ runTest({checkpoint: false});
+
+ // Repeat the test again, but ensure that some data is written to disk before the mongod is
+ // terminated.
+ jsTest.log('Creating a checkpoint part-way through running the test');
+ runTest({checkpoint: true});
+})();