diff options
author | Andy Schwerin <schwerin@mongodb.com> | 2018-06-22 12:00:21 -0400 |
---|---|---|
committer | Andy Schwerin <schwerin@mongodb.com> | 2018-06-22 12:32:29 -0400 |
commit | d520be0814492c262515cf0a5d62a127ace70dce (patch) | |
tree | e754e3cce243a7b51922b6d2a179a3d355ccefb7 /src/mongo/db/service_context.h | |
parent | c0b942e3a80b9ccd8434ab0927d97cbd1862d19a (diff) | |
download | mongo-d520be0814492c262515cf0a5d62a127ace70dce.tar.gz |
SERVER-34798 Remove ServiceContext subclasses and use new ServiceContext in every unit test.
This patch does several loosely related and surprisingly hard to separate things.
1.) Make the ServiceContext class final
2.) Create a mechanism, called ConstructorActions, for running methods on
ServiceContexts immediately after they're built and immediately before they're
destroyed.
3.) Introduce / improve test fixture base classes for tests, giving them fresh
ServiceContext instances for each test case. There is one fixture for tests that
need a storage engine and another for those that do not.
4.) Make several remaining global variables SC decorations in support of (3)
5.) Replace many MONGO_INITIALIZERS that access getGlobalServiceContext with the
new constructor-actions system, which is needed for (3.)
6.) Fix up tests to use the fixtures from (3) and fix tests that silently used
different service contexts in together in a technically illegal fashion that now
breaks.
7.) Utilize (2) as necessary to simplify initialization of new ServiceContexts,
simplifying the fixtures in (3).
Diffstat (limited to 'src/mongo/db/service_context.h')
-rw-r--r-- | src/mongo/db/service_context.h | 168 |
1 files changed, 128 insertions, 40 deletions
diff --git a/src/mongo/db/service_context.h b/src/mongo/db/service_context.h index 73b272470e6..24905f2fc4d 100644 --- a/src/mongo/db/service_context.h +++ b/src/mongo/db/service_context.h @@ -28,14 +28,17 @@ #pragma once +#include <boost/optional.hpp> #include <vector> #include "mongo/base/disallow_copying.h" +#include "mongo/base/global_initializer_registerer.h" #include "mongo/db/logical_session_id.h" #include "mongo/db/storage/storage_engine.h" #include "mongo/platform/atomic_word.h" #include "mongo/stdx/condition_variable.h" #include "mongo/stdx/functional.h" +#include "mongo/stdx/list.h" #include "mongo/stdx/memory.h" #include "mongo/stdx/mutex.h" #include "mongo/stdx/unordered_set.h" @@ -89,20 +92,11 @@ protected: * A ServiceContext is the root of a hierarchy of contexts. A ServiceContext owns * zero or more Clients, which in turn each own OperationContexts. */ -class ServiceContext : public Decorable<ServiceContext> { +class ServiceContext final : public Decorable<ServiceContext> { MONGO_DISALLOW_COPYING(ServiceContext); public: /** - * Special deleter used for cleaning up Client objects owned by a ServiceContext. - * See UniqueClient, below. - */ - class ClientDeleter { - public: - void operator()(Client* client) const; - }; - - /** * Observer interface implemented to hook client and operation context creation and * destruction. */ @@ -172,12 +166,23 @@ public: }; /** - * Special deleter used for cleaning up OperationContext objects owned by a ServiceContext. - * See UniqueOperationContext, below. + * Special deleter used for cleaning up ServiceContext objects. + * See UniqueServiceContext, below. */ - class OperationContextDeleter { + class ServiceContextDeleter { public: - void operator()(OperationContext* opCtx) const; + void operator()(ServiceContext* service) const; + }; + + using UniqueServiceContext = std::unique_ptr<ServiceContext, ServiceContextDeleter>; + + /** + * Special deleter used for cleaning up Client objects owned by a ServiceContext. + * See UniqueClient, below. + */ + class ClientDeleter { + public: + void operator()(Client* client) const; }; /** @@ -186,11 +191,96 @@ public: using UniqueClient = std::unique_ptr<Client, ClientDeleter>; /** + * 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 OperationContexts created by a ServiceContext. */ using UniqueOperationContext = std::unique_ptr<OperationContext, OperationContextDeleter>; - virtual ~ServiceContext(); + /** + * Register a function of this type using an instance of ConstructorActionRegisterer, + * below, to cause the function to be executed on new ServiceContext instances. + */ + using ConstructorAction = stdx::function<void(ServiceContext*)>; + + /** + * Register a function of this type using an instance of ConstructorActionRegisterer, + * below, to cause the function to be executed on ServiceContext instances before they + * are destroyed. + */ + using DestructorAction = stdx::function<void(ServiceContext*) noexcept>; + + /** + * Representation of a paired ConstructorAction and DestructorAction. + */ + class ConstructorDestructorActions { + public: + ConstructorDestructorActions(ConstructorAction constructor, DestructorAction destructor) + : _constructor(std::move(constructor)), _destructor(std::move(destructor)) {} + + void onCreate(ServiceContext* service) const { + _constructor(service); + } + void onDestroy(ServiceContext* service) const { + _destructor(service); + } + + private: + ConstructorAction _constructor; + DestructorAction _destructor; + }; + + /** + * Registers a function to execute on new service contexts when they are created, and optionally + * also register a function to execute before those contexts are destroyed. + * + * Construct instances of this type during static initialization only, as they register + * MONGO_INITIALIZERS. + */ + class ConstructorActionRegisterer { + public: + /** + * This constructor registers a constructor and optional destructor with the given + * "name" and no prerequisite constructors or mongo initializers. + */ + ConstructorActionRegisterer(std::string name, + ConstructorAction constructor, + DestructorAction destructor = {}); + + /** + * This constructor registers a constructor and optional destructor with the given + * "name", and a list of names of prerequisites, "prereqs". + * + * The named constructor will run after all of its prereqs successfully complete, + * and the corresponding destructor, if provided, will run before any of its + * prerequisites execute. + */ + ConstructorActionRegisterer(std::string name, + std::vector<std::string> prereqs, + ConstructorAction constructor, + DestructorAction destructor = {}); + + private: + using ConstructorActionListIterator = stdx::list<ConstructorDestructorActions>::iterator; + ConstructorActionListIterator _iter; + boost::optional<GlobalInitializerRegisterer> _registerer; + }; + + /** + * Factory function for making instances of ServiceContext. It is the only means by which they + * should be created. + */ + static UniqueServiceContext make(); + + ServiceContext(); + ~ServiceContext(); /** * Registers an observer of lifecycle events on Clients created by this ServiceContext. @@ -411,20 +501,29 @@ public: */ void setServiceExecutor(std::unique_ptr<transport::ServiceExecutor> exec); -protected: - ServiceContext(); +private: + class ClientObserverHolder { + public: + explicit ClientObserverHolder(std::unique_ptr<ClientObserver> observer) + : _observer(std::move(observer)) {} + void onCreate(Client* client) const { + _observer->onCreateClient(client); + } + void onDestroy(Client* client) const { + _observer->onDestroyClient(client); + } + void onCreate(OperationContext* opCtx) const { + _observer->onCreateOperationContext(opCtx); + } + void onDestroy(OperationContext* opCtx) const { + _observer->onDestroyOperationContext(opCtx); + } - /** - * Mutex used to synchronize access to mutable state of this ServiceContext instance, - * including possibly by its subclasses. - */ - stdx::mutex _mutex; + private: + std::unique_ptr<ClientObserver> _observer; + }; -private: - /** - * Returns a new OperationContext. Private, for use by makeOperationContext. - */ - virtual std::unique_ptr<OperationContext> _newOpCtx(Client* client, unsigned opId) = 0; + stdx::mutex _mutex; /** * The storage engine, if any. @@ -454,7 +553,7 @@ private: /** * Vector of registered observers. */ - std::vector<std::unique_ptr<ClientObserver>> _clientObservers; + std::vector<ClientObserverHolder> _clientObservers; ClientSet _clients; /** @@ -503,23 +602,12 @@ bool hasGlobalServiceContext(); ServiceContext* getGlobalServiceContext(); /** - * Warning - This function is temporary. Do not introduce new uses of this API. - * - * Returns the singleton ServiceContext for this server process. - * - * Waits until there is a valid global ServiceContext. - * - * Caller does not own pointer. - */ -ServiceContext* waitAndGetGlobalServiceContext(); - -/** * Sets the global ServiceContext. If 'serviceContext' is NULL, un-sets and deletes * the current global ServiceContext. * * Takes ownership of 'serviceContext'. */ -void setGlobalServiceContext(std::unique_ptr<ServiceContext>&& serviceContext); +void setGlobalServiceContext(ServiceContext::UniqueServiceContext&& serviceContext); /** * Shortcut for querying the storage engine about whether it supports document-level locking. |