diff options
author | ADAM David Alan Martin <adam.martin@10gen.com> | 2017-04-24 17:48:06 -0400 |
---|---|---|
committer | ADAM David Alan Martin <adam.martin@10gen.com> | 2017-04-24 17:48:06 -0400 |
commit | caec188e15b6e6015c2360b8e5bafc160d0d1f48 (patch) | |
tree | 3cc332db0cfe23cdfd6aeb32c8a079aa47357614 /src/mongo/db/catalog/database_holder.h | |
parent | 918ac217df662fcb0865dba278df9151c3665fbc (diff) | |
download | mongo-caec188e15b6e6015c2360b8e5bafc160d0d1f48.tar.gz |
SERVER-28842 Slice `DatabaseHolder` using a vtable
The `DatabaseHolder` class and the `dbHolder` free function are
used in many libraries which are circularly dependent with `catalog`.
By adding a vtable to facilitate dynamically injectable implementations,
we can break those dependencies.
Diffstat (limited to 'src/mongo/db/catalog/database_holder.h')
-rw-r--r-- | src/mongo/db/catalog/database_holder.h | 95 |
1 files changed, 78 insertions, 17 deletions
diff --git a/src/mongo/db/catalog/database_holder.h b/src/mongo/db/catalog/database_holder.h index ecde0496b76..58af1747218 100644 --- a/src/mongo/db/catalog/database_holder.h +++ b/src/mongo/db/catalog/database_holder.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2012-2014 MongoDB Inc. + * Copyright (C) 2017 MongoDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, @@ -33,12 +33,12 @@ #include "mongo/base/string_data.h" #include "mongo/db/namespace_string.h" +#include "mongo/stdx/functional.h" #include "mongo/stdx/mutex.h" #include "mongo/util/concurrency/mutex.h" #include "mongo/util/string_map.h" namespace mongo { - class Database; class OperationContext; @@ -47,13 +47,43 @@ class OperationContext; */ class DatabaseHolder { public: - DatabaseHolder() = default; + class Impl { + public: + virtual ~Impl() = 0; + + virtual Database* get(OperationContext* opCtx, StringData ns) const = 0; + + virtual Database* openDb(OperationContext* opCtx, StringData ns, bool* justCreated) = 0; + + virtual void close(OperationContext* opCtx, StringData ns, const std::string& reason) = 0; + + virtual bool closeAll(OperationContext* opCtx, + BSONObjBuilder& result, + bool force, + const std::string& reason) = 0; + + virtual std::set<std::string> getNamesWithConflictingCasing(StringData name) = 0; + }; + +private: + static std::unique_ptr<Impl> makeImpl(); + +public: + using factory_function_type = decltype(makeImpl); + + static void registerFactory(stdx::function<factory_function_type> factory); + + inline ~DatabaseHolder() = default; + + inline explicit DatabaseHolder() : _pimpl(makeImpl()) {} /** * Retrieves an already opened database or returns NULL. Must be called with the database * locked in at least IS-mode. */ - Database* get(OperationContext* opCtx, StringData ns) const; + inline Database* get(OperationContext* const opCtx, const StringData ns) const { + return this->_impl().get(opCtx, ns); + } /** * Retrieves a database reference if it is already opened, or opens it if it hasn't been @@ -62,12 +92,20 @@ public: * @param justCreated Returns whether the database was newly created (true) or it already * existed (false). Can be NULL if this information is not necessary. */ - Database* openDb(OperationContext* opCtx, StringData ns, bool* justCreated = NULL); + inline Database* openDb(OperationContext* const opCtx, + const StringData ns, + bool* const justCreated = nullptr) { + return this->_impl().openDb(opCtx, ns, justCreated); + } /** * Closes the specified database. Must be called with the database locked in X-mode. */ - void close(OperationContext* opCtx, StringData ns, const std::string& reason); + inline void close(OperationContext* const opCtx, + const StringData ns, + const std::string& reason) { + return this->_impl().close(opCtx, ns, reason); + } /** * Closes all opened databases. Must be called with the global lock acquired in X-mode. @@ -76,23 +114,46 @@ public: * @param force Force close even if something underway - use at shutdown * @param reason The reason for close. */ - bool closeAll(OperationContext* opCtx, - BSONObjBuilder& result, - bool force, - const std::string& reason); + inline bool closeAll(OperationContext* const opCtx, + BSONObjBuilder& result, + const bool force, + const std::string& reason) { + return this->_impl().closeAll(opCtx, result, force, reason); + } /** * Returns the set of existing database names that differ only in casing. */ - std::set<std::string> getNamesWithConflictingCasing(StringData name); + inline std::set<std::string> getNamesWithConflictingCasing(const StringData name) { + return this->_impl().getNamesWithConflictingCasing(name); + } private: - std::set<std::string> _getNamesWithConflictingCasing_inlock(StringData name); + // This structure exists to give us a customization point to decide how to force users of this + // class to depend upon the corresponding `database_holder.cpp` Translation Unit (TU). All + // public forwarding functions call `_impl(), and `_impl` creates an instance of this structure. + struct TUHook { + static void hook() noexcept; + + explicit inline TUHook() noexcept { + if (kDebugBuild) + this->hook(); + } + }; + + inline const Impl& _impl() const { + TUHook{}; + return *this->_pimpl; + } + + inline Impl& _impl() { + TUHook{}; + return *this->_pimpl; + } - typedef StringMap<Database*> DBs; - mutable SimpleMutex _m; - DBs _dbs; + std::unique_ptr<Impl> _pimpl; }; -DatabaseHolder& dbHolder(); -} +extern DatabaseHolder& dbHolder(); +extern void registerDbHolderImpl(stdx::function<decltype(dbHolder)> impl); +} // namespace mongo |