summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdam Midvidy <amidvidy@gmail.com>2015-03-26 10:03:29 -0400
committerAdam Midvidy <amidvidy@gmail.com>2015-03-26 14:20:38 -0400
commit8a805598bbcb2ac20c345e0734c9fbd4c4722cb0 (patch)
tree4aebb32c235232b931c705bbd9e6c86f27162ff4 /src
parent78005d5702732d841119ff2628d5675a5049335c (diff)
downloadmongo-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.cpp114
-rw-r--r--src/mongo/db/commands/fsync.h2
-rw-r--r--src/mongo/db/instance.cpp66
-rw-r--r--src/mongo/shell/db.js11
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){