diff options
author | Adam Midvidy <amidvidy@gmail.com> | 2015-03-26 10:03:29 -0400 |
---|---|---|
committer | Adam Midvidy <amidvidy@gmail.com> | 2015-03-26 14:20:38 -0400 |
commit | 8a805598bbcb2ac20c345e0734c9fbd4c4722cb0 (patch) | |
tree | 4aebb32c235232b931c705bbd9e6c86f27162ff4 /src | |
parent | 78005d5702732d841119ff2628d5675a5049335c (diff) | |
download | mongo-8a805598bbcb2ac20c345e0734c9fbd4c4722cb0.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 | 114 | ||||
-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 | 11 |
4 files changed, 138 insertions, 55 deletions
diff --git a/src/mongo/db/commands/fsync.cpp b/src/mongo/db/commands/fsync.cpp index f9f829df3b7..267ecf82a0e 100644 --- a/src/mongo/db/commands/fsync.cpp +++ b/src/mongo/db/commands/fsync.cpp @@ -26,16 +26,23 @@ * 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 <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 +50,10 @@ #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/util/background.h" #include "mongo/util/log.h" - namespace mongo { using std::endl; @@ -154,6 +159,61 @@ namespace mongo { } } 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; + } + } + + } unlockFsyncCmd; + SimpleMutex filesLockedFsync("filesLockedFsync"); void FSyncLockThread::doRealWork() { @@ -164,12 +224,12 @@ namespace mongo { 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 { + 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(); @@ -183,7 +243,7 @@ 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(); @@ -193,37 +253,39 @@ namespace mongo { invariant(!fsyncCmd.locked); fsyncCmd.locked = true; - + fsyncCmd._threadSync.notify_one(); while ( ! fsyncCmd.pendingUnlock ) { fsyncCmd._unlockSync.wait(fsyncCmd.m); } fsyncCmd.pendingUnlock = false; - + 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..7be8562cca2 100644 --- a/src/mongo/shell/db.js +++ b/src/mongo/shell/db.js @@ -975,7 +975,16 @@ 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") || + res.code === 59)) { + // fallback for old servers + res = this.getSiblingDB("admin").$cmd.sys.unlock.findOne(); + } + return res; } DB.autocomplete = function(obj){ |