summaryrefslogtreecommitdiff
path: root/src/mongo/db/commands/current_op.cpp
diff options
context:
space:
mode:
authorBernard Gorman <bernard.gorman@gmail.com>2017-07-07 04:47:07 +0100
committerBernard Gorman <bernard.gorman@gmail.com>2017-07-07 14:38:34 +0100
commit2b198988a626df6f36c9e606b08b266c462cceb4 (patch)
tree56c3cb97ea71d8b617d39b3af678276e55d07b7b /src/mongo/db/commands/current_op.cpp
parent286717ae5aa0c5a83ea8bf49b75158ae4af0b857 (diff)
downloadmongo-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.cpp172
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;