summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2014-10-16 10:37:39 -0400
committerEliot Horowitz <eliot@10gen.com>2014-10-16 17:56:42 -0400
commita93beee92a74be918a1e861070f39bb9549c0134 (patch)
tree2b5a85a9d053e703a8fe4dd63ab5501710dc0158 /src
parent398270f3dff1fac5b7f2d853dc31af64bc8ce3a7 (diff)
downloadmongo-a93beee92a74be918a1e861070f39bb9549c0134.tar.gz
SERVER-15683: add command to introspect OperationContext and RecoveryUnit
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/clientlistplugin.cpp46
-rw-r--r--src/mongo/db/global_environment_d.cpp4
-rw-r--r--src/mongo/db/operation_context_impl.cpp42
-rw-r--r--src/mongo/db/operation_context_impl.h1
-rw-r--r--src/mongo/db/storage/recovery_unit.h4
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.
*