diff options
author | Eliot Horowitz <eliot@10gen.com> | 2014-10-16 10:37:39 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2014-10-16 17:56:42 -0400 |
commit | a93beee92a74be918a1e861070f39bb9549c0134 (patch) | |
tree | 2b5a85a9d053e703a8fe4dd63ab5501710dc0158 /src | |
parent | 398270f3dff1fac5b7f2d853dc31af64bc8ce3a7 (diff) | |
download | mongo-a93beee92a74be918a1e861070f39bb9549c0134.tar.gz |
SERVER-15683: add command to introspect OperationContext and RecoveryUnit
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/clientlistplugin.cpp | 46 | ||||
-rw-r--r-- | src/mongo/db/global_environment_d.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.cpp | 42 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.h | 1 | ||||
-rw-r--r-- | src/mongo/db/storage/recovery_unit.h | 4 |
5 files changed, 75 insertions, 22 deletions
diff --git a/src/mongo/db/clientlistplugin.cpp b/src/mongo/db/clientlistplugin.cpp index 18d7ae04156..a7fd007d28c 100644 --- a/src/mongo/db/clientlistplugin.cpp +++ b/src/mongo/db/clientlistplugin.cpp @@ -28,7 +28,9 @@ #include "mongo/platform/basic.h" +#include "mongo/bson/bsonobjbuilder.h" #include "mongo/db/client.h" +#include "mongo/db/commands.h" #include "mongo/db/curop.h" #include "mongo/db/global_environment_experiment.h" #include "mongo/db/operation_context.h" @@ -116,5 +118,49 @@ namespace { } } clientListPlugin; + + class CommandHelper : public GlobalEnvironmentExperiment::ProcessOperationContext { + public: + virtual void processOpContext(OperationContext* txn) { + BSONObjBuilder b; + if ( txn->getClient() ) + txn->getClient()->reportState( b ); + if ( txn->getCurOp() ) + txn->getCurOp()->reportState( &b ); + if ( txn->lockState() ) + b.append( "lockState", txn->lockState()->reportState() ); + if ( txn->recoveryUnit() ) + txn->recoveryUnit()->reportState( &b ); + array.append( b.obj() ); + } + + BSONArrayBuilder array; + }; + + class CurrentOpContexts : public Command { + public: + CurrentOpContexts() : Command( "currentOpCtx" ) { } + + virtual bool isWriteCommandForConfigServer() const { return false; } + + virtual bool slaveOk() const { return true; } + + bool run( OperationContext* txn, + const string& dbname, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + CommandHelper helper; + getGlobalEnvironment()->forEachOperationContext(&helper); + + result.appendArray( "operations", helper.array.arr() ); + + return true; + } + } currentOpContexts; + } // namespace } // namespace mongo diff --git a/src/mongo/db/global_environment_d.cpp b/src/mongo/db/global_environment_d.cpp index 33fe95a6bfe..cae5ef8ccad 100644 --- a/src/mongo/db/global_environment_d.cpp +++ b/src/mongo/db/global_environment_d.cpp @@ -176,8 +176,8 @@ namespace mongo { void GlobalEnvironmentMongoD::forEachOperationContext(ProcessOperationContext* procOpCtx) { scoped_lock lock(_registeredOpContextsMutex); - OperationContextSet::iterator it; - for (it = _registeredOpContexts.begin(); it != _registeredOpContexts.end(); it++) { + OperationContextSet::const_iterator it; + for (it = _registeredOpContexts.begin(); it != _registeredOpContexts.end(); ++it) { procOpCtx->processOpContext(*it); } } diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp index 91858ff64d7..47310d3b0f5 100644 --- a/src/mongo/db/operation_context_impl.cpp +++ b/src/mongo/db/operation_context_impl.cpp @@ -57,6 +57,8 @@ namespace mongo { _locker.reset(new LockerImpl<true>()); } + _client = &cc(); + getGlobalEnvironment()->registerOperationContext(this); } @@ -92,15 +94,15 @@ namespace mongo { } bool OperationContextImpl::isGod() const { - return cc().isGod(); + return getClient()->isGod(); } Client* OperationContextImpl::getClient() const { - return &cc(); + return _client; } CurOp* OperationContextImpl::getCurOp() const { - return cc().curop(); + return getClient()->curop(); } unsigned int OperationContextImpl::getOpID() const { @@ -153,9 +155,9 @@ namespace mongo { } // namespace void OperationContextImpl::checkForInterrupt(bool heedMutex) const { - Client& c = cc(); + Client* c = getClient(); - if (heedMutex && lockState()->isWriteLocked() && c.hasWrittenSinceCheckpoint()) { + if (heedMutex && lockState()->isWriteLocked() && c->hasWrittenSinceCheckpoint()) { return; } @@ -163,46 +165,46 @@ namespace mongo { "interrupted at shutdown", !getGlobalEnvironment()->getKillAllOperations()); - if (c.curop()->maxTimeHasExpired()) { - c.curop()->kill(); + if (c->curop()->maxTimeHasExpired()) { + c->curop()->kill(); uasserted(ErrorCodes::ExceededTimeLimit, "operation exceeded time limit"); } MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) { - if (opShouldFail(c, scopedFailPoint.getData())) { - log() << "set pending kill on " << (c.curop()->parent() ? "nested" : "top-level") - << " op " << c.curop()->opNum() << ", for checkForInterruptFail"; - c.curop()->kill(); + if (opShouldFail(*c, scopedFailPoint.getData())) { + log() << "set pending kill on " << (c->curop()->parent() ? "nested" : "top-level") + << " op " << c->curop()->opNum() << ", for checkForInterruptFail"; + c->curop()->kill(); } } - if (c.curop()->killPending()) { + if (c->curop()->killPending()) { uasserted(ErrorCodes::Interrupted, "operation was interrupted"); } } Status OperationContextImpl::checkForInterruptNoAssert() const { // TODO(spencer): Unify error codes and implementation with checkForInterrupt() - Client& c = cc(); + Client* c = getClient(); if (getGlobalEnvironment()->getKillAllOperations()) { return Status(ErrorCodes::Interrupted, "interrupted at shutdown"); } - if (c.curop()->maxTimeHasExpired()) { - c.curop()->kill(); + if (c->curop()->maxTimeHasExpired()) { + c->curop()->kill(); return Status(ErrorCodes::Interrupted, "exceeded time limit"); } MONGO_FAIL_POINT_BLOCK(checkForInterruptFail, scopedFailPoint) { - if (opShouldFail(c, scopedFailPoint.getData())) { - log() << "set pending kill on " << (c.curop()->parent() ? "nested" : "top-level") - << " op " << c.curop()->opNum() << ", for checkForInterruptFail"; - c.curop()->kill(); + if (opShouldFail(*c, scopedFailPoint.getData())) { + log() << "set pending kill on " << (c->curop()->parent() ? "nested" : "top-level") + << " op " << c->curop()->opNum() << ", for checkForInterruptFail"; + c->curop()->kill(); } } - if (c.curop()->killPending()) { + if (c->curop()->killPending()) { return Status(ErrorCodes::Interrupted, "interrupted"); } diff --git a/src/mongo/db/operation_context_impl.h b/src/mongo/db/operation_context_impl.h index b8ae53a2185..616380e174f 100644 --- a/src/mongo/db/operation_context_impl.h +++ b/src/mongo/db/operation_context_impl.h @@ -73,6 +73,7 @@ namespace mongo { private: std::auto_ptr<RecoveryUnit> _recovery; std::auto_ptr<Locker> _locker; + Client* _client; // cached, not owned }; } // namespace mongo diff --git a/src/mongo/db/storage/recovery_unit.h b/src/mongo/db/storage/recovery_unit.h index 4657a85c7f6..39fb62b47cd 100644 --- a/src/mongo/db/storage/recovery_unit.h +++ b/src/mongo/db/storage/recovery_unit.h @@ -35,6 +35,8 @@ namespace mongo { + class BSONObjBuilder; + /** * A RecoveryUnit is responsible for ensuring that data is persisted. * All on-disk information must be mutated through this interface. @@ -44,6 +46,8 @@ namespace mongo { public: virtual ~RecoveryUnit() { } + virtual void reportState( BSONObjBuilder* b ) const { } + /** * These should be called through WriteUnitOfWork rather than directly. * |