diff options
-rw-r--r-- | jstests/auth/lib/commands_lib.js | 16 | ||||
-rw-r--r-- | jstests/core/fsync.js | 11 | ||||
-rw-r--r-- | jstests/noPassthroughWithMongod/fsync2.js | 2 | ||||
-rw-r--r-- | jstests/repl/snapshot1.js | 4 | ||||
-rw-r--r-- | jstests/replsets/fsync_lock_read_secondaries.js | 2 | ||||
-rw-r--r-- | jstests/replsets/maxSyncSourceLagSecs.js | 2 | ||||
-rw-r--r-- | jstests/replsets/stepdown.js | 2 | ||||
-rw-r--r-- | jstests/replsets/stepdown3.js | 2 | ||||
-rw-r--r-- | src/mongo/db/commands/fsync.cpp | 163 | ||||
-rw-r--r-- | src/mongo/db/commands/fsync.h | 2 | ||||
-rw-r--r-- | src/mongo/db/instance.cpp | 66 | ||||
-rw-r--r-- | src/mongo/shell/db.js | 9 |
12 files changed, 80 insertions, 201 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index e4d5fbed16e..c73439d2494 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -1144,22 +1144,6 @@ var authCommandsLib = { ] }, { - testname: "fsyncUnlock", - command: {fsyncUnlock: 1}, - testcases: [ - { - runOnDb: adminDbName, - roles: roles_hostManager, - privileges: [ - { resource: {cluster: true}, actions: ["fsync"] } - ], - expectFail: true - }, - { runOnDb: firstDbName, roles: {} }, - { runOnDb: secondDbName, roles: {} } - ] - }, - { testname: "geoNear", command: {geoNear: "x", near: [50, 50], num: 1}, setup: function (db) { diff --git a/jstests/core/fsync.js b/jstests/core/fsync.js index 14c5d323591..53ebef0f97d 100644 --- a/jstests/core/fsync.js +++ b/jstests/core/fsync.js @@ -36,14 +36,3 @@ assert.eq(2, fsyncLockDB.coll.count({})); // Ensure eval is not allowed to invoke fsyncLock assert(!db.eval('db.fsyncLock()').ok, "eval('db.fsyncLock()') should fail."); - -// Check that the fsyncUnlock pseudo-command (a lookup on cmd.$sys.unlock) -// still has the same effect as a legitimate 'fsyncUnlock' command -// TODO: remove this in in the release following MongoDB 3.2 when pseudo-commands -// are removed -var fsyncCommandRes = db.fsyncLock(); -assert(fsyncLockRes.ok, "fsyncLock command failed against admin DB"); -assert(db.currentOp().fsyncLock, "Value in db.currentOp incorrect for fsyncLocked server"); -var fsyncPseudoCommandRes = db.getSiblingDB("admin").$cmd.sys.unlock.findOne(); -assert(fsyncPseudoCommandRes.ok, "fsyncUnlock pseudo-command failed"); -assert(db.currentOp().fsyncLock == null, "fsyncUnlock is not null in db.currentOp"); diff --git a/jstests/noPassthroughWithMongod/fsync2.js b/jstests/noPassthroughWithMongod/fsync2.js index fcf4da08533..7080837a99b 100644 --- a/jstests/noPassthroughWithMongod/fsync2.js +++ b/jstests/noPassthroughWithMongod/fsync2.js @@ -40,7 +40,7 @@ function doTest() { // Uncomment once SERVER-4243 is fixed //assert.eq(1, m.getDB(db.getName()).fsync2.count()); - assert( m.getDB("admin").fsyncUnlock().ok ); + assert( m.getDB("admin").$cmd.sys.unlock.findOne().ok ); assert.eq( 2, db.fsync2.count() ); diff --git a/jstests/repl/snapshot1.js b/jstests/repl/snapshot1.js index 076ec2403f9..3be37aa125b 100644 --- a/jstests/repl/snapshot1.js +++ b/jstests/repl/snapshot1.js @@ -14,7 +14,7 @@ for( i = 0; i < 1000; ++i ) m.getDB( "admin" ).runCommand( {fsync:1,lock:1} ); copyDbpath( rt1.getPath( true ), rt1.getPath( false ) ); -m.getDB( "admin" ).fsyncUnlock(); +m.getDB( "admin" ).$cmd.sys.unlock.findOne(); s1 = rt1.start( false, null, true ); assert.eq( 1000, s1.getDB( baseName )[ baseName ].count() ); @@ -23,7 +23,7 @@ assert.soon( function() { return 1001 == s1.getDB( baseName )[ baseName ].count( s1.getDB( "admin" ).runCommand( {fsync:1,lock:1} ); copyDbpath( rt1.getPath( false ), rt2.getPath( false ) ); -s1.getDB( "admin" ).fsyncUnlock(); +s1.getDB( "admin" ).$cmd.sys.unlock.findOne(); s2 = rt2.start( false, null, true ); assert.eq( 1001, s2.getDB( baseName )[ baseName ].count() ); diff --git a/jstests/replsets/fsync_lock_read_secondaries.js b/jstests/replsets/fsync_lock_read_secondaries.js index d217e85241f..7aab61fd4b2 100644 --- a/jstests/replsets/fsync_lock_read_secondaries.js +++ b/jstests/replsets/fsync_lock_read_secondaries.js @@ -53,7 +53,7 @@ for (var i=0; i<docNum; i++) { // this should work just fine. var slave0count = slaves[0].getDB("foo").bar.count(); assert.eq(slave0count, 100, "Doc count in fsync lock wrong. Expected (=100), found " + slave0count); -assert(slaves[0].getDB("admin").fsyncUnlock().ok); +assert(slaves[0].getDB("admin").$cmd.sys.unlock.findOne().ok); // The secondary should have equal or more documents than what it had before. assert.soon(function() { diff --git a/jstests/replsets/maxSyncSourceLagSecs.js b/jstests/replsets/maxSyncSourceLagSecs.js index 1a7348c2e64..8d4702510e1 100644 --- a/jstests/replsets/maxSyncSourceLagSecs.js +++ b/jstests/replsets/maxSyncSourceLagSecs.js @@ -44,6 +44,6 @@ return (slaves[1].getDB("foo").bar.count() === 2); }, "slave should have caught up after syncing to primary."); - assert.commandWorked(slaves[0].getDB("admin").fsyncUnlock()); + assert.commandWorked(slaves[0].getDB("admin").$cmd.sys.unlock.findOne()); replTest.stopSet(); }()); diff --git a/jstests/replsets/stepdown.js b/jstests/replsets/stepdown.js index 275d7726d40..474154ae6ef 100644 --- a/jstests/replsets/stepdown.js +++ b/jstests/replsets/stepdown.js @@ -53,7 +53,7 @@ assert.eq(r2.ismaster, false); assert.eq(r2.secondary, true); print("\nunlock"); -printjson(locked.getDB("admin").fsyncUnlock()); +printjson(locked.getDB("admin").$cmd.sys.unlock.findOne()); print("\nreset stepped down time"); master.getDB("admin").runCommand({replSetFreeze:0}); diff --git a/jstests/replsets/stepdown3.js b/jstests/replsets/stepdown3.js index 05ce573c883..af7f84607b7 100644 --- a/jstests/replsets/stepdown3.js +++ b/jstests/replsets/stepdown3.js @@ -46,5 +46,5 @@ print("result of gle:"); printjson(result); // unlock and shut down -printjson(locked.getDB("admin").fsyncUnlock()); +printjson(locked.getDB("admin").$cmd.sys.unlock.findOne()); replTest.stopSet(); diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index b6fde72e309..f9f829df3b7 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -26,24 +26,16 @@ * it in the license file. */ -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage #include "mongo/db/commands/fsync.h" -#include <iostream> -#include <memory> -#include <sstream> #include <string> #include <vector> -#include "mongo/base/init.h" -#include "mongo/bson/bsonobj.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/db/audit.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" -#include "mongo/db/auth/authorization_session.h" #include "mongo/db/auth/privilege.h" #include "mongo/db/concurrency/d_concurrency.h" #include "mongo/db/commands.h" @@ -51,11 +43,12 @@ #include "mongo/db/storage/mmap_v1/dur.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/db/client.h" +#include "mongo/db/jsobj.h" #include "mongo/db/operation_context_impl.h" -#include "mongo/stdx/memory.h" #include "mongo/util/background.h" #include "mongo/util/log.h" + namespace mongo { using std::endl; @@ -159,73 +152,7 @@ namespace mongo { } return 1; } - }; - - namespace { - bool unlockFsync(); - } // namespace - - class FSyncUnlockCommand : public Command { - public: - - FSyncUnlockCommand() : Command("fsyncUnlock") {} - - bool isWriteCommandForConfigServer() const override { return false; } - - bool slaveOk() const override { return true; } - - bool adminOnly() const override { return true; } - - Status checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) override { - - bool isAuthorized = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), - ActionType::unlock); - - if (isAuthorized) { - audit::logFsyncUnlockAuthzCheck(client, ErrorCodes::OK); - return Status::OK(); - } - else { - audit::logFsyncUnlockAuthzCheck(client, ErrorCodes::Unauthorized); - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - } - - bool run(OperationContext* txn, - const std::string& db, - BSONObj& cmdObj, - int options, - std::string& errmsg, - BSONObjBuilder& result, - bool fromRepl) override { - - log() << "command: unlock requested"; - - if (unlockFsync()) { - result.append("info", "unlock completed"); - return true; - } - else { - errmsg = "not locked"; - return false; - } - } - - }; - - namespace { - std::unique_ptr<FSyncCommand> fsyncCmd; - std::unique_ptr<FSyncUnlockCommand> fsyncUnlockCmd; - } // namespace - - MONGO_INITIALIZER(FSyncAndFsyncUnlock)(InitializerContext*) { - fsyncCmd = stdx::make_unique<FSyncCommand>(); - fsyncUnlockCmd = stdx::make_unique<FSyncUnlockCommand>(); - return Status::OK(); - } + } fsyncCmd; SimpleMutex filesLockedFsync("filesLockedFsync"); @@ -236,17 +163,17 @@ namespace mongo { ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite global(txn.lockState()); // No WriteUnitOfWork needed - SimpleMutex::scoped_lock lk(fsyncCmd->m); - - invariant(!fsyncCmd->locked); // impossible to get here if locked is true - try { + SimpleMutex::scoped_lock lk(fsyncCmd.m); + + invariant(!fsyncCmd.locked); // impossible to get here if locked is true + try { getDur().syncDataAndTruncateJournal(&txn); - } - catch( std::exception& e ) { + } + catch( std::exception& e ) { error() << "error doing syncDataAndTruncateJournal: " << e.what() << endl; - fsyncCmd->err = e.what(); - fsyncCmd->_threadSync.notify_one(); - fsyncCmd->locked = false; + fsyncCmd.err = e.what(); + fsyncCmd._threadSync.notify_one(); + fsyncCmd.locked = false; return; } @@ -256,49 +183,47 @@ namespace mongo { StorageEngine* storageEngine = getGlobalEnvironment()->getGlobalStorageEngine(); storageEngine->flushAllFiles(true); } - catch( std::exception& e ) { + catch( std::exception& e ) { error() << "error doing flushAll: " << e.what() << endl; - fsyncCmd->err = e.what(); - fsyncCmd->_threadSync.notify_one(); - fsyncCmd->locked = false; + fsyncCmd.err = e.what(); + fsyncCmd._threadSync.notify_one(); + fsyncCmd.locked = false; return; } - invariant(!fsyncCmd->locked); - fsyncCmd->locked = true; - - fsyncCmd->_threadSync.notify_one(); + invariant(!fsyncCmd.locked); + fsyncCmd.locked = true; + + fsyncCmd._threadSync.notify_one(); - while ( ! fsyncCmd->pendingUnlock ) { - fsyncCmd->_unlockSync.wait(fsyncCmd->m); + while ( ! fsyncCmd.pendingUnlock ) { + fsyncCmd._unlockSync.wait(fsyncCmd.m); } - fsyncCmd->pendingUnlock = false; + fsyncCmd.pendingUnlock = false; + + fsyncCmd.locked = false; + fsyncCmd.err = "unlocked"; - fsyncCmd->locked = false; - fsyncCmd->err = "unlocked"; - - fsyncCmd->_unlockSync.notify_one(); + fsyncCmd._unlockSync.notify_one(); } - bool lockedForWriting() { - return fsyncCmd->locked; + bool lockedForWriting() { + return fsyncCmd.locked; } - namespace { - // @return true if unlocked - bool unlockFsync() { - SimpleMutex::scoped_lock lk( fsyncCmd->m ); - if( !fsyncCmd->locked ) { - return false; - } - fsyncCmd->pendingUnlock = true; - fsyncCmd->_unlockSync.notify_one(); - fsyncCmd->_threadSync.notify_one(); - - while ( fsyncCmd->locked ) { - fsyncCmd->_unlockSync.wait( fsyncCmd->m ); - } - return true; + // @return true if unlocked + bool _unlockFsync() { + SimpleMutex::scoped_lock lk( fsyncCmd.m ); + if( !fsyncCmd.locked ) { + return false; } - } // namespace + fsyncCmd.pendingUnlock = true; + fsyncCmd._unlockSync.notify_one(); + fsyncCmd._threadSync.notify_one(); + + while ( fsyncCmd.locked ) { + fsyncCmd._unlockSync.wait( fsyncCmd.m ); + } + return true; + } } diff --git a/src/mongo/db/commands/fsync.h b/src/mongo/db/commands/fsync.h index 4072a1f6e50..f3fa2adb993 100644 --- a/src/mongo/db/commands/fsync.h +++ b/src/mongo/db/commands/fsync.h @@ -34,4 +34,4 @@ namespace mongo { // Use this for blocking during an fsync-and-lock extern SimpleMutex filesLockedFsync; bool lockedForWriting(); -} // namespace mongo +} diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 242a81db415..46e0edd4b13 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -180,6 +180,32 @@ namespace mongo { replyToQuery(0, m, dbresponse, obj); } + bool _unlockFsync(); + static void unlockFsync(OperationContext* txn, const char *ns, Message& m, DbResponse &dbresponse) { + BSONObj obj; + + const bool isAuthorized = txn->getClient()->getAuthorizationSession()->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), ActionType::unlock); + audit::logFsyncUnlockAuthzCheck( + txn->getClient(), isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); + if (!isAuthorized) { + obj = fromjson("{\"err\":\"unauthorized\"}"); + } + else if (strncmp(ns, "admin.", 6) != 0 ) { + obj = fromjson("{\"err\":\"unauthorized - this command must be run against the admin DB\"}"); + } + else { + log() << "command: unlock requested" << endl; + if( _unlockFsync() ) { + obj = fromjson("{ok:1,\"info\":\"unlock completed\"}"); + } + else { + obj = fromjson("{ok:0,\"errmsg\":\"not locked\"}"); + } + } + replyToQuery(0, m, dbresponse, obj); + } + namespace { void generateErrorResponse(const AssertionException* exception, @@ -298,44 +324,6 @@ namespace { dbResponse.responseTo = responseTo; } -namespace { - - // In SERVER-7775 we reimplemented the pseudo-commands fsyncUnlock, inProg, and killOp - // as ordinary commands. To support old clients for another release, this helper serves - // to execute the real command from the legacy pseudo-command codepath. - // TODO: remove after MongoDB 3.2 is released - void receivedPseudoCommand(OperationContext* txn, - const NamespaceString& nss, - Client& client, - DbResponse& dbResponse, - Message& message, - StringData realCommandName) { - Message interposed; - - NamespaceString interposedNss(nss.db(), "$cmd"); - - BSONObjBuilder cmdBob; - cmdBob.append(realCommandName, 1); - auto cmd = cmdBob.done(); - - // TODO: use OP_COMMAND here instead of constructing - // a legacy OP_QUERY style command - BufBuilder cmdMsgBuf; - cmdMsgBuf.appendNum(DataView(message.header().data()).readLE<int32_t>()); // flags - cmdMsgBuf.appendStr(interposedNss.db(), false); // not including null byte - cmdMsgBuf.appendStr(".$cmd"); - cmdMsgBuf.appendNum(0); // ntoskip - cmdMsgBuf.appendNum(1); // ntoreturn - cmdMsgBuf.appendBuf(cmd.objdata(), cmd.objsize()); - - interposed.setData(dbQuery, cmdMsgBuf.buf(), cmdMsgBuf.len()); - interposed.header().setId(message.header().getId()); - - receivedCommand(txn, interposedNss, client, dbResponse, interposed); - } - -} // namespace - static void receivedQuery(OperationContext* txn, const NamespaceString& nss, Client& c, @@ -420,7 +408,7 @@ namespace { return; } if (nsString.coll() == "$cmd.sys.unlock") { - receivedPseudoCommand(txn, nsString, c, dbresponse, m, "fsyncUnlock"); + unlockFsync(txn, ns, m, dbresponse); return; } } diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index 9a6c5399067..48e086ad9f6 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -975,14 +975,7 @@ DB.prototype.fsyncLock = function() { } DB.prototype.fsyncUnlock = function() { - var res = this.adminCommand({fsyncUnlock: 1}); - if (!res.ok && - // handle both error messages for nonexistent command... - (res.errmsg.startsWith("no such cmd") || res.errmsg.startsWith("no such command"))) { - // fallback for old servers - res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne(); - } - return res; + return this.getSiblingDB("admin").$cmd.sys.unlock.findOne() } DB.autocomplete = function(obj){ |