summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorAndy Schwerin <schwerin@mongodb.com>2015-06-04 18:32:23 -0400
committerAndy Schwerin <schwerin@mongodb.com>2015-06-05 14:21:57 -0400
commit6c2a61091396087f85c58bd6298519688a98e5d8 (patch)
tree201822868554014a882b85a86cb3e291ba6acf4a /src/mongo/db
parent54040db4fa000284cb1148b93e85f81c54ca12d6 (diff)
downloadmongo-6c2a61091396087f85c58bd6298519688a98e5d8.tar.gz
SERVER-18515 Put OperationContext into mongos client request path.
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/auth/auth_decorations.cpp8
-rw-r--r--src/mongo/db/client.cpp4
-rw-r--r--src/mongo/db/client.h6
-rw-r--r--src/mongo/db/dbwebserver.cpp8
-rw-r--r--src/mongo/db/range_deleter.cpp8
-rw-r--r--src/mongo/db/range_deleter.h2
-rw-r--r--src/mongo/db/range_deleter_db_env.cpp4
-rw-r--r--src/mongo/db/range_deleter_db_env.h2
-rw-r--r--src/mongo/db/range_deleter_mock_env.h2
-rw-r--r--src/mongo/db/repl/sync_source_feedback.cpp2
-rw-r--r--src/mongo/db/service_context.cpp57
-rw-r--r--src/mongo/db/service_context.h59
-rw-r--r--src/mongo/db/service_context_d.cpp3
-rw-r--r--src/mongo/db/service_context_d.h34
-rw-r--r--src/mongo/db/service_context_noop.cpp4
-rw-r--r--src/mongo/db/service_context_noop.h37
16 files changed, 171 insertions, 69 deletions
diff --git a/src/mongo/db/auth/auth_decorations.cpp b/src/mongo/db/auth/auth_decorations.cpp
index 31b1c49d9df..cbd4ca3083a 100644
--- a/src/mongo/db/auth/auth_decorations.cpp
+++ b/src/mongo/db/auth/auth_decorations.cpp
@@ -70,13 +70,17 @@ namespace {
class AuthzClientObserver final : public ServiceContext::ClientObserver {
public:
- void onCreateClient(ServiceContext* service, Client* client) override {
+ void onCreateClient(Client* client) override {
+ auto service = client->getServiceContext();
AuthorizationSession::set(
client,
AuthorizationManager::get(service)->makeAuthorizationSession());
}
- void onDestroyClient(ServiceContext* service, Client* client) override {}
+ void onDestroyClient(Client* client) override {}
+
+ void onCreateOperationContext(OperationContext* opCtx) override {}
+ void onDestroyOperationContext(OperationContext* opCtx) override {}
};
} // namespace
diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp
index a7d3de69b16..8ab9a7995f3 100644
--- a/src/mongo/db/client.cpp
+++ b/src/mongo/db/client.cpp
@@ -114,6 +114,10 @@ namespace mongo {
}
}
+ ServiceContext::UniqueOperationContext Client::makeOperationContext() {
+ return getServiceContext()->makeOperationContext(this);
+ }
+
void Client::setOperationContext(OperationContext* txn) {
// We can only set the OperationContext once before resetting it.
invariant(txn != NULL && _txn == NULL);
diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h
index 597ed07dd70..251fce3b6d6 100644
--- a/src/mongo/db/client.h
+++ b/src/mongo/db/client.h
@@ -87,6 +87,12 @@ namespace mongo {
void unlock() { _lock.unlock(); }
/**
+ * Makes a new operation context representing an operation on this client. At most
+ * one operation context may be in scope on a client at a time.
+ */
+ ServiceContext::UniqueOperationContext makeOperationContext();
+
+ /**
* Sets the active operation context on this client to "txn", which must be non-NULL.
*
* It is an error to call this method if there is already an operation context on Client.
diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp
index 054e4a334d2..dadf01d432d 100644
--- a/src/mongo/db/dbwebserver.cpp
+++ b/src/mongo/db/dbwebserver.cpp
@@ -313,7 +313,8 @@ namespace {
vector<string>& headers,
const SockAddr &from) {
- auto txn = getGlobalServiceContext()->newOpCtx();
+ Client* client = &cc();
+ auto txn = client->makeOperationContext();
if (url.size() > 1) {
@@ -437,7 +438,7 @@ namespace {
vector<string>& headers,
const SockAddr &from) {
- AuthorizationSession* authSess = AuthorizationSession::get(cc());
+ AuthorizationSession* authSess = AuthorizationSession::get(txn->getClient());
if (!authSess->getAuthorizationManager().isAuthEnabled()) {
return true;
}
@@ -464,8 +465,7 @@ namespace {
// Only users in the admin DB are visible by the webserver
UserName userName(parms["username"], "admin");
User* user;
- AuthorizationManager& authzManager =
- AuthorizationSession::get(cc())->getAuthorizationManager();
+ AuthorizationManager& authzManager = authSess->getAuthorizationManager();
Status status = authzManager.acquireUser(txn, userName, &user);
if (!status.isOK()) {
if (status.code() != ErrorCodes::UserNotFound) {
diff --git a/src/mongo/db/range_deleter.cpp b/src/mongo/db/range_deleter.cpp
index cb00ad28554..6eefd436274 100644
--- a/src/mongo/db/range_deleter.cpp
+++ b/src/mongo/db/range_deleter.cpp
@@ -35,6 +35,7 @@
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <memory>
+#include "mongo/db/client.h"
#include "mongo/db/service_context.h"
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/write_concern_options.h"
@@ -443,7 +444,8 @@ namespace {
}
void RangeDeleter::doWork() {
- _env->initThread();
+ Client::initThreadIfNotAlready("RangeDeleter");
+ Client* client = &cc();
while (!inShutdown() && !stopRequested()) {
string errMsg;
@@ -471,7 +473,7 @@ namespace {
set<CursorId> cursorsNow;
if (entry->options.waitForOpenCursors) {
- auto txn = getGlobalServiceContext()->newOpCtx();
+ auto txn = client->makeOperationContext();
_env->getCursorIds(txn.get(),
entry->options.range.ns,
&cursorsNow);
@@ -513,7 +515,7 @@ namespace {
}
{
- auto txn = getGlobalServiceContext()->newOpCtx();
+ auto txn = client->makeOperationContext();
nextTask->stats.deleteStartTS = jsTime();
bool delResult = _env->deleteRange(txn.get(),
*nextTask,
diff --git a/src/mongo/db/range_deleter.h b/src/mongo/db/range_deleter.h
index a1a9bb97a2c..69957229872 100644
--- a/src/mongo/db/range_deleter.h
+++ b/src/mongo/db/range_deleter.h
@@ -306,8 +306,6 @@ namespace mongo {
struct RangeDeleterEnv {
virtual ~RangeDeleterEnv() {}
- virtual void initThread() = 0;
-
/**
* Deletes the documents from the given range. This method should be
* responsible for making sure that the proper contexts are setup
diff --git a/src/mongo/db/range_deleter_db_env.cpp b/src/mongo/db/range_deleter_db_env.cpp
index c84818158c2..2641147b26c 100644
--- a/src/mongo/db/range_deleter_db_env.cpp
+++ b/src/mongo/db/range_deleter_db_env.cpp
@@ -49,10 +49,6 @@ namespace mongo {
using std::endl;
using std::string;
- void RangeDeleterDBEnv::initThread() {
- Client::initThreadIfNotAlready("RangeDeleter");
- }
-
/**
* Outline of the delete process:
* 1. Initialize the client for this thread if there is no client. This is for the worker
diff --git a/src/mongo/db/range_deleter_db_env.h b/src/mongo/db/range_deleter_db_env.h
index df04674faef..176399511d5 100644
--- a/src/mongo/db/range_deleter_db_env.h
+++ b/src/mongo/db/range_deleter_db_env.h
@@ -37,8 +37,6 @@ namespace mongo {
*/
struct RangeDeleterDBEnv : public RangeDeleterEnv {
- virtual void initThread();
-
/**
* Deletes the documents from the given range synchronously.
*
diff --git a/src/mongo/db/range_deleter_mock_env.h b/src/mongo/db/range_deleter_mock_env.h
index b6c802b6354..02eebb341ab 100644
--- a/src/mongo/db/range_deleter_mock_env.h
+++ b/src/mongo/db/range_deleter_mock_env.h
@@ -59,8 +59,6 @@ namespace mongo {
public:
RangeDeleterMockEnv();
- void initThread() {}
-
//
// Environment modification methods.
//
diff --git a/src/mongo/db/repl/sync_source_feedback.cpp b/src/mongo/db/repl/sync_source_feedback.cpp
index f11e420612a..960fd92ac6c 100644
--- a/src/mongo/db/repl/sync_source_feedback.cpp
+++ b/src/mongo/db/repl/sync_source_feedback.cpp
@@ -173,7 +173,7 @@ namespace repl {
_positionChanged = false;
}
- auto txn = cc().getServiceContext()->newOpCtx();
+ auto txn = cc().makeOperationContext();
MemberState state = replCoord->getMemberState();
if (state.primary() || state.startup()) {
_resetConnection();
diff --git a/src/mongo/db/service_context.cpp b/src/mongo/db/service_context.cpp
index a1d38162c5e..175702aebad 100644
--- a/src/mongo/db/service_context.cpp
+++ b/src/mongo/db/service_context.cpp
@@ -120,14 +120,14 @@ namespace mongo {
auto observer = _clientObservers.cbegin();
try {
for (; observer != _clientObservers.cend(); ++observer) {
- observer->get()->onCreateClient(this, client.get());
+ observer->get()->onCreateClient(client.get());
}
}
catch (...) {
try {
while (observer != _clientObservers.cbegin()) {
--observer;
- observer->get()->onDestroyClient(this, client.get());
+ observer->get()->onDestroyClient(client.get());
}
}
catch (...) {
@@ -150,7 +150,7 @@ namespace mongo {
}
try {
for (const auto& observer : service->_clientObservers) {
- observer->onDestroyClient(service, client);
+ observer->onDestroyClient(client);
}
}
catch (...) {
@@ -159,6 +159,57 @@ namespace mongo {
delete client;
}
+ ServiceContext::UniqueOperationContext ServiceContext::makeOperationContext(Client* client) {
+ auto opCtx = _newOpCtx(client);
+ auto observer = _clientObservers.begin();
+ try {
+ for (; observer != _clientObservers.cend(); ++observer) {
+ observer->get()->onCreateOperationContext(opCtx.get());
+ }
+ }
+ catch (...) {
+ try {
+ while (observer != _clientObservers.cbegin()) {
+ --observer;
+ observer->get()->onDestroyOperationContext(opCtx.get());
+ }
+ }
+ catch (...) {
+ std::terminate();
+ }
+ throw;
+ }
+ // // TODO(schwerin): When callers no longer construct their own OperationContexts directly,
+ // // but only through the ServiceContext, uncomment the following. Until then, it must
+ // // be done in the operation context destructors, which introduces a potential race.
+ // {
+ // stdx::lock_guard<Client> lk(*client);
+ // client->setOperationContext(opCtx.get());
+ // }
+ return UniqueOperationContext(opCtx.release());
+ };
+
+ void ServiceContext::OperationContextDeleter::operator()(OperationContext* opCtx) const {
+ auto client = opCtx->getClient();
+ auto service = client->getServiceContext();
+ // // TODO(schwerin): When callers no longer construct their own OperationContexts directly,
+ // // but only through the ServiceContext, uncomment the following. Until then, it must
+ // // be done in the operation context destructors, which introduces a potential race.
+ // {
+ // stdx::lock_guard<Client> lk(*client);
+ // client->resetOperationContext();
+ // }
+ try {
+ for (const auto& observer : service->_clientObservers) {
+ observer->onDestroyOperationContext(opCtx);
+ }
+ }
+ catch (...) {
+ std::terminate();
+ }
+ delete opCtx;
+ }
+
void ServiceContext::registerClientObserver(std::unique_ptr<ClientObserver> observer) {
_clientObservers.push_back(std::move(observer));
}
diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h
index 675b9dfd1ae..3153558f63b 100644
--- a/src/mongo/db/service_context.h
+++ b/src/mongo/db/service_context.h
@@ -94,28 +94,46 @@ namespace mongo {
};
/**
- * Observer interface implemented to hook client creation and destruction.
+ * Observer interface implemented to hook client and operation context creation and
+ * destruction.
*/
class ClientObserver {
public:
virtual ~ClientObserver() = default;
/**
- * Hook called after a new client "client" is created on "service" by
+ * Hook called after a new client "client" is created on a service by
* service->makeClient().
*
* For a given client and registered instance of ClientObserver, if onCreateClient
* returns without throwing an exception, onDestroyClient will be called when "client"
* is deleted.
*/
- virtual void onCreateClient(ServiceContext* service, Client* client) = 0;
+ virtual void onCreateClient(Client* client) = 0;
/**
- * Hook called on a "client" created by "service" before deleting "client".
+ * Hook called on a "client" created by a service before deleting "client".
*
* Like a destructor, must not throw exceptions.
*/
- virtual void onDestroyClient(ServiceContext* service, Client* client) = 0;
+ virtual void onDestroyClient(Client* client) = 0;
+
+ /**
+ * Hook called after a new operation context is created on a client by
+ * service->makeOperationContext(client) or client->makeOperationContext().
+ *
+ * For a given operation context and registered instance of ClientObserver, if
+ * onCreateOperationContext returns without throwing an exception,
+ * onDestroyOperationContext will be called when "opCtx" is deleted.
+ */
+ virtual void onCreateOperationContext(OperationContext* opCtx) = 0;
+
+ /**
+ * Hook called on a "opCtx" created by a service before deleting "opCtx".
+ *
+ * Like a destructor, must not throw exceptions.
+ */
+ virtual void onDestroyOperationContext(OperationContext* opCtx) = 0;
};
using ClientSet = unordered_set<Client*>;
@@ -145,10 +163,24 @@ namespace mongo {
};
/**
+ * Special deleter used for cleaning up OperationContext objects owned by a ServiceContext.
+ * See UniqueOperationContext, below.
+ */
+ class OperationContextDeleter {
+ public:
+ void operator()(OperationContext* opCtx) const;
+ };
+
+ /**
* This is the unique handle type for Clients created by a ServiceContext.
*/
using UniqueClient = std::unique_ptr<Client, ClientDeleter>;
+ /**
+ * This is the unique handle type for OperationContexts created by a ServiceContext.
+ */
+ using UniqueOperationContext = std::unique_ptr<OperationContext, OperationContextDeleter>;
+
virtual ~ServiceContext();
/**
@@ -172,6 +204,13 @@ namespace mongo {
*/
UniqueClient makeClient(std::string desc, AbstractMessagingPort* p = nullptr);
+ /**
+ * Creates a new OperationContext on "client".
+ *
+ * "client" must not have an active operation context.
+ */
+ UniqueOperationContext makeOperationContext(Client* client);
+
//
// Storage
//
@@ -250,11 +289,6 @@ namespace mongo {
*/
virtual void registerKillOpListener(KillOpListenerInterface* listener) = 0;
- /**
- * Returns a new OperationContext.
- */
- virtual std::unique_ptr<OperationContext> newOpCtx() = 0;
-
//
// Global OpObserver.
//
@@ -280,6 +314,11 @@ namespace mongo {
private:
/**
+ * Returns a new OperationContext. Private, for use by makeOperationContext.
+ */
+ virtual std::unique_ptr<OperationContext> _newOpCtx(Client* client) = 0;
+
+ /**
* Vector of registered observers.
*/
std::vector<std::unique_ptr<ClientObserver>> _clientObservers;
diff --git a/src/mongo/db/service_context_d.cpp b/src/mongo/db/service_context_d.cpp
index de3b418e694..f02423a9e1a 100644
--- a/src/mongo/db/service_context_d.cpp
+++ b/src/mongo/db/service_context_d.cpp
@@ -290,7 +290,8 @@ namespace mongo {
_killOpListeners.push_back(listener);
}
- std::unique_ptr<OperationContext> ServiceContextMongoD::newOpCtx() {
+ std::unique_ptr<OperationContext> ServiceContextMongoD::_newOpCtx(Client* client) {
+ invariant(&cc() == client);
return stdx::make_unique<OperationContextImpl>();
}
diff --git a/src/mongo/db/service_context_d.h b/src/mongo/db/service_context_d.h
index 14ec7dc475d..972063c147b 100644
--- a/src/mongo/db/service_context_d.h
+++ b/src/mongo/db/service_context_d.h
@@ -39,7 +39,7 @@ namespace mongo {
class Client;
class StorageEngineLockFile;
- class ServiceContextMongoD : public ServiceContext {
+ class ServiceContextMongoD final : public ServiceContext {
public:
typedef std::map<std::string, const StorageEngine::Factory*> FactoryMap;
@@ -47,39 +47,39 @@ namespace mongo {
~ServiceContextMongoD();
- StorageEngine* getGlobalStorageEngine();
+ StorageEngine* getGlobalStorageEngine() override;
- void initializeGlobalStorageEngine();
+ void initializeGlobalStorageEngine() override;
- void shutdownGlobalStorageEngineCleanly();
+ void shutdownGlobalStorageEngineCleanly() override;
void registerStorageEngine(const std::string& name,
- const StorageEngine::Factory* factory);
+ const StorageEngine::Factory* factory) override;
- bool isRegisteredStorageEngine(const std::string& name);
+ bool isRegisteredStorageEngine(const std::string& name) override;
- StorageFactoriesIterator* makeStorageFactoriesIterator();
+ StorageFactoriesIterator* makeStorageFactoriesIterator() override;
- void setKillAllOperations();
+ void setKillAllOperations() override;
- void unsetKillAllOperations();
+ void unsetKillAllOperations() override;
- bool getKillAllOperations();
+ bool getKillAllOperations() override;
- bool killOperation(unsigned int opId);
+ bool killOperation(unsigned int opId) override;
- void killAllUserOperations(const OperationContext* txn);
+ void killAllUserOperations(const OperationContext* txn) override;
- void registerKillOpListener(KillOpListenerInterface* listener);
+ void registerKillOpListener(KillOpListenerInterface* listener) override;
- std::unique_ptr<OperationContext> newOpCtx();
+ void setOpObserver(std::unique_ptr<OpObserver> opObserver) override;
- void setOpObserver(std::unique_ptr<OpObserver> opObserver);
-
- OpObserver* getOpObserver();
+ OpObserver* getOpObserver() override;
private:
+ std::unique_ptr<OperationContext> _newOpCtx(Client* client) override;
+
/**
* Kills the active operation on "client" if that operation is associated with operation id
* "opId".
diff --git a/src/mongo/db/service_context_noop.cpp b/src/mongo/db/service_context_noop.cpp
index 87bff0c7932..d4ad381172c 100644
--- a/src/mongo/db/service_context_noop.cpp
+++ b/src/mongo/db/service_context_noop.cpp
@@ -82,8 +82,8 @@ namespace mongo {
void ServiceContextNoop::registerKillOpListener(KillOpListenerInterface* listener) {
}
- std::unique_ptr<OperationContext> ServiceContextNoop::newOpCtx() {
- return stdx::make_unique<OperationContextNoop>();
+ std::unique_ptr<OperationContext> ServiceContextNoop::_newOpCtx(Client* client) {
+ return stdx::make_unique<OperationContextNoop>(client, _nextOpId.fetchAndAdd(1));
}
void ServiceContextNoop::setOpObserver(std::unique_ptr<OpObserver> opObserver) {
diff --git a/src/mongo/db/service_context_noop.h b/src/mongo/db/service_context_noop.h
index 833c37f975a..8cf85865f21 100644
--- a/src/mongo/db/service_context_noop.h
+++ b/src/mongo/db/service_context_noop.h
@@ -28,40 +28,45 @@
#include "mongo/db/service_context.h"
+#include "mongo/platform/atomic_word.h"
+
namespace mongo {
- class ServiceContextNoop : public ServiceContext {
+ class ServiceContextNoop final : public ServiceContext {
public:
- StorageEngine* getGlobalStorageEngine();
+ StorageEngine* getGlobalStorageEngine() override;
- void initializeGlobalStorageEngine();
+ void initializeGlobalStorageEngine() override;
- void shutdownGlobalStorageEngineCleanly();
+ void shutdownGlobalStorageEngineCleanly() override;
void registerStorageEngine(const std::string& name,
- const StorageEngine::Factory* factory);
+ const StorageEngine::Factory* factory) override;
+
+ bool isRegisteredStorageEngine(const std::string& name) override;
- bool isRegisteredStorageEngine(const std::string& name);
+ StorageFactoriesIterator* makeStorageFactoriesIterator() override;
- StorageFactoriesIterator* makeStorageFactoriesIterator();
+ bool killOperation(unsigned int opId) override;
- bool killOperation(unsigned int opId);
+ void killAllUserOperations(const OperationContext* txn) override;
- void killAllUserOperations(const OperationContext* txn);
+ void setKillAllOperations() override;
- void setKillAllOperations();
+ void unsetKillAllOperations() override;
- void unsetKillAllOperations();
+ bool getKillAllOperations() override;
- bool getKillAllOperations();
+ void registerKillOpListener(KillOpListenerInterface* listener) override;
- void registerKillOpListener(KillOpListenerInterface* listener);
+ std::unique_ptr<OperationContext> _newOpCtx(Client* client) override;
- std::unique_ptr<OperationContext> newOpCtx();
+ void setOpObserver(std::unique_ptr<OpObserver> opObserver) override;
- void setOpObserver(std::unique_ptr<OpObserver> opObserver);
+ OpObserver* getOpObserver() override;
- OpObserver* getOpObserver();
+ private:
+ AtomicUInt32 _nextOpId{1};
};
} // namespace mongo