1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <set> 34 #include <string> 35 36 #include "mongo/base/string_data.h" 37 #include "mongo/db/namespace_string.h" 38 #include "mongo/stdx/functional.h" 39 #include "mongo/stdx/mutex.h" 40 #include "mongo/util/concurrency/mutex.h" 41 #include "mongo/util/string_map.h" 42 43 namespace mongo { 44 class Database; 45 class OperationContext; 46 47 /** 48 * Registry of opened databases. 49 */ 50 class DatabaseHolder { 51 public: 52 class Impl { 53 public: 54 virtual ~Impl() = 0; 55 56 virtual Database* get(OperationContext* opCtx, StringData ns) const = 0; 57 58 virtual Database* openDb(OperationContext* opCtx, StringData ns, bool* justCreated) = 0; 59 60 virtual void close(OperationContext* opCtx, StringData ns, const std::string& reason) = 0; 61 62 virtual bool closeAll(OperationContext* opCtx, 63 BSONObjBuilder& result, 64 bool force, 65 const std::string& reason) = 0; 66 67 virtual std::set<std::string> getNamesWithConflictingCasing(StringData name) = 0; 68 }; 69 70 private: 71 static std::unique_ptr<Impl> makeImpl(); 72 73 public: 74 using factory_function_type = decltype(makeImpl); 75 76 static void registerFactory(stdx::function<factory_function_type> factory); 77 78 inline ~DatabaseHolder() = default; 79 DatabaseHolder()80 inline explicit DatabaseHolder() : _pimpl(makeImpl()) {} 81 82 /** 83 * Retrieves an already opened database or returns NULL. Must be called with the database 84 * locked in at least IS-mode. 85 */ get(OperationContext * const opCtx,const StringData ns)86 inline Database* get(OperationContext* const opCtx, const StringData ns) const { 87 return this->_impl().get(opCtx, ns); 88 } 89 90 /** 91 * Retrieves a database reference if it is already opened, or opens it if it hasn't been 92 * opened/created yet. Must be called with the database locked in X-mode. 93 * 94 * @param justCreated Returns whether the database was newly created (true) or it already 95 * existed (false). Can be NULL if this information is not necessary. 96 */ 97 inline Database* openDb(OperationContext* const opCtx, 98 const StringData ns, 99 bool* const justCreated = nullptr) { 100 return this->_impl().openDb(opCtx, ns, justCreated); 101 } 102 103 /** 104 * Closes the specified database. Must be called with the database locked in X-mode. 105 */ close(OperationContext * const opCtx,const StringData ns,const std::string & reason)106 inline void close(OperationContext* const opCtx, 107 const StringData ns, 108 const std::string& reason) { 109 return this->_impl().close(opCtx, ns, reason); 110 } 111 112 /** 113 * Closes all opened databases. Must be called with the global lock acquired in X-mode. 114 * 115 * @param result Populated with the names of the databases, which were closed. 116 * @param force Force close even if something underway - use at shutdown 117 * @param reason The reason for close. 118 */ closeAll(OperationContext * const opCtx,BSONObjBuilder & result,const bool force,const std::string & reason)119 inline bool closeAll(OperationContext* const opCtx, 120 BSONObjBuilder& result, 121 const bool force, 122 const std::string& reason) { 123 return this->_impl().closeAll(opCtx, result, force, reason); 124 } 125 126 /** 127 * Returns the set of existing database names that differ only in casing. 128 */ getNamesWithConflictingCasing(const StringData name)129 inline std::set<std::string> getNamesWithConflictingCasing(const StringData name) { 130 return this->_impl().getNamesWithConflictingCasing(name); 131 } 132 133 private: 134 // This structure exists to give us a customization point to decide how to force users of this 135 // class to depend upon the corresponding `database_holder.cpp` Translation Unit (TU). All 136 // public forwarding functions call `_impl(), and `_impl` creates an instance of this structure. 137 struct TUHook { 138 static void hook() noexcept; 139 TUHookTUHook140 explicit inline TUHook() noexcept { 141 if (kDebugBuild) 142 this->hook(); 143 } 144 }; 145 _impl()146 inline const Impl& _impl() const { 147 TUHook{}; 148 return *this->_pimpl; 149 } 150 _impl()151 inline Impl& _impl() { 152 TUHook{}; 153 return *this->_pimpl; 154 } 155 156 std::unique_ptr<Impl> _pimpl; 157 }; 158 159 extern DatabaseHolder& dbHolder(); 160 extern void registerDbHolderImpl(stdx::function<decltype(dbHolder)> impl); 161 } // namespace mongo 162