MySQL 8.0.30
Source Code Documentation
dim.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2016, 2022, 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 MySQLSession;
359}
360namespace mysqlrouter {
361class Ofstream;
362}
363namespace mysql_harness {
364class RandomGeneratorInterface;
365}
366namespace mysql_harness {
367namespace logging {
368class Registry;
369}
370} // namespace mysql_harness
371namespace mysql_harness {
372class LoaderConfig;
373}
374namespace mysql_harness {
375class DynamicState;
376}
377
378namespace mysql_harness {
379
380class HARNESS_EXPORT DIM { // DIM = Dependency Injection Manager
381
382 // this class is a singleton
383 protected:
386
387 public:
388 DIM(const DIM &) = delete;
389 DIM &operator=(const DIM &) = delete;
390 static DIM &instance();
391
392 // NOTE: once we gain confidence in this DIM and we can treat it as black box,
393 // all the boilerplate stuff (steps 2-4) for each class can be generated
394 // by a macro)
395
396 public:
397 ////////////////////////////////////////////////////////////////////////////////
398 // factory and deleter setters [step 2]
399 ////////////////////////////////////////////////////////////////////////////////
400
401 // Logging Registry
402 void reset_LoggingRegistry() { reset_generic(instance_LoggingRegistry_); }
404 const std::function<mysql_harness::logging::Registry *(void)> &factory,
405 const std::function<void(mysql_harness::logging::Registry *)> &deleter) {
406 factory_LoggingRegistry_ = factory;
407 deleter_LoggingRegistry_ = deleter;
408 }
409
410 // MySQLSession
412 const std::function<mysqlrouter::MySQLSession *(void)> &factory,
413 const std::function<void(mysqlrouter::MySQLSession *)> &deleter) {
414 factory_MySQLSession_ = factory;
415 deleter_MySQLSession_ = deleter;
416 }
417
418 // RandomGenerator
420 const std::function<mysql_harness::RandomGeneratorInterface *(void)>
421 &factory,
422 const std::function<void(mysql_harness::RandomGeneratorInterface *)>
423 &deleter) {
424 factory_RandomGenerator_ = factory;
425 deleter_RandomGenerator_ = deleter;
426 }
427
428 // LoaderConfig
429 void reset_Config() { reset_generic(instance_Config_); }
431 const std::function<mysql_harness::LoaderConfig *(void)> &factory,
432 const std::function<void(mysql_harness::LoaderConfig *)> &deleter) {
433 factory_Config_ = factory;
434 deleter_Config_ = deleter;
435 }
436
437 // DynamicState
438 void reset_DynamicState() { reset_generic(instance_DynamicState_); }
440 const std::function<mysql_harness::DynamicState *(void)> &factory,
441 const std::function<void(mysql_harness::DynamicState *)> &deleter) {
442 factory_DynamicState_ = factory;
443 deleter_DynamicState_ = deleter;
444 }
445
446 ////////////////////////////////////////////////////////////////////////////////
447 // object getters [step 3] (used for singleton objects)
448 ////////////////////////////////////////////////////////////////////////////////
449
450 // Logging Registry
452 return get_external_generic(instance_LoggingRegistry_,
453 factory_LoggingRegistry_,
454 deleter_LoggingRegistry_);
455 }
456
457 // RandomGenerator
459 return get_generic(factory_RandomGenerator_, deleter_RandomGenerator_);
460 }
461
462 // LoaderConfig
464 return get_external_generic(instance_Config_, factory_Config_,
465 deleter_Config_);
466 }
467
468 // DynamicState
469 bool is_DynamicState() { return (bool)instance_DynamicState_; }
471 return get_external_generic(instance_DynamicState_, factory_DynamicState_,
472 deleter_DynamicState_);
473 }
474
475 ////////////////////////////////////////////////////////////////////////////////
476 // object creators [step 3] (used for non-singleton objects)
477 ////////////////////////////////////////////////////////////////////////////////
478
479 // MySQLSession
481 return new_generic(factory_MySQLSession_, deleter_MySQLSession_);
482 }
483
484 private:
485 ////////////////////////////////////////////////////////////////////////////////
486 // factory and deleter functions [step 4]
487 ////////////////////////////////////////////////////////////////////////////////
488
489 // Logging Registry
490 std::function<mysql_harness::logging::Registry *(void)>
491 factory_LoggingRegistry_;
492 std::function<void(mysql_harness::logging::Registry *)>
495
496 // MySQLSession
497 std::function<mysqlrouter::MySQLSession *(void)> factory_MySQLSession_;
499
500 // RandomGenerator
501 std::function<mysql_harness::RandomGeneratorInterface *(void)>
502 factory_RandomGenerator_;
503 std::function<void(mysql_harness::RandomGeneratorInterface *)>
505
506 // LoaderConfig
507 std::function<mysql_harness::LoaderConfig *(void)> factory_Config_;
510
511 // DynamicState
512 std::function<mysql_harness::DynamicState *(void)> factory_DynamicState_;
515
516 ////////////////////////////////////////////////////////////////////////////////
517 // utility functions
518 ////////////////////////////////////////////////////////////////////////////////
519
520 protected:
521 template <typename T>
522 static T &get_generic(const std::function<T *(void)> &factory,
523 const std::function<void(T *)> &deleter) {
524 static UniquePtr<T> obj = new_generic(factory, deleter);
525 return *obj;
526 }
527
528 // new_generic*() (add more variants if needed, or convert into varargs
529 // template)
530 template <typename T>
531 static UniquePtr<T> new_generic(const std::function<T *(void)> &factory,
532 const std::function<void(T *)> &deleter) {
533 return UniquePtr<T>(factory(),
534 [deleter](T *p) {
535 deleter(p);
536 } // [&deleter] would be unsafe if set_T() was called
537 // before this object got erased
538 );
539 }
540 template <typename T, typename A1>
541 static UniquePtr<T> new_generic1(const std::function<T *(A1)> &factory,
542 const std::function<void(T *)> &deleter,
543 const A1 &a1) {
544 return UniquePtr<T>(factory(a1),
545 [deleter](T *p) {
546 deleter(p);
547 } // [&deleter] would be unsafe if set_T() was called
548 // before this object got erased
549 );
550 }
551 template <typename T, typename A1, typename A2>
552 static UniquePtr<T> new_generic2(const std::function<T *(A1, A2)> &factory,
553 const std::function<void(T *)> &deleter,
554 const A1 &a1, const A2 &a2) {
555 return UniquePtr<T>(factory(a1, a2),
556 [deleter](T *p) {
557 deleter(p);
558 } // [&deleter] would be unsafe if set_T() was called
559 // before this object got erased
560 );
561 }
562
563 template <typename T>
565 const std::function<T *()> &factory,
566 const std::function<void(T *)> &deleter) {
567 mtx_.lock();
568 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); });
569
570 if (!object) object = new_generic(factory, deleter);
571
572 return *object;
573 }
574
575 template <typename T>
577 mtx_.lock();
578 std::shared_ptr<void> exit_trigger(nullptr, [&](void *) { mtx_.unlock(); });
579
580 object.reset();
581 }
582
583 mutable std::recursive_mutex mtx_;
584
585}; // class DIM
586
587} // namespace mysql_harness
588#endif //#ifndef MYSQL_HARNESS_DIMANAGER_INCLUDED
Definition: dim.h:380
mysql_harness::RandomGeneratorInterface & get_RandomGenerator() const
Definition: dim.h:458
T & get_external_generic(UniquePtr< T > &object, const std::function< T *()> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:564
static T & get_generic(const std::function< T *(void)> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:522
void set_Config(const std::function< mysql_harness::LoaderConfig *(void)> &factory, const std::function< void(mysql_harness::LoaderConfig *)> &deleter)
Definition: dim.h:430
void set_LoggingRegistry(const std::function< mysql_harness::logging::Registry *(void)> &factory, const std::function< void(mysql_harness::logging::Registry *)> &deleter)
Definition: dim.h:403
std::function< void(mysql_harness::DynamicState *)> deleter_DynamicState_
Definition: dim.h:513
DIM(const DIM &)=delete
UniquePtr< mysqlrouter::MySQLSession > new_MySQLSession() const
Definition: dim.h:480
std::function< void(mysql_harness::RandomGeneratorInterface *)> deleter_RandomGenerator_
Definition: dim.h:504
static UniquePtr< T > new_generic(const std::function< T *(void)> &factory, const std::function< void(T *)> &deleter)
Definition: dim.h:531
std::function< void(mysqlrouter::MySQLSession *)> deleter_MySQLSession_
Definition: dim.h:498
UniquePtr< mysql_harness::logging::Registry > instance_LoggingRegistry_
Definition: dim.h:494
mysql_harness::DynamicState & get_DynamicState()
Definition: dim.h:470
void set_RandomGenerator(const std::function< mysql_harness::RandomGeneratorInterface *(void)> &factory, const std::function< void(mysql_harness::RandomGeneratorInterface *)> &deleter)
Definition: dim.h:419
std::function< void(mysql_harness::logging::Registry *)> deleter_LoggingRegistry_
Definition: dim.h:493
mysql_harness::LoaderConfig & get_Config()
Definition: dim.h:463
std::recursive_mutex mtx_
Definition: dim.h:583
void set_DynamicState(const std::function< mysql_harness::DynamicState *(void)> &factory, const std::function< void(mysql_harness::DynamicState *)> &deleter)
Definition: dim.h:439
static UniquePtr< T > new_generic1(const std::function< T *(A1)> &factory, const std::function< void(T *)> &deleter, const A1 &a1)
Definition: dim.h:541
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:552
mysql_harness::logging::Registry & get_LoggingRegistry()
Definition: dim.h:451
std::function< void(mysql_harness::LoaderConfig *)> deleter_Config_
Definition: dim.h:508
void reset_generic(UniquePtr< T > &object)
Definition: dim.h:576
DIM & operator=(const DIM &)=delete
bool is_DynamicState()
Definition: dim.h:469
void reset_Config()
Definition: dim.h:429
void set_MySQLSession(const std::function< mysqlrouter::MySQLSession *(void)> &factory, const std::function< void(mysqlrouter::MySQLSession *)> &deleter)
Definition: dim.h:411
UniquePtr< mysql_harness::DynamicState > instance_DynamicState_
Definition: dim.h:514
UniquePtr< mysql_harness::LoaderConfig > instance_Config_
Definition: dim.h:509
void reset_LoggingRegistry()
Definition: dim.h:402
void reset_DynamicState()
Definition: dim.h:438
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
Definition: mysql_session.h:154
const char * p
Definition: ctype-mb.cc:1236
Definition: common.h:41
Definition: dim.h:357