diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2015-06-04 18:32:23 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2015-06-05 14:21:57 -0400 |
commit | 6c2a61091396087f85c58bd6298519688a98e5d8 (patch) | |
tree | 201822868554014a882b85a86cb3e291ba6acf4a /src/mongo/db | |
parent | 54040db4fa000284cb1148b93e85f81c54ca12d6 (diff) | |
download | mongo-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.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/client.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/client.h | 6 | ||||
-rw-r--r-- | src/mongo/db/dbwebserver.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/range_deleter.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/range_deleter.h | 2 | ||||
-rw-r--r-- | src/mongo/db/range_deleter_db_env.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/range_deleter_db_env.h | 2 | ||||
-rw-r--r-- | src/mongo/db/range_deleter_mock_env.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/sync_source_feedback.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/service_context.cpp | 57 | ||||
-rw-r--r-- | src/mongo/db/service_context.h | 59 | ||||
-rw-r--r-- | src/mongo/db/service_context_d.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/service_context_d.h | 34 | ||||
-rw-r--r-- | src/mongo/db/service_context_noop.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/service_context_noop.h | 37 |
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 |