MySQL 8.0.40
Source Code Documentation
dim.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2016, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_DIMANAGER_INCLUDED
27#define MYSQL_HARNESS_DIMANAGER_INCLUDED
28
29#include "harness_export.h"
30#include "unique_ptr.h"
31
32#include <functional>
33#include <mutex> // using fwd declaration + ptr-to-implementation gives build errors on BSD-based systems
34#include <string> // unfortunately, std::string is a typedef and therefore not easy to forward-declare
35
36/** @file
37 * @brief Provides simple, yet useful dependency injection mechanism
38 *
39 * # Introduction
40 *
41 * Let's start with showing usage, for example class Foo:
42 *
43 * @code
44 * class Foo {
45 * public:
46 * Foo();
47 * void do_something();
48 * };
49 * @endcode
50 *
51 * We want DIM to make instance(s) of this class available throughout our
52 * application.
53 *
54 * ## Scenario 1: when Foo is a singleton
55 *
56 * @code
57 * void init_code() {
58 * DIM::instance().set_Foo([](){ return new Foo; });
59 * }
60 *
61 * void use_code() {
62 * Foo& foo = DIM::instance().get_Foo();
63 *
64 * // each call works on the same object
65 * foo.do_something();
66 * foo.do_something();
67 * foo.do_something();
68 * }
69 * @endcode
70 *
71 * ## Scenario 2: when Foo is not a singleton
72 *
73 * @code
74 * void init_code() {
75 * DIM::instance().set_Foo([](){ return new Foo; });
76 * }
77 *
78 * void use_code() {
79 * // each call generates a new object
80 * UniquePtr<Foo> foo1 = DIM::instance().new_Foo();
81 * foo1->do_something();
82 *
83 * UniquePtr<Foo> foo2 = DIM::instance().new_Foo();
84 * foo2->do_something();
85 *
86 * UniquePtr<Foo> foo3 = DIM::instance().new_Foo();
87 * foo3->do_something();
88 * }
89 * @endcode
90 *
91 * ## Scenario 3: when Foo already exists (typically used in unit tests)
92 *
93 * @code
94 * Foo foo_that_lives_forever;
95 *
96 * void init_code() {
97 * DIM::instance().set_Foo(
98 * [](){
99 * return &foo_that_lives_forever;
100 * },
101 * [](Foo*) {}); // so that DIM does not try to delete it
102 * }
103 *
104 * void use_code() {
105 * Foo& foo = DIM::instance().get_Foo();
106 * foo.do_something();
107 * }
108 * @endcode
109 *
110 * Convenient, isn't it? But to make all this happen, class Foo (boilerplate
111 * code) has to be added to DIM class.
112 *
113 * # Usage
114 *
115 * Adding a new managed object is done in 4 steps:
116 *
117 * 1. add class forward declaration
118 * 2. add object factory + deleter setter
119 * 3. add singleton object getter or object creator. Adding both usually makes
120 * no sense
121 * 4. add factory and deleter function objects
122 *
123 * Here is the (relevant part of) class DIM for class Foo:
124 *
125 *
126 * @code
127 * // [step 1]
128 * // forward declarations
129 * class Foo;
130 *
131 * class DIM {
132 * // ... constructors, instance(), other support methods ...
133 *
134 * public:
135 * // [step 2]
136 * // factory + deleter setter
137 * void set_Foo(const std::function<Foo*(void)>& factory,
138 * const std::function<void(Foo*)>& deleter =
139 * std::default_delete<Foo>()) {
140 * factory_Foo_ = factory; deleter_Foo_ = deleter;
141 * }
142 *
143 * // [step 3]
144 * // singleton object getter
145 * // (shown here, but normally mutually-exclusive with next method)
146 * Foo& get_Foo() const {
147 * return get_generic<Foo>(factory_Foo_, deleter_Foo_);
148 * }
149 *
150 * // object creator
151 * // (shown here, but normally mutually-exclusive with previous method)
152 * UniquePtr<Foo> new_Foo() const {
153 * return new_generic(factory_Foo_, deleter_Foo_);
154 * }
155 *
156 * private:
157 * // factory and deleter function objects [step 4]
158 * std::function<Foo*(void)> factory_Foo_;
159 * std::function<void(Foo*)> deleter_Foo_;
160 * };
161 * @endcode
162 *
163 *
164 * ## Example
165 *
166 * @code
167 * // forward declarations [step 1]
168 * class Foo;
169 * class Bar;
170 * class Baz;
171 *
172 * class DIM {
173 * // ... constructors, instance(), other support methods ...
174 *
175 * // Example: Foo depends on Bar and Baz,
176 * // Bar depends on Baz and some int,
177 * // Baz depends on nothing
178 *
179 * public:
180 * // factory + deleter setters [step 2]
181 * void set_Foo(const std::function<Foo*(void)>& factory,
182 * const std::function<void(Foo*)>& deleter =
183 * std::default_delete<Foo>()) {
184 * factory_Foo_ = factory; deleter_Foo_ = deleter;
185 * }
186 *
187 * void set_Bar(const std::function<Bar*(void)>& factory,
188 * const std::function<void(Bar*)>& deleter =
189 * std::default_delete<Bar>()) {
190 * factory_Bar_ = factory; deleter_Bar_ = deleter;
191 * }
192 *
193 * void set_Baz(const std::function<Baz*(void)>& factory,
194 * const std::function<void(Baz*)>& deleter =
195 * std::default_delete<Baz>()) {
196 * factory_Baz_ = factory; deleter_Baz_ = deleter;
197 * }
198 *
199 * // singleton object getters
200 * // (all are shown, but normally mutually-exclusive
201 * // with next group) [step 3]
202 * Foo& get_Foo() const {
203 * return get_generic<Foo>(factory_Foo_, deleter_Foo_);
204 * }
205 * Bar& get_Bar() const {
206 * return get_generic<Bar>(factory_Bar_, deleter_Bar_);
207 * }
208 * Baz& get_Baz() const {
209 * return get_generic<Baz>(factory_Baz_, deleter_Baz_);
210 * }
211 *
212 * // object creators
213 * // (all are shown, but normally mutually-exclusive
214 * // with previous group) [step 3]
215 * UniquePtr<Foo> new_Foo() const {
216 * return new_generic(factory_Foo_, deleter_Foo_);
217 * }
218 * UniquePtr<Bar> new_Bar() const {
219 * return new_generic(factory_Bar_, deleter_Bar_);
220 * }
221 * UniquePtr<Baz> new_Baz() const {
222 * return new_generic(factory_Baz_, deleter_Baz_);
223 * }
224 *
225 * private:
226 * // factory and deleter function objects [step 4]
227 * std::function<Foo*(void)> factory_Foo_;
228 * std::function<void(Foo*)> deleter_Foo_;
229 * std::function<Bar*(void)> factory_Bar_;
230 * std::function<void(Bar*)> deleter_Bar_;
231 * std::function<Baz*(void)> factory_Baz_;
232 * std::function<void(Baz*)> deleter_Baz_;
233 * };
234 *
235 *
236 *
237 * // actual classes
238 * struct Baz {
239 * Baz() {}
240 * };
241 * struct Bar {
242 * Bar(Baz, int) {}
243 * };
244 * struct Foo {
245 * Foo(Bar, Baz) {}
246 * void do_something() {}
247 * };
248 *
249 *
250 *
251 * // usage
252 * int main() {
253 * int n = 3306;
254 *
255 * // init code
256 * DIM& dim = DIM::instance();
257 * dim.set_Foo([&dim]() {
258 * return new Foo(dim.get_Bar(), dim.get_Baz()); });
259 * dim.set_Bar([&dim, n]() {
260 * return new Bar(dim.get_Baz(), n); });
261 * dim.set_Baz([]() {
262 * return new Baz; });
263 *
264 * // use code (as singleton)
265 * //
266 * // will automatically instantiate Bar and Baz as well
267 * dim.get_Foo().do_something();
268 *
269 * // use code (as new object)
270 * UniquePtr<Foo> foo = dim.new_Foo();
271 * foo->do_something();
272 * }
273 * @endcode
274 *
275 * # Object Reset
276 *
277 * There's also an option to reset an object managed by DIM, should you need it.
278 * Normally, on the first call to get_Foo(), it will call the factory_Foo_() to
279 * create the object before returning it. On subsequent calls, it will just
280 * return that Foo object previously created. But what if you needed to reset
281 * that object? And perhaps to create it via another Foo factory method, or with
282 * different parameters?
283 *
284 * For such case, we can define reset_Foo() method, which will reset the Foo
285 * object back to nullptr. The Foo object can no longer be kept inside of
286 * get_Foo(), because it has to be modifiable via reset_Foo(). Here's the code:
287 *
288 *
289 * @code
290 * // Foo-related members.
291 * //
292 * // instance_Foo_ is new here, it now stores the Foo object
293 * //
294 * // (previously, this object was stored as a static variable
295 * // inside of get_Foo()
296 * std::function<Foo*(void)> factory_Foo_;
297 * std::function<void(Foo*)> deleter_Foo_;
298 * UniquePtr<Foo> instance_Foo_; // <---- new member
299 *
300 * // getter now relies on get_external_generic() to manage the Foo object
301 * Foo& get_Foo() {
302 * return get_external_generic(instance_Foo_,
303 * factory_Foo_,
304 * deleter_Foo_);
305 * }
306 *
307 * // this is our new function.
308 * //
309 * // After calling it, set_Foo() can be used again
310 * // to set the factory method, which will be
311 * // triggered on subsequent call to get_Foo() to
312 * // create the new Foo object
313 * void reset_Foo() { reset_generic(instance_Foo_); }
314 *
315 * // set_Foo remains unaltered
316 * void set_Foo(const std::function<Foo*(void)>& factory,
317 * const std::function<void(Foo*)>& deleter =
318 * std::default_delete<Foo>()) {
319 * factory_Foo_ = factory;
320 * deleter_Foo_ = deleter;
321 * }
322 * @endcode
323 *
324 * ## Example
325 *
326 * @code
327 * // init code
328 * DIM& dim = DIM::instance();
329 * dim.set_Foo([]() { return new Foo(42); });
330 *
331 * // use code
332 *
333 * // automatically calls set_Foo() which returns new Foo(42)
334 * dim.get_Foo().do_something();
335 *
336 * // does not call set_Foo() anymore
337 * dim.get_Foo().do_something();
338 *
339 * // does not call set_Foo() anymore
340 * dim.get_Foo().do_something();
341 *
342 * // sets new creating function
343 * dim.set_Foo([]() {
344 * return new Foo(555);
345 * });
346 * // but the new set_Foo() is still not called
347 * dim.get_Foo().do_something();
348 *
349 * dim.reset_Foo();
350 *
351 * // automatically calls (new) set_Foo(), which returns new Foo(555)
352 * dim.get_Foo().do_something();
353 * @endcode
354 *
355 */
356
357// forward declarations [step 1]
358namespace mysqlrouter {
359class Ofstream;
360}
361namespace mysql_harness {
362class RandomGeneratorInterface;
363}
364namespace mysql_harness {
365namespace logging {
366class Registry;
367}
368} // namespace mysql_harness
369namespace mysql_harness {
370class LoaderConfig;
371}
372namespace mysql_harness {
373class DynamicState;
374}
375
376namespace mysql_harness {
377
378class HARNESS_EXPORT DIM { // DIM = Dependency Injection Manager
379
380 // this class is a singleton
381 protected:
384
385 public:
386 DIM(const DIM &) = delete;
387 DIM &operator=(const DIM &) = delete;
388 static DIM &instance();
389
390 // NOTE: once we gain confidence in this DIM and we can treat it as black box,
391 // all the boilerplate stuff (steps 2-4) for each class can be generated
392 // by a macro)
393
394 public:
395 ////////////////////////////////////////////////////////////////////////////////
396 // factory and deleter setters [step 2]
397 ////////////////////////////////////////////////////////////////////////////////
398
399 // Logging Registry
400 void reset_LoggingRegistry() { reset_generic(instance_LoggingRegistry_); }
402 const std::function<mysql_harness::logging::Registry *(void)> &factory,
403 const std::function<void(mysql_harness::logging::Registry *)> &deleter) {
404 factory_LoggingRegistry_ = factory;
405 deleter_LoggingRegistry_ = deleter;
406 }
407
408 // RandomGenerator
410 const std::function<mysql_harness::RandomGeneratorInterface *(void)>
411 &factory,
412 const std::function<void(mysql_harness::RandomGeneratorInterface *)>
413 &deleter) {
414 factory_RandomGenerator_ = factory;
415 deleter_RandomGenerator_ = deleter;
416 }
417
418 // LoaderConfig
419 void reset_Config() { reset_generic(instance_Config_); }
421 const std::function<mysql_harness::LoaderConfig *(void)> &factory,
422 const std::function<void(mysql_harness::LoaderConfig *)> &deleter) {
423 factory_Config_ = factory;
424 deleter_Config_ = deleter;
425 }
426
427 // DynamicState
428 void reset_DynamicState() { reset_generic(instance_DynamicState_); }
430 const std::function<mysql_harness::DynamicState *(void)> &factory,
431 const std::function<void(mysql_harness::DynamicState *)> &deleter) {
432 factory_DynamicState_ = factory;
433 deleter_DynamicState_ = deleter;
434 }
435
436 ////////////////////////////////////////////////////////////////////////////////
437 // object getters [step 3] (used for singleton objects)
438 ////////////////////////////////////////////////////////////////////////////////
439
440 // Logging Registry
442 return get_external_generic(instance_LoggingRegistry_,
443 factory_LoggingRegistry_,
444 deleter_LoggingRegistry_);
445 }
446
447 // RandomGenerator
449 return get_generic(factory_RandomGenerator_, deleter_RandomGenerator_);
450 }
451
452 // LoaderConfig
454 return get_external_generic(instance_Config_, factory_Config_,
455 deleter_Config_);
456 }
457
458 // DynamicState
459 bool is_DynamicState() { return (bool)instance_DynamicState_; }
461 return get_external_generic(instance_DynamicState_, factory_DynamicState_,
462 deleter_DynamicState_);
463 }
464
465 private:
466 ////////////////////////////////////////////////////////////////////////////////
467 // factory and deleter functions [step 4]
468 ////////////////////////////////////////////////////////////////////////////////
469
470 // Logging Registry
471 std::function<mysql_harness::logging::Registry *(void)>
472 factory_LoggingRegistry_;
473 std::function<void(mysql_harness::logging::Registry *)>
476
477 // RandomGenerator
478 std::function<mysql_harness::RandomGeneratorInterface *(void)>
479 factory_RandomGenerator_;
480 std::function<void(mysql_harness::RandomGeneratorInterface *)>
482
483 // LoaderConfig
484 std::function<mysql_harness::LoaderConfig *(void)> factory_Config_;
487
488 // DynamicState
489 std::function<mysql_harness::DynamicState *(void)> factory_DynamicState_;
492
493 ////////////////////////////////////////////////////////////////////////////////
494 // utility functions
495 ////////////////////////////////////////////////////////////////////////////////
496
497 protected:
498 template <typename T>
499 static T &get_generic(const std::function<T *(void)> &factory,
500 const std::function<void(T *)> &deleter) {
501 static UniquePtr<T> obj = new_generic(factory, deleter);
502 return *obj;
503 }
504
505 // new_generic*() (add more variants if needed, or convert into varargs
506 // template)
507 template <typename T>
508 static UniquePtr<T> new_generic(const std::function<T *(void)> &factory,
509 const std::function<void(T *)> &deleter) {
510 return UniquePtr<T>(factory(),
511 [deleter](T *p) {
512 deleter(p);
513 } // [&deleter] would be unsafe if set_T() was called
514 // before this object got erased
515 );
516 }
517 template <typename T, typename A1>
518 static UniquePtr<T> new_generic1(const std::function<T *(A1)> &factory,
519 const std::function<void(T *)> &deleter,
520 const A1 &a1) {
521 return UniquePtr<T>(factory(a1),
522 [deleter](T *p) {
523 deleter(p);
524 } // [&deleter] would be unsafe if set_T() was called
525 // before this object got erased
526 );
527 }
528 template <typename T, typename A1, typename A2>
529 static UniquePtr<T> new_generic2(const std::function<T *(A1, A2)> &factory,
530 const std::function<void(T *)> &deleter,
531 const A1 &a1, const A2 &a2) {
532 return UniquePtr<T>(factory(a1, a2),
533 [deleter](T *p) {
534 deleter(p);
535 } // [&deleter] would be unsafe if set_T() was called
536 // before this object got erased
537 );
538 }
539
540 template <typename T>
542 const std::function<T *()> &factory,
543 const std::function<void(T *)> &deleter) {
544 mtx_.lock();
545 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); });
546
547 if (!object) object = new_generic(factory, deleter);
548
549 return *object;
550 }
551
552 template <typename T>
554 mtx_.lock();
555 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); });
556
557 object.reset();
558 }
559
560 mutable std::recursive_mutex mtx_;
561
562}; // class DIM
563
564} // namespace mysql_harness
565#endif // #ifndef MYSQL_HARNESS_DIMANAGER_INCLUDED
Definition: dim.h:378
mysql_harness::RandomGeneratorInterface & get_RandomGenerator() const
Definition: dim.h:448
T & get_external_generic(UniquePtr< T > &object, const std::function< T *()> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:541
static T & get_generic(const std::function< T *(void)> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:499
void set_Config(const std::function< mysql_harness::LoaderConfig *(void)> &factory, const std::function< void(mysql_harness::LoaderConfig *)> &deleter)
Definition: dim.h:420
void set_LoggingRegistry(const std::function< mysql_harness::logging::Registry *(void)> &factory, const std::function< void(mysql_harness::logging::Registry *)> &deleter)
Definition: dim.h:401
std::function< void(mysql_harness::DynamicState *)> deleter_DynamicState_
Definition: dim.h:490
DIM(const DIM &)=delete
std::function< void(mysql_harness::RandomGeneratorInterface *)> deleter_RandomGenerator_
Definition: dim.h:481
static UniquePtr< T > new_generic(const std::function< T *(void)> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:508
UniquePtr< mysql_harness::logging::Registry > instance_LoggingRegistry_
Definition: dim.h:475
mysql_harness::DynamicState & get_DynamicState()
Definition: dim.h:460
void set_RandomGenerator(const std::function< mysql_harness::RandomGeneratorInterface *(void)> &factory, const std::function< void(mysql_harness::RandomGeneratorInterface *)> &deleter)
Definition: dim.h:409
std::function< void(mysql_harness::logging::Registry *)> deleter_LoggingRegistry_
Definition: dim.h:474
mysql_harness::LoaderConfig & get_Config()
Definition: dim.h:453
std::recursive_mutex mtx_
Definition: dim.h:560
void set_DynamicState(const std::function< mysql_harness::DynamicState *(void)> &factory, const std::function< void(mysql_harness::DynamicState *)> &deleter)
Definition: dim.h:429
static UniquePtr< T > new_generic1(const std::function< T *(A1)> &factory, const std::function< void(T *)> &deleter, const A1 &a1)
Definition: dim.h:518
static UniquePtr< T > new_generic2(const std::function< T *(A1, A2)> &factory, const std::function< void(T *)> &deleter, const A1 &a1, const A2 &a2)
Definition: dim.h:529
mysql_harness::logging::Registry & get_LoggingRegistry()
Definition: dim.h:441
std::function< void(mysql_harness::LoaderConfig *)> deleter_Config_
Definition: dim.h:485
void reset_generic(UniquePtr< T > &object)
Definition: dim.h:553
DIM & operator=(const DIM &)=delete
bool is_DynamicState()
Definition: dim.h:459
void reset_Config()
Definition: dim.h:419
UniquePtr< mysql_harness::DynamicState > instance_DynamicState_
Definition: dim.h:491
UniquePtr< mysql_harness::LoaderConfig > instance_Config_
Definition: dim.h:486
void reset_LoggingRegistry()
Definition: dim.h:400
void reset_DynamicState()
Definition: dim.h:428
DynamicState represents a MySQLRouter dynamic state object.
Definition: dynamic_state.h:64
Configuration file handler for the loader.
Definition: loader_config.h:46
Definition: random_generator.h:36
Definition: unique_ptr.h:75
Definition: registry.h:47
const char * p
Definition: ctype-mb.cc:1237
Definition: common.h:42
Definition: dim.h:358