MySQL 9.4.0
Source Code Documentation
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
weak_service_reference.h
Go to the documentation of this file.
1/* Copyright (c) 2024, 2025, Oracle and/or its affiliates.
2
3This program is free software; you can redistribute it and/or modify
4it under the terms of the GNU General Public License, version 2.0,
5as published by the Free Software Foundation.
6
7This program is designed to work with certain software (including
8but not limited to OpenSSL) that is licensed under separate terms,
9as designated in a particular file or component or in included license
10documentation. The authors of MySQL hereby grant you an additional
11permission to link the program and your derivative works with the
12separately licensed software that they have either included with
13the program or referenced in the documentation.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License, version 2.0, for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24#ifndef WEAK_REQUIRES_SERVICE_GUARD
25#define WEAK_REQUIRES_SERVICE_GUARD
26
27#include <atomic>
28#include <cassert>
29#include <functional>
30#include <string>
36/**
37 @brief A utility class to implement a delayed service reference
38
39 This class allows a component to have a "weak" reference to a component
40 service.
41
42 @par Operation in default mode (keep references = true)
43 In its default mode (keep references) when the weak reference is initialized
44 the class checks if the service required already has implementations. If it
45 does, the class takes a reference to the default one, calls the supplied
46 function and keeps the reference. If there's no implementation of the service
47 the class registers a listener to the
48 dynamic_loader_services_loaded_notification broadcast service by implementing
49 a dynamic_loader_services_loaded_notification service that, when called by the
50 dynamic loader, will take a reference to the desired service, call the
51 function supplied and keep the reference until deinit. And then it sets a flag
52 preventing any further calls to the function.
53
54 @par
55 At deinit time, if there's an active reference, deinit calls the supplied
56 function and passes it as a parameter. And then releases the reference.
57 Otherwise, no call of the supplied deinit function is done.
58 It also unregisters the dynamic_loader_services_loaded_notification callback,
59 if registered.
60
61 @par Operation in do-not-keep-references mode.
62 When the weak reference is initialized the class checks if the service
63 required already has implementations. If it does, then the class takes a
64 reference to the default implementation, calls the supplied init function and
65 <b>releases</b> the reference. It then proceeds to <b>unconditioanlly</b>
66 register a listener to the dynamic_loader_services_loaded_notification
67 broadcast service by implementing a
68 dynamic_loader_services_loaded_notification service that, when called by the
69 dynamic loader, will take a reference to the desired service, call the
70 function supplied and then release the reference.
71 Every time a new implementation is registered, the notification callback will
72 be called so the weak reference can re-register itself again.
73
74 @par
75 At deinit time, deinit tries to acquire the required service and, if
76 successful, calls the supplied deinit function and passes it as a parameter.
77 Note that if the service implementation has been undefined in the meanwhile no
78 call of the supplied deinit function is done.
79
80 @warning
81 Do not use the do-not-keep-references mode for anyting but the server!
82 It is only justified for the server component (aka the bootstrap component)
83 because if it doesn't use it no one will be able to unload the component
84 implementing the service once captured by the bootstrap component.
85 Yes, unloading service implementation component would be impossible, but
86 that's a desired side effect since there is state that needs to be
87 destroyed properly before the service implementation can be unloaded.
88
89 Normal usage pattern is that the @ref weak_service_reference::init() is called
90 during component initialization.
91
92 And @ref weak_service_reference::deinit() is called during the component
93 deinitialization.
94
95 One can expect that the function argument is called either at init() time or
96 asyncronously, possibly from anoher thread, when an implementation of a
97 service is registered.
98
99 Typical usage:
100 @code
101 #include "mysql/components/util/weak_service_reference.h"
102 ...
103 #include "mysql/components/services/foo.h"
104 #include "mysql/components/services/registry.h"
105 ...
106
107 REQUIRES_SERVICE_PLACEHOLDER(registry_registration);
108
109 const std::string c_name(component_foo), s_name("foo");
110 typedef weak_service_reference<SERVICE_TYPE(foo), c_name, s_name>
111 weak_foo_service;
112
113
114 BEGIN_COMPONENT_REQUIRES(component_foo)
115 ...
116 REQUIRES_SERVICE(registry_registration),
117 ...
118 END_COMPONENT_REQUIRES();
119
120 bool component_init() {
121 ...
122 if (weak_foo_service::init(SERVICE_PLACEHOLDER(registry),
123 SERVICE_PLACEHOLDER(registry_registration),
124 [&](SERVICE_TYPE(foo) * foo_svc) {
125 return 0 != foo_svc->define(12);
126 }))
127 return 1;
128 ...
129 }
130
131 bool component_deinit() {
132 ...
133 if (weak_option::deinit(SERVICE_PLACEHOLDER(registry),
134 SERVICE_PLACEHOLDER(registry_registration),
135 [&](SERVICE_TYPE(foo) * foo_svc) {
136 return 0 != foo_svc->undefine(12);
137 }))
138 return 1;
139 @endcode
140
141 @tparam Service This is the type of the service to be called. E.g.
142 SERVICE_TYPE(foo)
143 @tparam container The name of the "container". Usually a component name.
144 It has to be a rvalue ref since you would need a distinct set of the
145 static members of the template class for every service/component combo.
146 @tparam service_name The name of the service to try to call.
147 It has to be a rvalue ref since you would need a distinct set of the
148 static members of the template class for every service/component combo.
149*/
150template <typename Service, const std::string &container,
151 const std::string &service_name>
153 /**
154 A single instance of the class to hold (and initialize) some data
155 at init time.
156 */
158 nullptr};
159
160 /**
161 We need to store a reference to the registry since the init callback needs
162 it.
163 */
164 inline static SERVICE_TYPE(registry) * registry{nullptr};
165 /**
166 A flag stating if the callback service implementation listening
167 for new implementations of the service has been registered.
168 */
169 inline static bool callback_registered{false};
170
171 /**
172 true when the weak reference class is to keep the reference
173 acquired for reuse until deinit is called.
174 */
175 inline static bool keep_active_reference{true};
176
177 /**
178 A flag if the init callback function has been called.
179 This is to prevent multiple calls to the init callback.
180 Ideally we'd unregister the callback altogether, but the callback
181 is called while a reference to it is held, so it can't unregister
182 itself due to an active reference.
183 Hence we raise the flag to prevent further action and deregister
184 at deinit()
185 */
186 std::atomic<bool> function_called{false};
187 /**
188 The init callback reference.
189 */
190 const std::function<bool(Service *)> function;
191
192 /**
193 A service_loaded listener implementation name of the following format:
194 dynamic_loader_services_loaded_notification.&lt;conainer_name&gt;_&lt;service_name&gt;
195 */
196 std::string listener_name;
197
199
200 /**
201 @brief A private constructor for the hton
202
203 @param func_arg The function to call when there's an implementation.
204 active reference until deinit.
205 */
206 weak_service_reference(std::function<bool(Service *)> &func_arg)
207 : function(func_arg) {
209 std::string("dynamic_loader_services_loaded_notification.") +
210 container + std::string("_") + service_name;
211 }
212
213 /**
214 @brief Helper function to take a reference to the service needed
215 and call the init callback function.
216
217 @retval true failure
218 @retval false success
219 */
220 static bool call_function() {
222 if (!hton->service_reference.is_valid())
223 hton->service_reference.acquire(service_name.c_str(), registry);
224
225 if (hton->service_reference.is_valid()) {
226 if (hton->function(hton->service_reference)) return true;
227 hton->function_called = true;
228 }
229 } else {
230 my_service<Service> svc(service_name.c_str(), registry);
231 if (svc.is_valid()) {
232 if (hton->function(svc)) return true;
233 hton->function_called = true;
234 }
235 }
236 return false;
237 }
238
239 /**
240 @brief An implementation for the
241 dynamic_loader_services_loaded_notification::notify service method
242
243 This is called by the dynamic loader when a new service implementation
244 is registered.
245 */
247 (const char **services, unsigned int count)) try {
248 if (!keep_active_reference || !hton->function_called) {
249 for (unsigned idx = 0; idx < count; idx++) {
250 std::string svc(services[idx]);
251 if (svc.length() > service_name.length() &&
252 svc[service_name.length()] == '.' && 0 == svc.find(service_name))
253 return call_function() ? 1 : 0;
254 }
255 }
256 return 0;
257 } catch (...) {
258 return 1;
259 }
260
261 public:
262 /**
263 @brief Initialize the weak reference class
264
265 @param reg_arg A reference to the registry service implementation
266 @param reg_reg_arg A reference to the registry_registration service
267 implementation
268 @param func_arg A function to be called when an implementation of the service
269 is available. Typically used to initialize some state, e.g. allocate
270 instance handles or register some features in registries.
271 @param keep_active_reference_arg True if weak_reference is to keep an active
272 reference until deinit.
273
274 This is typically called by the component initialization.
275 If there's already an implementation of the service required a reference to it
276 is obtained and is passed to the function callback from the argument.
277
278 If no implementations are available a listener for new implementation
279 registration (an implementation of the
280 dynamic_loader_services_loaded_notifications service) is registered into the
281 registry and the function returns.
282
283 @note Pass the "normal" references to the registry and the registry
284 registration services here. init() is called without any locks being held to
285 the registry.
286
287 @retval true Failure
288 @retval false Success
289 */
290 static bool init(SERVICE_TYPE(registry) * reg_arg,
291 SERVICE_TYPE(registry_registration) * reg_reg_arg,
292 std::function<bool(Service *)> func_arg,
293 bool keep_active_reference_arg = true) {
294 registry = reg_arg;
295 keep_active_reference = keep_active_reference_arg;
296 assert(hton == nullptr);
297 hton =
299 if (call_function()) return true;
300
301 if (!hton->function_called || !keep_active_reference) {
303 x, dynamic_loader_services_loaded_notification) notify
305 if (reg_reg_arg->register_service(
306 hton->listener_name.c_str(),
307 (my_h_service) const_cast<void *>(
308 (const void *)&SERVICE_IMPLEMENTATION(
309 x, dynamic_loader_services_loaded_notification))))
310 return true;
311 callback_registered = true;
312 }
313 return false;
314 }
315
316 /**
317 @brief Deinitializes a weak reference caller class
318
319 If the init callback was called it will try to acquire a reference to the
320 service and call the deinit callback if the reference is acquired.
321
322 Then it will deregister the dynamic_loader_services_loaded_notification
323 implementation, if it's been registered by init().
324
325 And it will then proceed to delete the state in hton and reset the class.
326
327 @param registry_arg A reference to the registry service implementation
328 @param registry_registration_arg A reference to the registry_registration
329 service implementation
330 @param deinit_func_arg A (deinit) function to call if an implementation of
331 the service required is definied. One typically reverses the action taken by
332 the registration callback here, e.g. diposes of state, deregisters features
333 etc.
334
335 @retval true failure
336 @retval false success
337 */
338 static bool deinit(SERVICE_TYPE(registry) * registry_arg,
339 SERVICE_TYPE(registry_registration) *
340 registry_registration_arg,
341 std::function<bool(Service *)> deinit_func_arg) {
342 // the server may exit before init was called
343 if (hton == nullptr) return false;
344
346 if (hton->function_called) {
347 assert(hton->service_reference.is_valid());
348 if (deinit_func_arg(hton->service_reference)) return true;
349 }
350 /*
351 We need to release explicitly here becase it was acquired with the
352 registry at init but we need to release it with the registry argument
353 supplied.
354 */
355 if (hton->service_reference.is_valid()) {
356 my_service<Service> svc(hton->service_reference, registry_arg);
357 svc.release();
358 hton->service_reference.untie();
359 }
360 } else {
361 if (hton->function_called) {
362 my_service<Service> svc(service_name.c_str(), registry_arg);
363 if (svc.is_valid() && deinit_func_arg(svc)) return true;
364 }
365 }
367 registry_registration_arg->unregister(hton->listener_name.c_str()))
368 return true;
369 delete hton;
370 hton = nullptr;
371 registry = nullptr;
372 callback_registered = false;
373 return false;
374 }
375
376 /**
377 @brief Get the service reference, if available
378
379 If you need to call more methods of the service the weak service reference
380 wraps around you can use this cast operator.
381 Warning: it might return a null pointer if the weak reference doesn't hold
382 an active reference (init()'s keep_active_reference_arg parameter is false).
383
384 @sa @ref my_service
385
386 @return Returns a service reference, if available. And a nullptr if mot.
387 */
388 static Service *get_service() {
389 return hton ? ((Service *)hton->service_reference) : nullptr;
390 }
391
392 /**
393 @brief Gets the my_h_service reference, if available
394
395 See the other cast operator for details.
396
397 Warning: it might return a null pointer if the weak reference doesn't hold
398 an active reference (init()'s keep_active_reference_arg parameter is false).
399
400 @return my_h_service Same as the other cast operator, but instead of
401 downcasting to the service class it will return the raw my_h_service.
402
403 @sa @ref my_service
404 */
406 return hton ? hton->service_reference : nullptr;
407 }
408};
409
410#endif /* WEAK_REQUIRES_SERVICE_GUARD */
Wraps my_h_service struct conforming ABI into RAII C++ object with ability to cast to desired service...
Definition: my_service.h:35
bool is_valid() const
Definition: my_service.h:127
void release()
Releases the reference, if any, and cleans the instance up.
Definition: my_service.h:104
A utility class to implement a delayed service reference.
Definition: weak_service_reference.h:152
static my_h_service get_my_hservice()
Gets the my_h_service reference, if available.
Definition: weak_service_reference.h:405
static weak_service_reference< Service, container, service_name > * hton
A single instance of the class to hold (and initialize) some data at init time.
Definition: weak_service_reference.h:157
static bool keep_active_reference
true when the weak reference class is to keep the reference acquired for reuse until deinit is called...
Definition: weak_service_reference.h:175
static bool init(const mysql_service_registry_t *reg_arg, const mysql_service_registry_registration_t *reg_reg_arg, std::function< bool(Service *)> func_arg, bool keep_active_reference_arg=true)
Initialize the weak reference class.
Definition: weak_service_reference.h:290
std::string listener_name
A service_loaded listener implementation name of the following format: dynamic_loader_services_loaded...
Definition: weak_service_reference.h:196
static mysql_service_status_t notify(const char **services, unsigned int count) noexcept
An implementation for the dynamic_loader_services_loaded_notification::notify service method.
Definition: weak_service_reference.h:247
std::atomic< bool > function_called
A flag if the init callback function has been called.
Definition: weak_service_reference.h:186
my_service< Service > service_reference
Definition: weak_service_reference.h:198
static Service * get_service()
Get the service reference, if available.
Definition: weak_service_reference.h:388
static bool call_function()
Helper function to take a reference to the service needed and call the init callback function.
Definition: weak_service_reference.h:220
static bool callback_registered
A flag stating if the callback service implementation listening for new implementations of the servic...
Definition: weak_service_reference.h:169
static const mysql_service_registry_t * registry
We need to store a reference to the registry since the init callback needs it.
Definition: weak_service_reference.h:164
weak_service_reference(std::function< bool(Service *)> &func_arg)
A private constructor for the hton.
Definition: weak_service_reference.h:206
const std::function< bool(Service *)> function
The init callback reference.
Definition: weak_service_reference.h:190
static bool deinit(const mysql_service_registry_t *registry_arg, const mysql_service_registry_registration_t *registry_registration_arg, std::function< bool(Service *)> deinit_func_arg)
Deinitializes a weak reference caller class.
Definition: weak_service_reference.h:338
Connection event tracking.
struct my_h_service_imp * my_h_service
A handle type for acquired Service.
Definition: registry.h:33
static int count
Definition: myisam_ftdump.cc:45
Definition: atomics_array.h:39
Definition: services.cc:40
#define SERVICE_TYPE(name)
Generates the standard Service type name.
Definition: service.h:76
Specifies macros to define Service Implementations.
#define BEGIN_SERVICE_IMPLEMENTATION(component, service)
Declares a Service Implementation.
Definition: service_implementation.h:62
#define END_SERVICE_IMPLEMENTATION()
A macro to end the last declaration of a Service Implementation.
Definition: service_implementation.h:67
#define DEFINE_BOOL_METHOD(name, args)
A short macro to define method that returns bool, which is the most common case.
Definition: service_implementation.h:88
#define SERVICE_IMPLEMENTATION(component, service)
Reference to the name of the service implementation variable.
Definition: service_implementation.h:51