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