diff options
author | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2015-07-07 17:36:31 -0400 |
---|---|---|
committer | Ramon Fernandez <ramon.fernandez@mongodb.com> | 2015-09-25 11:29:36 -0400 |
commit | 8612f5af228ea853087a82453b14b81c629afb30 (patch) | |
tree | cd1324ee35444ad33b458e1b49ce129092f05a29 | |
parent | 6bb726540cde2cd0942bf3c9b08bea52355afbef (diff) | |
download | mongo-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.js | 91 | ||||
-rw-r--r-- | jstests/noPassthrough/wt_nojournal_toggle.js | 113 |
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}); +})(); |