summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/client.cpp19
-rw-r--r--src/mongo/db/client.h7
-rw-r--r--src/mongo/db/clientcursor.cpp5
-rw-r--r--src/mongo/db/clientcursor.h2
-rw-r--r--src/mongo/db/commands/write_commands/batch_executor.cpp6
-rw-r--r--src/mongo/db/curop.cpp71
-rw-r--r--src/mongo/db/curop.h23
-rw-r--r--src/mongo/db/curop_test.cpp15
-rw-r--r--src/mongo/db/dbhelpers.cpp2
-rw-r--r--src/mongo/db/instance.cpp14
-rw-r--r--src/mongo/db/operation_context_impl.cpp17
-rw-r--r--src/mongo/db/query/find.cpp2
-rw-r--r--src/mongo/db/service_context_d.cpp10
-rw-r--r--src/mongo/dbtests/query_stage_update.cpp4
-rw-r--r--src/mongo/dbtests/querytests.cpp2
15 files changed, 127 insertions, 72 deletions
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index c408723d462..6fe85d249e2 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -111,8 +111,6 @@ namespace mongo {
_connectionId(p ? p->connectionId() : 0),
_inDirectClient(false),
_txn(NULL) {
-
- _curOp = new CurOp( this );
}
Client::~Client() {
@@ -122,13 +120,6 @@ namespace mongo {
boost::lock_guard<boost::mutex> clientLock(clientsMutex);
clients.erase(this);
}
-
- CurOp* last;
- do {
- last = _curOp;
- delete _curOp;
- // _curOp may have been reset to _curOp->_wrapped
- } while (_curOp != last);
}
}
@@ -167,9 +158,13 @@ namespace mongo {
}
string Client::clientAddress(bool includePort) const {
- if( _curOp )
- return _curOp->getRemoteString(includePort);
- return "";
+ if (!hasRemote()) {
+ return "";
+ }
+ if (includePort) {
+ return getRemote().toString();
+ }
+ return getRemote().host();
}
ClientBasic* ClientBasic::getCurrent() {
diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h
index 5b11d057e99..b2a6dbf6950 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -49,7 +49,6 @@
namespace mongo {
- class CurOp;
class Collection;
class AbstractMessagingPort;
@@ -98,7 +97,6 @@ namespace mongo {
bool shutdown();
std::string clientAddress(bool includePort = false) const;
- CurOp* curop() const { return _curOp; }
const std::string& desc() const { return _desc; }
void reportState(BSONObjBuilder& builder);
@@ -122,8 +120,6 @@ namespace mongo {
bool isFromUserConnection() const { return _connectionId > 0; }
private:
- friend class CurOp;
-
Client(const std::string& desc,
ServiceContext* serviceContext,
AbstractMessagingPort *p = 0);
@@ -146,9 +142,6 @@ namespace mongo {
// 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;
};
/** get the Client object for this thread. */
diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp
index 26bea429d2a..9fc4c309aa5 100644
--- a/src/mongo/db/clientcursor.cpp
+++ b/src/mongo/db/clientcursor.cpp
@@ -44,7 +44,6 @@
#include "mongo/db/commands.h"
#include "mongo/db/commands/server_status.h"
#include "mongo/db/commands/server_status_metric.h"
-#include "mongo/db/curop.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/operation_context_impl.h"
#include "mongo/db/repl/repl_client_info.h"
@@ -182,13 +181,13 @@ namespace mongo {
_idleAgeMillis = millis;
}
- void ClientCursor::updateSlaveLocation(OperationContext* txn, CurOp& curop) {
+ void ClientCursor::updateSlaveLocation(OperationContext* txn) {
if (_slaveReadTill.isNull())
return;
verify(str::startsWith(_ns.c_str(), "local.oplog."));
- Client* c = curop.getClient();
+ Client* c = txn->getClient();
verify(c);
OID rid = repl::ReplClientInfo::forClient(c).getRemoteID();
if (!rid.isSet())
diff --git a/src/mongo/db/clientcursor.h b/src/mongo/db/clientcursor.h
index c5b8629d675..554fb0e7076 100644
--- a/src/mongo/db/clientcursor.h
+++ b/src/mongo/db/clientcursor.h
@@ -135,7 +135,7 @@ namespace mongo {
// Replication-related stuff. TODO: Document and clean.
//
- void updateSlaveLocation(OperationContext* txn, CurOp& curop);
+ void updateSlaveLocation(OperationContext* txn);
void slaveReadTill( const OpTime& t ) { _slaveReadTill = t; }
/** Just for testing. */
OpTime getSlaveReadTill() const { return _slaveReadTill; }
diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp
index cd03c645c32..fceb7bd042c 100644
--- a/src/mongo/db/commands/write_commands/batch_executor.cpp
+++ b/src/mongo/db/commands/write_commands/batch_executor.cpp
@@ -922,7 +922,7 @@ namespace mongo {
WriteErrorDetail** error ) {
// BEGIN CURRENT OP
- CurOp currentOp( _txn->getClient(), _txn->getClient()->curop() );
+ CurOp currentOp(_txn->getClient());
beginCurrentOp( &currentOp, _txn->getClient(), updateItem );
incOpStats( updateItem );
@@ -966,7 +966,7 @@ namespace mongo {
// Removes are similar to updates, but page faults are handled externally
// BEGIN CURRENT OP
- CurOp currentOp( _txn->getClient(), _txn->getClient()->curop() );
+ CurOp currentOp(_txn->getClient());
beginCurrentOp( &currentOp, _txn->getClient(), removeItem );
incOpStats( removeItem );
@@ -1165,7 +1165,7 @@ namespace mongo {
void WriteBatchExecutor::execOneInsert(ExecInsertsState* state, WriteErrorDetail** error) {
BatchItemRef currInsertItem(state->request, state->currIndex);
- CurOp currentOp( _txn->getClient(), _txn->getClient()->curop() );
+ CurOp currentOp(_txn->getClient());
beginCurrentOp( &currentOp, _txn->getClient(), currInsertItem );
incOpStats(currInsertItem);
diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp
index 439e0c20921..7d46b032486 100644
--- a/src/mongo/db/curop.cpp
+++ b/src/mongo/db/curop.cpp
@@ -33,12 +33,14 @@
#include "mongo/db/curop.h"
#include "mongo/base/counter.h"
+#include "mongo/base/disallow_copying.h"
#include "mongo/db/client.h"
#include "mongo/db/commands/server_status_metric.h"
#include "mongo/db/catalog/database.h"
#include "mongo/db/service_context.h"
#include "mongo/db/json.h"
#include "mongo/db/stats/top.h"
+#include "mongo/util/exit.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
@@ -46,6 +48,55 @@ namespace mongo {
using std::string;
+ /**
+ * This type decorates a Client object with a stack of active CurOp objects.
+ *
+ * It encapsulates the nesting logic for curops attached to a Client, along with
+ * the notion that there is always a root CurOp attached to a Client.
+ *
+ * The stack itself is represented in the _parent pointers of the CurOp class.
+ */
+ class CurOp::ClientCuropStack {
+ MONGO_DISALLOW_COPYING(ClientCuropStack);
+ public:
+ ClientCuropStack() : _base(this) {}
+
+ /**
+ * Returns the top of the CurOp stack.
+ */
+ CurOp* top() const { return _top; }
+
+ /**
+ * Adds "curOp" to the top of the CurOp stack for a client. Called by CurOp's constructor.
+ */
+ void push(CurOp* curOp) {
+ boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
+ invariant(!curOp->_parent);
+ curOp->_parent = _top;
+ _top = curOp;
+ }
+
+ /**
+ * Pops the top off the CurOp stack for a Client. Called by CurOp's destructor.
+ */
+ CurOp* pop() {
+ boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
+ invariant(_top);
+ CurOp* retval = _top;
+ _top = _top->_parent;
+ return retval;
+ }
+
+ private:
+ // Top of the stack of CurOps for a Client.
+ CurOp* _top = nullptr;
+
+ // The bottom-most CurOp for a client.
+ const CurOp _base;
+ };
+
+ const auto CurOp::_curopStack = Client::declareDecoration<CurOp::ClientCuropStack>();
+
// Enabling the maxTimeAlwaysTimeOut fail point will cause any query or command run with a
// valid non-zero max time to fail immediately. Any getmore operation on a cursor already
// created with a valid non-zero max time will also fail immediately.
@@ -64,12 +115,13 @@ namespace mongo {
fromjson("{\"$msg\":\"query not recording (too large)\"}");
- CurOp::CurOp( Client * client , CurOp * wrapped ) :
- _client(client),
- _wrapped(wrapped)
- {
- if ( _wrapped )
- _client->_curOp = this;
+ CurOp* CurOp::get(const Client* client) { return _curopStack(client).top(); }
+ CurOp* CurOp::get(const Client& client) { return _curopStack(client).top(); }
+
+ CurOp::CurOp(Client* client) : CurOp(&_curopStack(client)) {}
+
+ CurOp::CurOp(ClientCuropStack* stack) : _stack(stack) {
+ _stack->push(this);
_start = 0;
_active = false;
_reset();
@@ -130,11 +182,10 @@ namespace mongo {
}
CurOp::~CurOp() {
- if ( _wrapped ) {
- boost::lock_guard<boost::mutex> clientLock(Client::clientsMutex);
- _client->_curOp = _wrapped;
+ if (!inShutdown()) {
+ // TODO(schwerin): See if there's a reason not to clean up during shutdown.
+ invariant(this == _stack->pop());
}
- _client = 0;
}
void CurOp::setNS( StringData ns ) {
diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h
index 14bea54eab1..0228d2d6a7a 100644
--- a/src/mongo/db/curop.h
+++ b/src/mongo/db/curop.h
@@ -193,7 +193,10 @@ namespace mongo {
*/
class CurOp : boost::noncopyable {
public:
- CurOp( Client * client , CurOp * wrapped = 0 );
+ static CurOp* get(const Client* client);
+ static CurOp* get(const Client& client);
+
+ explicit CurOp(Client* client);
~CurOp();
bool haveQuery() const { return _query.have(); }
@@ -278,11 +281,10 @@ namespace mongo {
int elapsedSeconds() { return elapsedMillis() / 1000; }
void setQuery(const BSONObj& query) { _query.set( query ); }
- Client * getClient() const { return _client; }
-
+
Command * getCommand() const { return _command; }
void setCommand(Command* command) { _command = command; }
-
+
void reportState(BSONObjBuilder* builder);
// Fetches less information than "info()"; used to search for ops with certain criteria
@@ -300,7 +302,7 @@ namespace mongo {
int secondsBetween = 3);
std::string getMessage() const { return _message.toString(); }
ProgressMeter& getProgressMeter() { return _progressMeter; }
- CurOp *parent() const { return _wrapped; }
+ CurOp *parent() const { return _parent; }
void kill();
bool killPendingStrict() const { return _killPending.load(); }
bool killPending() const { return _killPending.loadRelaxed(); }
@@ -320,12 +322,17 @@ namespace mongo {
void setNS( StringData ns );
private:
- friend class Client;
+ class ClientCuropStack;
+
+ static const Client::Decoration<ClientCuropStack> _curopStack;
+
+ explicit CurOp(ClientCuropStack*);
+
void _reset();
static AtomicUInt32 _nextOpNum;
- Client * _client;
- CurOp * _wrapped;
+ ClientCuropStack* _stack;
+ CurOp* _parent = nullptr;
Command * _command;
long long _start;
long long _end;
diff --git a/src/mongo/db/curop_test.cpp b/src/mongo/db/curop_test.cpp
index f8682c79481..85ad5d98973 100644
--- a/src/mongo/db/curop_test.cpp
+++ b/src/mongo/db/curop_test.cpp
@@ -31,7 +31,14 @@
#include <boost/thread/thread.hpp>
#include "mongo/base/init.h"
+#include "mongo/db/auth/authorization_manager.h"
+#include "mongo/db/auth/authorization_manager_global.h"
+#include "mongo/db/auth/authz_manager_external_state_mock.h"
+#include "mongo/db/client.h"
#include "mongo/db/curop.h"
+#include "mongo/db/service_context.h"
+#include "mongo/db/service_context_noop.h"
+#include "mongo/stdx/memory.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -67,12 +74,16 @@ namespace mongo {
sleepmillis(10);
}
+ setGlobalServiceContext(stdx::make_unique<ServiceContextNoop>());
+ setGlobalAuthorizationManager(
+ new AuthorizationManager(new AuthzManagerExternalStateMock()));
+ Client::initThread("CurOpTestMain");
return Status::OK();
}
// Long operation + short timeout => time should expire.
TEST(TimeHasExpired, PosSimple) {
- CurOp curOp(NULL);
+ CurOp curOp(&cc());
curOp.setMaxTimeMicros(intervalShort);
curOp.ensureStarted();
sleepmicros(intervalLong);
@@ -81,7 +92,7 @@ namespace mongo {
// Short operation + long timeout => time should not expire.
TEST(TimeHasExpired, NegSimple) {
- CurOp curOp(NULL);
+ CurOp curOp(&cc());
curOp.setMaxTimeMicros(intervalLong);
curOp.ensureStarted();
sleepmicros(intervalShort);
diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp
index d74d74f493c..f9fb4f0d33a 100644
--- a/src/mongo/db/dbhelpers.cpp
+++ b/src/mongo/db/dbhelpers.cpp
@@ -270,7 +270,7 @@ namespace mongo {
update(txn, context.db(), request, &debug);
- txn->getClient()->curop()->done();
+ CurOp::get(txn->getClient())->done();
}
BSONObj Helpers::toKeyFormat( const BSONObj& o ) {
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index f5efc2938d4..1c49b54c3a1 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -217,7 +217,7 @@ namespace {
DbMessage dbMessage(message);
QueryMessage queryMessage(dbMessage);
- CurOp* op = client.curop();
+ CurOp* op = CurOp::get(client);
std::unique_ptr<Message> response(new Message());
@@ -325,7 +325,7 @@ namespace {
QueryMessage q(d);
auto_ptr< Message > resp( new Message() );
- CurOp& op = *(c.curop());
+ CurOp& op = *CurOp::get(c);
try {
Client* client = txn->getClient();
@@ -436,15 +436,13 @@ namespace {
globalOpCounters.gotDelete();
break;
}
-
+
scoped_ptr<CurOp> nestedOp;
- CurOp* currentOpP = c.curop();
- if ( currentOpP->active() ) {
- nestedOp.reset( new CurOp( &c , currentOpP ) );
- currentOpP = nestedOp.get();
+ if (CurOp::get(c)->active()) {
+ nestedOp.reset(new CurOp(&c));
}
- CurOp& currentOp = *currentOpP;
+ CurOp& currentOp = *CurOp::get(c);
currentOp.reset(remote,op);
OpDebug& debug = currentOp.debug();
diff --git a/src/mongo/db/operation_context_impl.cpp b/src/mongo/db/operation_context_impl.cpp
index 8c7a793ca86..9bb5cc6af60 100644
--- a/src/mongo/db/operation_context_impl.cpp
+++ b/src/mongo/db/operation_context_impl.cpp
@@ -126,7 +126,7 @@ namespace {
}
CurOp* OperationContextImpl::getCurOp() const {
- return getClient()->curop();
+ return CurOp::get(getClient());
}
unsigned int OperationContextImpl::getOpID() const {
@@ -162,7 +162,7 @@ namespace {
}
// Only target nested operations if requested.
- if (!failPointInfo["allowNested"].trueValue() && c.curop()->parent() != NULL) {
+ if (!failPointInfo["allowNested"].trueValue() && CurOp::get(c)->parent() != NULL) {
return false;
}
@@ -192,20 +192,21 @@ namespace {
}
Client* c = getClient();
- if (c->curop()->maxTimeHasExpired()) {
- c->curop()->kill();
+ if (CurOp::get(c)->maxTimeHasExpired()) {
+ CurOp::get(c)->kill();
return Status(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();
+ log() << "set pending kill on "
+ << (CurOp::get(c)->parent() ? "nested" : "top-level")
+ << " op " << CurOp::get(c)->opNum() << ", for checkForInterruptFail";
+ CurOp::get(c)->kill();
}
}
- if (c->curop()->killPending()) {
+ if (CurOp::get(c)->killPending()) {
return Status(ErrorCodes::Interrupted, "operation was interrupted");
}
diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp
index 9875b0c4a24..fb6218fc800 100644
--- a/src/mongo/db/query/find.cpp
+++ b/src/mongo/db/query/find.cpp
@@ -368,7 +368,7 @@ namespace mongo {
txn->checkForInterrupt(); // May trigger maxTimeAlwaysTimeOut fail point.
if (0 == pass) {
- cc->updateSlaveLocation(txn, curop);
+ cc->updateSlaveLocation(txn);
}
if (cc->isAggCursor()) {
diff --git a/src/mongo/db/service_context_d.cpp b/src/mongo/db/service_context_d.cpp
index 4c3d30032df..50a9b660394 100644
--- a/src/mongo/db/service_context_d.cpp
+++ b/src/mongo/db/service_context_d.cpp
@@ -187,12 +187,12 @@ namespace mongo {
bool ServiceContextMongoD::_killOperationsAssociatedWithClientAndOpId_inlock(
Client* client, unsigned int opId) {
- for( CurOp *k = client->curop(); k; k = k->parent() ) {
+ for( CurOp *k = CurOp::get(client); k; k = k->parent() ) {
if ( k->opNum() != opId )
continue;
k->kill();
- for( CurOp *l = client->curop(); l; l = l->parent() ) {
+ for( CurOp *l = CurOp::get(client); l; l = l->parent() ) {
l->kill();
}
@@ -237,15 +237,15 @@ namespace mongo {
continue;
}
- if (client->curop()->opNum() == txn->getOpID()) {
+ if (CurOp::get(client)->opNum() == txn->getOpID()) {
// Don't kill ourself.
continue;
}
bool found = _killOperationsAssociatedWithClientAndOpId_inlock(
- client, client->curop()->opNum());
+ client, CurOp::get(client)->opNum());
if (!found) {
- warning() << "Attempted to kill operation " << client->curop()->opNum()
+ warning() << "Attempted to kill operation " << CurOp::get(client)->opNum()
<< " but the opId changed";
}
}
diff --git a/src/mongo/dbtests/query_stage_update.cpp b/src/mongo/dbtests/query_stage_update.cpp
index 752cb6d7dc5..0d118a64066 100644
--- a/src/mongo/dbtests/query_stage_update.cpp
+++ b/src/mongo/dbtests/query_stage_update.cpp
@@ -189,7 +189,7 @@ namespace QueryStageUpdate {
{
OldClientWriteContext ctx(&_txn, ns());
Client& c = cc();
- CurOp& curOp = *c.curop();
+ CurOp& curOp = *CurOp::get(c);
OpDebug* opDebug = &curOp.debug();
UpdateDriver driver( (UpdateDriver::Options()) );
Collection* collection = ctx.getCollection();
@@ -258,7 +258,7 @@ namespace QueryStageUpdate {
ASSERT_EQUALS(10U, count(BSONObj()));
Client& c = cc();
- CurOp& curOp = *c.curop();
+ CurOp& curOp = *CurOp::get(c);
OpDebug* opDebug = &curOp.debug();
UpdateDriver driver( (UpdateDriver::Options()) );
Database* db = ctx.db();
diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp
index 4ce39171757..eb5cf7402f9 100644
--- a/src/mongo/dbtests/querytests.cpp
+++ b/src/mongo/dbtests/querytests.cpp
@@ -1509,7 +1509,7 @@ namespace QueryTests {
DbMessage dbMessage( message );
QueryMessage queryMessage( dbMessage );
Message result;
- string exhaust = runQuery(&_txn, queryMessage, NamespaceString(ns()), *cc().curop(),
+ string exhaust = runQuery(&_txn, queryMessage, NamespaceString(ns()), *CurOp::get(cc()),
result);
ASSERT( exhaust.size() );
ASSERT_EQUALS( string( ns() ), exhaust );