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