diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-03-24 10:45:04 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-03-25 15:00:03 -0400 |
commit | 5c48ea0d3fd6556eb0ba7686a9da6159f0814d08 (patch) | |
tree | 6c32840fcf8d45a4ee70adf419ca2bb7390171c2 /src | |
parent | bbe95e94bc7231a0b06c395a52c6575d7d23e03e (diff) | |
download | mongo-5c48ea0d3fd6556eb0ba7686a9da6159f0814d08.tar.gz |
SERVER-7775 refactor fsyncUnlock to execute through standard command path
Diffstat (limited to 'src')
-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 |
4 files changed, 167 insertions, 73 deletions
diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index f9f829df3b7..b6fde72e309 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -26,16 +26,24 @@ * it in the license file. */ -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand #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" @@ -43,12 +51,11 @@ #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; @@ -152,7 +159,73 @@ namespace mongo { } return 1; } - } fsyncCmd; + }; + + 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(); + } SimpleMutex filesLockedFsync("filesLockedFsync"); @@ -163,17 +236,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; } @@ -183,47 +256,49 @@ 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.locked = false; - fsyncCmd.err = "unlocked"; + fsyncCmd->pendingUnlock = false; - fsyncCmd._unlockSync.notify_one(); + fsyncCmd->locked = false; + fsyncCmd->err = "unlocked"; + + fsyncCmd->_unlockSync.notify_one(); } - bool lockedForWriting() { - return fsyncCmd.locked; + bool lockedForWriting() { + return fsyncCmd->locked; } - // @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 ); + 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; - } + } // namespace } diff --git a/src/mongo/db/commands/fsync.h b/src/mongo/db/commands/fsync.h index f3fa2adb993..4072a1f6e50 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 46e0edd4b13..242a81db415 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -180,32 +180,6 @@ 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, @@ -324,6 +298,44 @@ 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, @@ -408,7 +420,7 @@ namespace { return; } if (nsString.coll() == "$cmd.sys.unlock") { - unlockFsync(txn, ns, m, dbresponse); + receivedPseudoCommand(txn, nsString, c, dbresponse, m, "fsyncUnlock"); return; } } diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js index 48e086ad9f6..9a6c5399067 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -975,7 +975,14 @@ DB.prototype.fsyncLock = function() { } DB.prototype.fsyncUnlock = function() { - return this.getSiblingDB("admin").$cmd.sys.unlock.findOne() + 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; } DB.autocomplete = function(obj){ |