summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-03-24 10:45:04 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-03-25 15:00:03 -0400
commit5c48ea0d3fd6556eb0ba7686a9da6159f0814d08 (patch)
tree6c32840fcf8d45a4ee70adf419ca2bb7390171c2 /src
parentbbe95e94bc7231a0b06c395a52c6575d7d23e03e (diff)
downloadmongo-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.cpp163
-rw-r--r--src/mongo/db/commands/fsync.h2
-rw-r--r--src/mongo/db/instance.cpp66
-rw-r--r--src/mongo/shell/db.js9
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){