diff options
author | Bernard Gorman <bernard.gorman@gmail.com> | 2017-07-07 04:47:07 +0100 |
---|---|---|
committer | Bernard Gorman <bernard.gorman@gmail.com> | 2017-07-07 14:38:34 +0100 |
commit | 2b198988a626df6f36c9e606b08b266c462cceb4 (patch) | |
tree | 56c3cb97ea71d8b617d39b3af678276e55d07b7b /src/mongo/db/commands/current_op.cpp | |
parent | 286717ae5aa0c5a83ea8bf49b75158ae4af0b857 (diff) | |
download | mongo-2b198988a626df6f36c9e606b08b266c462cceb4.tar.gz |
SERVER-19318 Reimplement the currentOp command as a $currentOp aggregation
Diffstat (limited to 'src/mongo/db/commands/current_op.cpp')
-rw-r--r-- | src/mongo/db/commands/current_op.cpp | 172 |
1 files changed, 26 insertions, 146 deletions
diff --git a/src/mongo/db/commands/current_op.cpp b/src/mongo/db/commands/current_op.cpp index 510bf298cba..838f01c44f0 100644 --- a/src/mongo/db/commands/current_op.cpp +++ b/src/mongo/db/commands/current_op.cpp @@ -26,51 +26,28 @@ * it in the license file. */ -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand - #include "mongo/platform/basic.h" -#include <string> +#include "mongo/db/commands/current_op_common.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/client.h" -#include "mongo/db/commands.h" #include "mongo/db/commands/fsync.h" -#include "mongo/db/curop.h" -#include "mongo/db/dbmessage.h" -#include "mongo/db/jsobj.h" -#include "mongo/db/matcher/extensions_callback_real.h" -#include "mongo/db/matcher/matcher.h" -#include "mongo/db/namespace_string.h" -#include "mongo/db/operation_context.h" +#include "mongo/db/commands/run_aggregate.h" +#include "mongo/db/pipeline/document.h" #include "mongo/db/stats/fill_locker_info.h" -#include "mongo/rpc/metadata/client_metadata.h" -#include "mongo/rpc/metadata/client_metadata_ismaster.h" -#include "mongo/util/log.h" -#include "mongo/util/time_support.h" namespace mongo { -class CurrentOpCommand : public Command { -public: - CurrentOpCommand() : Command("currentOp") {} - - - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - bool slaveOk() const final { - return true; - } +class CurrentOpCommand final : public CurrentOpCommandBase { + MONGO_DISALLOW_COPYING(CurrentOpCommand); - bool adminOnly() const final { - return true; - } +public: + CurrentOpCommand() = default; Status checkAuthForCommand(Client* client, - const std::string& dbname, + const std::string& dbName, const BSONObj& cmdObj) final { AuthorizationSession* authzSession = AuthorizationSession::get(client); if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forClusterResource(), @@ -86,127 +63,30 @@ public: return Status(ErrorCodes::Unauthorized, "Unauthorized"); } - bool run(OperationContext* opCtx, - const std::string& db, - const BSONObj& cmdObj, - std::string& errmsg, - BSONObjBuilder& result) final { - const bool includeAll = cmdObj["$all"].trueValue(); - const bool ownOpsOnly = cmdObj["$ownOps"].trueValue(); - - // Filter the output - BSONObj filter; - { - BSONObjBuilder b; - BSONObjIterator i(cmdObj); - invariant(i.more()); - i.next(); // skip {currentOp: 1} which is required to be the first element - while (i.more()) { - BSONElement e = i.next(); - const auto fieldName = e.fieldNameStringData(); - if (fieldName == "$all") { - continue; - } else if (fieldName == "$ownOps") { - continue; - } else if (Command::isGenericArgument(fieldName)) { - continue; - } - - b.append(e); - } - filter = b.obj(); - } + virtual StatusWith<CursorResponse> runAggregation( + OperationContext* opCtx, const AggregationRequest& request) const final { + auto aggCmdObj = request.serializeToCommandObj().toBson(); - std::vector<BSONObj> inprogInfos; - BSONArrayBuilder inprogBuilder(result.subarrayStart("inprog")); - - for (ServiceContext::LockedClientsCursor cursor(opCtx->getClient()->getServiceContext()); - Client* client = cursor.next();) { - invariant(client); - - stdx::lock_guard<Client> lk(*client); - - if (ownOpsOnly && - !AuthorizationSession::get(opCtx->getClient())->isCoauthorizedWithClient(client)) { - continue; - } - - const OperationContext* clientOpCtx = client->getOperationContext(); - - if (!includeAll) { - // Skip over inactive connections. - if (!clientOpCtx) - continue; - } - - BSONObjBuilder infoBuilder; - - // The client information - client->reportState(infoBuilder); - - const auto& clientMetadata = - ClientMetadataIsMasterState::get(client).getClientMetadata(); - if (clientMetadata) { - auto appName = clientMetadata.get().getApplicationName(); - if (!appName.empty()) { - infoBuilder.append("appName", appName); - } - - auto clientMetadataDocument = clientMetadata.get().getDocument(); - infoBuilder.append("clientMetadata", clientMetadataDocument); - } - - // Operation context specific information - infoBuilder.appendBool("active", static_cast<bool>(clientOpCtx)); - infoBuilder.append("currentOpTime", Date_t::now().toString()); - if (clientOpCtx) { - infoBuilder.append("opid", clientOpCtx->getOpID()); - if (clientOpCtx->isKillPending()) { - infoBuilder.append("killPending", true); - } - - CurOp::get(clientOpCtx)->reportState(&infoBuilder); - - // LockState - Locker::LockerInfo lockerInfo; - clientOpCtx->lockState()->getLockerInfo(&lockerInfo); - fillLockerInfo(lockerInfo, infoBuilder); - } - - // If we want to include all results or if the filter is empty, then we can append - // straight to the inprogBuilder, but otherwise we should run the filter Matcher - // outside this loop so we don't lock the ServiceContext while matching - in some cases - // this can cause deadlocks. - if (includeAll || filter.isEmpty()) { - inprogBuilder.append(infoBuilder.obj()); - } else { - inprogInfos.emplace_back(infoBuilder.obj()); - } - } + BSONObjBuilder responseBuilder; + + auto status = runAggregate( + opCtx, request.getNamespaceString(), request, std::move(aggCmdObj), responseBuilder); - if (!inprogInfos.empty()) { - // We use ExtensionsCallbackReal here instead of ExtensionsCallbackNoop in order to - // support the use case of having a $where filter with currentOp. However, since we - // don't have a collection, we pass in a fake collection name (and this is okay, - // because $where parsing only relies on the database part of the namespace). - const NamespaceString fakeNS(db, "$dummyNamespaceForCurrop"); - const Matcher matcher(filter, ExtensionsCallbackReal(opCtx, &fakeNS), nullptr); - - for (const auto& info : inprogInfos) { - if (matcher.matches(info)) { - inprogBuilder.append(info); - } - } + if (!status.isOK()) { + return status; } - inprogBuilder.done(); + appendCommandStatus(responseBuilder, Status::OK()); + + return CursorResponse::parseFromBSON(responseBuilder.obj()); + } + + virtual void appendToResponse(BSONObjBuilder* result) const final { if (lockedForWriting()) { - result.append("fsyncLock", true); - result.append("info", - "use db.fsyncUnlock() to terminate the fsync write/snapshot lock"); + result->append("fsyncLock", true); + result->append("info", + "use db.fsyncUnlock() to terminate the fsync write/snapshot lock"); } - - return true; } } currentOpCommand; |