summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/client.cpp9
-rw-r--r--src/mongo/db/client.h17
-rw-r--r--src/mongo/db/clientlistplugin.cpp203
-rw-r--r--src/mongo/db/currentop_command.cpp139
-rw-r--r--src/mongo/db/global_environment_d.cpp35
-rw-r--r--src/mongo/db/global_environment_d.h12
-rw-r--r--src/mongo/db/global_environment_experiment.h42
-rw-r--r--src/mongo/db/global_environment_noop.cpp12
-rw-r--r--src/mongo/db/global_environment_noop.h6
-rw-r--r--src/mongo/db/operation_context_impl.cpp4
-rw-r--r--src/mongo/db/stats/lock_server_status_section.cpp122
-rw-r--r--src/mongo/dbtests/repltests.cpp17
12 files changed, 264 insertions, 354 deletions
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index 21e25cd2266..63cb26cb6eb 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -113,6 +113,7 @@ namespace mongo {
_threadId(boost::this_thread::get_id()),
_connectionId(p ? p->connectionId() : 0),
_god(0),
+ _txn(NULL),
_lastOp(0),
_shutdown(false) {
@@ -329,8 +330,14 @@ namespace mongo {
if (_connectionId) {
builder.appendNumber("connectionId", _connectionId);
}
+ }
+
+ void Client::setOperationContext(OperationContext* txn) {
+ // We can only set or unset the OperationContexts, never swap them.
+ invariant((txn == NULL) ^ (_txn == NULL));
- _curOp->reportState(&builder);
+ boost::unique_lock<SpinLock> uniqueLock(_lock);
+ _txn = txn;
}
string Client::clientAddress(bool includePort) const {
diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h
index 840a3f0d4c9..e71180edd52 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -46,6 +46,7 @@
#include "mongo/db/operation_context.h"
#include "mongo/platform/unordered_set.h"
#include "mongo/stdx/functional.h"
+#include "mongo/util/concurrency/spin_lock.h"
#include "mongo/util/concurrency/threadlocal.h"
#include "mongo/util/paths.h"
@@ -205,6 +206,16 @@ namespace mongo {
void appendLastOp( BSONObjBuilder& b ) const;
void reportState(BSONObjBuilder& builder);
+ // Ensures stability of the client. When the client is locked, it is safe to access its
+ // contents. For example, the OperationContext will not disappear.
+ void lock() { _lock.lock(); }
+ void unlock() { _lock.unlock(); }
+
+ // Changes the currently active operation context on this client. There can only be one
+ // active OperationContext at a time.
+ void setOperationContext(OperationContext* txn);
+ const OperationContext* getOperationContext() const { return _txn; }
+
// TODO(spencer): SERVER-10228 SERVER-14779 Remove this/move it fully into OperationContext.
bool isGod() const { return _god; } /* this is for map/reduce writes */
bool setGod(bool newVal) { const bool prev = _god; _god = newVal; return prev; }
@@ -227,9 +238,15 @@ namespace mongo {
// > 0 for things "conn", 0 otherwise
const ConnectionId _connectionId;
+ // Protects the contents of the Client (such as changing the OperationContext, etc)
+ mutable SpinLock _lock;
+
// Whether this client is running as DBDirectClient
bool _god;
+ // If != NULL, then contains the currently active OperationContext
+ OperationContext* _txn;
+
// Changes, based on what operation is running. Some of this should be in OperationContext.
CurOp* _curOp;
diff --git a/src/mongo/db/clientlistplugin.cpp b/src/mongo/db/clientlistplugin.cpp
index 31381c87a16..607c37f4131 100644
--- a/src/mongo/db/clientlistplugin.cpp
+++ b/src/mongo/db/clientlistplugin.cpp
@@ -28,6 +28,8 @@
#include "mongo/platform/basic.h"
+#include <boost/thread/locks.hpp>
+
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/auth/action_type.h"
#include "mongo/db/auth/authorization_session.h"
@@ -43,64 +45,8 @@
#include "mongo/util/stringutils.h"
namespace mongo {
-
- class OperationsDataBuilder : public GlobalEnvironmentExperiment::ProcessOperationContext {
- public:
- OperationsDataBuilder(std::stringstream& stringStream)
- : _stringStream(stringStream) {
-
- }
-
- virtual void processOpContext(OperationContext* txn) {
- using namespace html;
-
- CurOp& co = *(txn->getCurOp());
-
- _stringStream << "<tr><td>" << txn->getClient()->desc() << "</td>";
-
- tablecell(_stringStream, co.opNum());
- tablecell(_stringStream, co.active());
-
- // LockState
- {
- Locker::LockerInfo lockerInfo;
- txn->lockState()->getLockerInfo(&lockerInfo);
-
- BSONObjBuilder lockerInfoBuilder;
- fillLockerInfo(lockerInfo, lockerInfoBuilder);
-
- tablecell(_stringStream, lockerInfoBuilder.obj());
- }
-
- if (co.active()) {
- tablecell(_stringStream, co.elapsedSeconds());
- }
- else {
- tablecell(_stringStream, "");
- }
-
- tablecell(_stringStream, co.getOp());
- tablecell(_stringStream, html::escape(co.getNS()));
- if (co.haveQuery()) {
- tablecell(_stringStream, html::escape(co.query().toString()));
- }
- else {
- tablecell(_stringStream, "");
- }
-
- tablecell(_stringStream, co.getRemoteString());
-
- tablecell(_stringStream, co.getMessage());
- tablecell(_stringStream, co.getProgressMeter().toString());
-
- _stringStream << "</tr>\n";
- }
-
- private:
- std::stringstream& _stringStream;
- };
-
namespace {
+
class ClientListPlugin : public WebStatusPlugin {
public:
ClientListPlugin() : WebStatusPlugin( "clients" , 20 ) {}
@@ -125,31 +71,35 @@ namespace {
<< "</tr>\n";
- OperationsDataBuilder opCtxDataBuilder(ss);
- getGlobalEnvironment()->forEachOperationContext(&opCtxDataBuilder);
+ _processAllClients(ss);
ss << "</table>\n";
-
}
- } clientListPlugin;
+ private:
- class CommandHelper : public GlobalEnvironmentExperiment::ProcessOperationContext {
- public:
- CommandHelper( MatchExpression* me )
- : matcher( me ) {
- }
+ static void _processAllClients(std::stringstream& ss) {
+ using namespace html;
+
+ boost::mutex::scoped_lock scopedLock(Client::clientsMutex);
+
+ ClientSet::const_iterator it = Client::clients.begin();
+ for (; it != Client::clients.end(); it++) {
+ Client* client = *it;
+ invariant(client);
+
+ // Make the client stable
+ boost::unique_lock<Client> clientLock(*client);
+ const OperationContext* txn = client->getOperationContext();
+ if (!txn) continue;
+
+ CurOp* curOp = txn->getCurOp();
+ if (!curOp) continue;
- virtual void processOpContext(OperationContext* txn) {
- BSONObjBuilder b;
- if ( txn->getClient() )
- txn->getClient()->reportState( b );
- if ( txn->getCurOp() )
- txn->getCurOp()->reportState( &b );
- if ( txn->lockState() ) {
- StringBuilder ss;
- ss << txn->lockState();
- b.append("lockStatePointer", ss.str());
+ ss << "<tr><td>" << client->desc() << "</td>";
+
+ tablecell(ss, curOp->opNum());
+ tablecell(ss, curOp->active());
// LockState
{
@@ -159,24 +109,37 @@ namespace {
BSONObjBuilder lockerInfoBuilder;
fillLockerInfo(lockerInfo, lockerInfoBuilder);
- b.append("lockState", lockerInfoBuilder.obj());
+ tablecell(ss, lockerInfoBuilder.obj());
}
- }
- if ( txn->recoveryUnit() )
- txn->recoveryUnit()->reportState( &b );
- BSONObj obj = b.obj();
+ if (curOp->active()) {
+ tablecell(ss, curOp->elapsedSeconds());
+ }
+ else {
+ tablecell(ss, "");
+ }
- if ( matcher && !matcher->matchesBSON( obj ) ) {
- return;
- }
+ tablecell(ss, curOp->getOp());
+ tablecell(ss, html::escape(curOp->getNS()));
+
+ if (curOp->haveQuery()) {
+ tablecell(ss, html::escape(curOp->query().toString()));
+ }
+ else {
+ tablecell(ss, "");
+ }
+
+ tablecell(ss, curOp->getRemoteString());
+
+ tablecell(ss, curOp->getMessage());
+ tablecell(ss, curOp->getProgressMeter().toString());
- array.append( obj );
+ ss << "</tr>\n";
+ }
}
- BSONArrayBuilder array;
- MatchExpression* matcher;
- };
+ } clientListPlugin;
+
class CurrentOpContexts : public Command {
public:
@@ -219,14 +182,70 @@ namespace {
filter.reset( res.getValue() );
}
- CommandHelper helper( filter.get() );
- getGlobalEnvironment()->forEachOperationContext(&helper);
-
- result.appendArray( "operations", helper.array.arr() );
+ result.appendArray("operations", _processAllClients(filter.get()));
return true;
}
+
+ private:
+
+ static BSONArray _processAllClients(MatchExpression* matcher) {
+ BSONArrayBuilder array;
+
+ boost::mutex::scoped_lock scopedLock(Client::clientsMutex);
+
+ ClientSet::const_iterator it = Client::clients.begin();
+ for (; it != Client::clients.end(); it++) {
+ Client* client = *it;
+ invariant(client);
+
+ BSONObjBuilder b;
+
+ // Make the client stable
+ boost::unique_lock<Client> clientLock(*client);
+
+ client->reportState(b);
+
+ const OperationContext* txn = client->getOperationContext();
+ if (txn) {
+
+ // CurOp
+ if (txn->getCurOp()) {
+ txn->getCurOp()->reportState(&b);
+ }
+
+ // LockState
+ if (txn->lockState()) {
+ StringBuilder ss;
+ ss << txn->lockState();
+ b.append("lockStatePointer", ss.str());
+
+ Locker::LockerInfo lockerInfo;
+ txn->lockState()->getLockerInfo(&lockerInfo);
+
+ BSONObjBuilder lockerInfoBuilder;
+ fillLockerInfo(lockerInfo, lockerInfoBuilder);
+
+ b.append("lockState", lockerInfoBuilder.obj());
+ }
+
+ // RecoveryUnit
+ if (txn->recoveryUnit()) {
+ txn->recoveryUnit()->reportState(&b);
+ }
+ }
+
+ const BSONObj obj = b.obj();
+
+ if (!matcher || matcher->matchesBSON(obj)) {
+ array.append(obj);
+ }
+ }
+
+ return array.arr();
+ }
+
} currentOpContexts;
} // namespace
diff --git a/src/mongo/db/currentop_command.cpp b/src/mongo/db/currentop_command.cpp
index 8aa96616ad0..fd0d53a798c 100644
--- a/src/mongo/db/currentop_command.cpp
+++ b/src/mongo/db/currentop_command.cpp
@@ -40,58 +40,17 @@
#include "mongo/db/curop.h"
#include "mongo/db/commands/fsync.h"
#include "mongo/db/dbmessage.h"
-#include "mongo/db/operation_context_impl.h"
-#include "mongo/db/global_environment_experiment.h"
+#include "mongo/db/operation_context.h"
#include "mongo/db/matcher/matcher.h"
#include "mongo/util/log.h"
namespace mongo {
namespace {
+
// Until we are able to resolve resource ids to db/collection names, report local db specially
const ResourceId resourceIdLocalDb = ResourceId(RESOURCE_DATABASE, std::string("local"));
-}
-
- /**
- * Populates the BSON array with information about all active clients on the server. A client
- * is active if it has an OperationContext.
- */
- class OperationInfoPopulator : public GlobalEnvironmentExperiment::ProcessOperationContext {
- public:
-
- OperationInfoPopulator(const Matcher& matcher, BSONArrayBuilder& builder)
- : _matcher(matcher),
- _builder(builder) {
-
- }
-
- virtual void processOpContext(OperationContext* txn) {
- if (!txn->getCurOp() || !txn->getCurOp()->active()) {
- return;
- }
-
- BSONObjBuilder infoBuilder;
-
- // Client-specific data
- txn->getClient()->reportState(infoBuilder);
-
- // Locking data
- Locker::LockerInfo lockerInfo;
- txn->lockState()->getLockerInfo(&lockerInfo);
- fillLockerInfo(lockerInfo, infoBuilder);
-
- infoBuilder.done();
-
- const BSONObj info = infoBuilder.obj();
-
- if (_matcher.matches(info)) {
- _builder.append(info);
- }
- }
- private:
- const Matcher& _matcher;
- BSONArrayBuilder& _builder;
- };
+} // namespace
void inProgCmd(OperationContext* txn, Message &message, DbResponse &dbresponse) {
@@ -114,60 +73,72 @@ namespace {
return;
}
+ const bool includeAll = q.query["$all"].trueValue();
+
+ // Filter the output
+ BSONObj filter;
+ {
+ BSONObjBuilder b;
+ BSONObjIterator i(q.query);
+ while (i.more()) {
+ BSONElement e = i.next();
+ if (str::equals("$all", e.fieldName())) {
+ continue;
+ }
+
+ b.append(e);
+ }
+ filter = b.obj();
+ }
+
+ const NamespaceString nss(d.getns());
+ const WhereCallbackReal whereCallback(txn, nss.db());
+ const Matcher matcher(filter, whereCallback);
+
BSONArrayBuilder inprogBuilder(retVal.subarrayStart("inprog"));
- // This lock is acquired for both cases (whether we iterate through the clients list or
- // through the OperationContexts), because we want the CurOp to not be destroyed from
- // underneath and ~CurOp synchronizes on the clients mutex.
- //
- // TODO: This is a legacy from 2.6, which needs to be fixed.
boost::mutex::scoped_lock scopedLock(Client::clientsMutex);
- const bool all = q.query["$all"].trueValue();
- if (all) {
- for (ClientSet::const_iterator i = Client::clients.begin();
- i != Client::clients.end();
- i++) {
+ ClientSet::const_iterator it = Client::clients.begin();
+ for ( ; it != Client::clients.end(); it++) {
+ Client* client = *it;
+ invariant(client);
- Client* client = *i;
- invariant(client);
+ boost::unique_lock<Client> uniqueLock(*client);
+ const OperationContext* opCtx = client->getOperationContext();
- CurOp* curop = client->curop();
- if ((client == txn->getClient()) && !curop) {
+ if (!includeAll) {
+ // Skip over inactive connections.
+ if (!opCtx || !opCtx->getCurOp() || !opCtx->getCurOp()->active()) {
continue;
}
+ }
- BSONObjBuilder infoBuilder;
- client->reportState(infoBuilder);
- infoBuilder.done();
+ BSONObjBuilder infoBuilder;
- inprogBuilder.append(infoBuilder.obj());
- }
- }
- else {
-
- // Filter the output
- BSONObj filter;
- {
- BSONObjBuilder b;
- BSONObjIterator i(q.query);
- while (i.more()) {
- BSONElement e = i.next();
- if (str::equals("$all", e.fieldName())) {
- continue;
- }
-
- b.append(e);
+ // The client information
+ client->reportState(infoBuilder);
+
+ // Operation context specific information
+ if (opCtx) {
+ // CurOp
+ if (opCtx->getCurOp()) {
+ opCtx->getCurOp()->reportState(&infoBuilder);
}
- filter = b.obj();
+
+ // LockState
+ Locker::LockerInfo lockerInfo;
+ client->getOperationContext()->lockState()->getLockerInfo(&lockerInfo);
+ fillLockerInfo(lockerInfo, infoBuilder);
}
- const NamespaceString nss(d.getns());
- const WhereCallbackReal whereCallback(txn, nss.db());
- const Matcher matcher(filter, whereCallback);
+ infoBuilder.done();
+
+ const BSONObj info = infoBuilder.obj();
- OperationInfoPopulator allOps(matcher, inprogBuilder);
- getGlobalEnvironment()->forEachOperationContext(&allOps);
+ if (includeAll || matcher.matches(info)) {
+ inprogBuilder.append(info);
+ }
}
inprogBuilder.done();
diff --git a/src/mongo/db/global_environment_d.cpp b/src/mongo/db/global_environment_d.cpp
index fe8ab0f9f85..a3c0694e6cd 100644
--- a/src/mongo/db/global_environment_d.cpp
+++ b/src/mongo/db/global_environment_d.cpp
@@ -30,8 +30,6 @@
#include "mongo/db/global_environment_d.h"
-#include <set>
-
#include "mongo/base/init.h"
#include "mongo/base/initializer.h"
#include "mongo/db/client.h"
@@ -52,13 +50,10 @@ namespace mongo {
GlobalEnvironmentMongoD::GlobalEnvironmentMongoD()
: _globalKill(false),
- _registeredOpContextsMutex("RegisteredOpContextsMutex"),
_storageEngine(NULL) { }
GlobalEnvironmentMongoD::~GlobalEnvironmentMongoD() {
- if (!_registeredOpContexts.empty()) {
- warning() << "Terminating with outstanding operation contexts." << endl;
- }
+
}
StorageEngine* GlobalEnvironmentMongoD::getGlobalStorageEngine() {
@@ -224,34 +219,6 @@ namespace mongo {
_killOpListeners.push_back(listener);
}
- void GlobalEnvironmentMongoD::registerOperationContext(OperationContext* txn) {
- scoped_lock lock(_registeredOpContextsMutex);
-
- // It is an error to register twice
- pair<OperationContextSet::const_iterator, bool> inserted
- = _registeredOpContexts.insert(txn);
- invariant(inserted.second);
- }
-
- void GlobalEnvironmentMongoD::unregisterOperationContext(OperationContext* txn) {
- scoped_lock lock(_registeredOpContextsMutex);
-
- // It is an error to unregister twice or to unregister something that's not been registered
- OperationContextSet::const_iterator it = _registeredOpContexts.find(txn);
- invariant(it != _registeredOpContexts.end());
-
- _registeredOpContexts.erase(it);
- }
-
- void GlobalEnvironmentMongoD::forEachOperationContext(ProcessOperationContext* procOpCtx) {
- scoped_lock lock(_registeredOpContextsMutex);
-
- OperationContextSet::const_iterator it;
- for (it = _registeredOpContexts.begin(); it != _registeredOpContexts.end(); ++it) {
- procOpCtx->processOpContext(*it);
- }
- }
-
OperationContext* GlobalEnvironmentMongoD::newOpCtx() {
return new OperationContextImpl();
}
diff --git a/src/mongo/db/global_environment_d.h b/src/mongo/db/global_environment_d.h
index 0639572a396..6b08e1cb3d1 100644
--- a/src/mongo/db/global_environment_d.h
+++ b/src/mongo/db/global_environment_d.h
@@ -34,7 +34,6 @@
#include "mongo/platform/unordered_set.h"
#include "mongo/util/concurrency/mutex.h"
-
namespace mongo {
class Client;
@@ -70,12 +69,6 @@ namespace mongo {
void registerKillOpListener(KillOpListenerInterface* listener);
- void registerOperationContext(OperationContext* txn);
-
- void unregisterOperationContext(OperationContext* txn);
-
- void forEachOperationContext(ProcessOperationContext* procOpCtx);
-
OperationContext* newOpCtx();
@@ -85,11 +78,6 @@ namespace mongo {
bool _globalKill;
- typedef unordered_set<OperationContext*> OperationContextSet;
-
- mongo::mutex _registeredOpContextsMutex;
- OperationContextSet _registeredOpContexts;
-
// protected by Client::clientsMutex
std::vector<KillOpListenerInterface*> _killOpListeners;
diff --git a/src/mongo/db/global_environment_experiment.h b/src/mongo/db/global_environment_experiment.h
index 67d87bd5437..78dc2b9181d 100644
--- a/src/mongo/db/global_environment_experiment.h
+++ b/src/mongo/db/global_environment_experiment.h
@@ -147,48 +147,6 @@ namespace mongo {
virtual void registerKillOpListener(KillOpListenerInterface* listener) = 0;
/**
- * Registers the specified operation context on the global environment, so it is
- * discoverable by diagnostics tools.
- *
- * This function must be thread-safe.
- */
- virtual void registerOperationContext(OperationContext* txn) = 0;
-
- /**
- * Unregisters a previously-registered operation context. It is an error to unregister the
- * same context twice or to unregister a context, which has not previously been registered.
- *
- * This function must be thread-safe.
- */
- virtual void unregisterOperationContext(OperationContext* txn) = 0;
-
- /**
- * Notification object to be passed to forEachOperationContext so that certain processing
- * can be done on all registered contexts.
- */
- class ProcessOperationContext {
- public:
-
- /**
- * Invoked for each registered OperationContext. The pointer is guaranteed to be stable
- * until the call returns.
- *
- * Implementations of this method should not acquire locks or do any operations, which
- * might block and should generally do as little work as possible in order to not block
- * the iteration or the release of the OperationContext.
- */
- virtual void processOpContext(OperationContext* txn) = 0;
-
- virtual ~ProcessOperationContext() { }
- };
-
- /**
- * Iterates over all registered operation contexts and invokes
- * ProcessOperationContext::processOpContext for each.
- */
- virtual void forEachOperationContext(ProcessOperationContext* procOpCtx) = 0;
-
- /**
* Returns a new OperationContext. Caller owns pointer.
*/
virtual OperationContext* newOpCtx() = 0;
diff --git a/src/mongo/db/global_environment_noop.cpp b/src/mongo/db/global_environment_noop.cpp
index d4526fd85aa..566c64a381f 100644
--- a/src/mongo/db/global_environment_noop.cpp
+++ b/src/mongo/db/global_environment_noop.cpp
@@ -72,18 +72,6 @@ namespace mongo {
void GlobalEnvironmentNoop::registerKillOpListener(KillOpListenerInterface* listener) {
}
- void GlobalEnvironmentNoop::registerOperationContext(OperationContext* txn) {
-
- }
-
- void GlobalEnvironmentNoop::unregisterOperationContext(OperationContext* txn) {
-
- }
-
- void GlobalEnvironmentNoop::forEachOperationContext(ProcessOperationContext* procOpCtx) {
-
- }
-
OperationContext* GlobalEnvironmentNoop::newOpCtx() {
return new OperationContextNoop();
}
diff --git a/src/mongo/db/global_environment_noop.h b/src/mongo/db/global_environment_noop.h
index 6d3681f7879..155e924e292 100644
--- a/src/mongo/db/global_environment_noop.h
+++ b/src/mongo/db/global_environment_noop.h
@@ -55,12 +55,6 @@ namespace mongo {
void registerKillOpListener(KillOpListenerInterface* listener);
- void registerOperationContext(OperationContext* txn);
-
- void unregisterOperationContext(OperationContext* txn);
-
- void forEachOperationContext(ProcessOperationContext* procOpCtx);
-
OperationContext* newOpCtx();
};
diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp
index 6cec3f70c6c..0d74b0c18ed 100644
--- a/src/mongo/db/operation_context_impl.cpp
+++ b/src/mongo/db/operation_context_impl.cpp
@@ -63,11 +63,11 @@ namespace {
_locker.reset(new LockerImpl<false>(idCounter.addAndFetch(1)));
}
- getGlobalEnvironment()->registerOperationContext(this);
+ _client->setOperationContext(this);
}
OperationContextImpl::~OperationContextImpl() {
- getGlobalEnvironment()->unregisterOperationContext(this);
+ _client->setOperationContext(NULL);
}
RecoveryUnit* OperationContextImpl::recoveryUnit() const {
diff --git a/src/mongo/db/stats/lock_server_status_section.cpp b/src/mongo/db/stats/lock_server_status_section.cpp
index 322e5322ad9..6cd04143133 100644
--- a/src/mongo/db/stats/lock_server_status_section.cpp
+++ b/src/mongo/db/stats/lock_server_status_section.cpp
@@ -28,47 +28,12 @@
#include "mongo/platform/basic.h"
+#include "mongo/db/client.h"
#include "mongo/db/commands/server_status.h"
-#include "mongo/db/global_environment_experiment.h"
#include "mongo/db/operation_context.h"
-
namespace mongo {
- /**
- * This is passed to the iterator for global environments and aggregates information about the
- * locks which are currently being held or waited on.
- */
- class LockStateAggregator : public GlobalEnvironmentExperiment::ProcessOperationContext {
- public:
- LockStateAggregator(bool blockedOnly)
- : numWriteLocked(0),
- numReadLocked(0),
- _blockedOnly(blockedOnly) {
-
- }
-
- virtual void processOpContext(OperationContext* txn) {
- if (_blockedOnly && !txn->lockState()->hasLockPending()) {
- return;
- }
-
- if (txn->lockState()->isWriteLocked()) {
- numWriteLocked++;
- }
- else {
- numReadLocked++;
- }
- }
-
- int numWriteLocked;
- int numReadLocked;
-
- private:
- const bool _blockedOnly;
- };
-
-
class GlobalLockServerStatusSection : public ServerStatusSection {
public:
GlobalLockServerStatusSection() : ServerStatusSection("globalLock"){
@@ -80,41 +45,78 @@ namespace mongo {
virtual BSONObj generateSection(OperationContext* txn,
const BSONElement& configElement) const {
- BSONObjBuilder t;
-
- t.append("totalTime", (long long)(1000 * (curTimeMillis64() - _started)));
-
- // SERVER-14978: Need to report the global lock statistics somehow
- //
- // t.append( "lockTime" , qlk.stats.getTimeLocked( 'W' ) );
+ int numTotal = 0;
+ int numWriteLocked = 0;
+ int numReadLocked = 0;
+ int numWaitingRead = 0;
+ int numWaitingWrite = 0;
// This returns the blocked lock states
{
- BSONObjBuilder ttt(t.subobjStart("currentQueue"));
+ boost::mutex::scoped_lock scopedLock(Client::clientsMutex);
+
+ // Count all clients
+ numTotal = Client::clients.size();
+
+ ClientSet::const_iterator it = Client::clients.begin();
+ for (; it != Client::clients.end(); it++) {
+ Client* client = *it;
+ invariant(client);
+
+ boost::unique_lock<Client> uniqueLock(*client);
+
+ const OperationContext* opCtx = client->getOperationContext();
+ if (opCtx == NULL) continue;
+
+ if (opCtx->lockState()->getWaitingResource().isValid()) {
+ // Count client as blocked
+ if (opCtx->lockState()->isWriteLocked()) {
+ numWaitingWrite++;
+ numWriteLocked++;
+ }
+ else {
+ numWaitingRead++;
+ numReadLocked++;
+ }
+ }
+ else {
+ // Count client as not blocked
+ if (opCtx->lockState()->isWriteLocked()) {
+ numWriteLocked++;
+ }
+ else {
+ numReadLocked++;
+ }
+ }
+ }
+ }
- LockStateAggregator blocked(true);
- getGlobalEnvironment()->forEachOperationContext(&blocked);
+ // Construct the actual return value out of the mutex
+ BSONObjBuilder ret;
- ttt.append("total", blocked.numReadLocked + blocked.numWriteLocked);
- ttt.append("readers", blocked.numReadLocked);
- ttt.append("writers", blocked.numWriteLocked);
- ttt.done();
- }
+ ret.append("totalTime", (long long)(1000 * (curTimeMillis64() - _started)));
- // This returns all the active clients (including those holding locks)
{
- BSONObjBuilder ttt(t.subobjStart("activeClients"));
+ BSONObjBuilder currentQueueBuilder(ret.subobjStart("currentQueue"));
+
+ currentQueueBuilder.append("total", numWaitingRead + numWaitingWrite);
+ currentQueueBuilder.append("readers", numWaitingRead);
+ currentQueueBuilder.append("writers", numWaitingWrite);
+ currentQueueBuilder.done();
+ }
- LockStateAggregator active(false);
- getGlobalEnvironment()->forEachOperationContext(&active);
+ {
+ BSONObjBuilder activeClientsBuilder(ret.subobjStart("activeClients"));
- ttt.append("total", active.numReadLocked + active.numWriteLocked);
- ttt.append("readers", active.numReadLocked);
- ttt.append("writers", active.numWriteLocked);
- ttt.done();
+ activeClientsBuilder.append("total", numTotal);
+ activeClientsBuilder.append("readers", numReadLocked);
+ activeClientsBuilder.append("writers", numWriteLocked);
+ activeClientsBuilder.done();
}
- return t.obj();
+ ret.done();
+
+ return ret.obj();
}
private:
diff --git a/src/mongo/dbtests/repltests.cpp b/src/mongo/dbtests/repltests.cpp
index 914a6d1ec1e..29444c86544 100644
--- a/src/mongo/dbtests/repltests.cpp
+++ b/src/mongo/dbtests/repltests.cpp
@@ -31,7 +31,7 @@
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
-#include "mongo/pch.h"
+#include "mongo/platform/basic.h"
#include "mongo/bson/mutable/document.h"
#include "mongo/bson/mutable/mutable_bson_test_utils.h"
@@ -151,21 +151,20 @@ namespace ReplTests {
return count;
}
int opCount() {
- OperationContextImpl txn;
- ScopedTransaction transaction(&txn, MODE_X);
- Lock::GlobalWrite lk(txn.lockState());
- Client::Context ctx(&txn, cllNS() );
+ ScopedTransaction transaction(&_txn, MODE_X);
+ Lock::GlobalWrite lk(_txn.lockState());
+ Client::Context ctx(&_txn, cllNS() );
Database* db = ctx.db();
- Collection* coll = db->getCollection( &txn, cllNS() );
+ Collection* coll = db->getCollection( &_txn, cllNS() );
if ( !coll ) {
- WriteUnitOfWork wunit(&txn);
- coll = db->createCollection( &txn, cllNS() );
+ WriteUnitOfWork wunit(&_txn);
+ coll = db->createCollection( &_txn, cllNS() );
wunit.commit();
}
int count = 0;
- RecordIterator* it = coll->getIterator(&txn);
+ RecordIterator* it = coll->getIterator(&_txn);
for ( ; !it->isEOF(); it->getNext() ) {
++count;
}