diff options
-rw-r--r-- | src/mongo/db/client.cpp | 9 | ||||
-rw-r--r-- | src/mongo/db/client.h | 17 | ||||
-rw-r--r-- | src/mongo/db/clientlistplugin.cpp | 203 | ||||
-rw-r--r-- | src/mongo/db/currentop_command.cpp | 139 | ||||
-rw-r--r-- | src/mongo/db/global_environment_d.cpp | 35 | ||||
-rw-r--r-- | src/mongo/db/global_environment_d.h | 12 | ||||
-rw-r--r-- | src/mongo/db/global_environment_experiment.h | 42 | ||||
-rw-r--r-- | src/mongo/db/global_environment_noop.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/global_environment_noop.h | 6 | ||||
-rw-r--r-- | src/mongo/db/operation_context_impl.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/stats/lock_server_status_section.cpp | 122 | ||||
-rw-r--r-- | src/mongo/dbtests/repltests.cpp | 17 |
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; } |