MySQL 26.7.0
Source Code Documentation
ut0atomic_sysvar.h
Go to the documentation of this file.
1/* Copyright (c) 2023, 2026, Oracle and/or its affiliates.
2
3This program is free software; you can redistribute it and/or modify it under
4the terms of the GNU General Public License, version 2.0, as published by the
5Free 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, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
18for more details.
19
20You should have received a copy of the GNU General Public License along with
21this program; if not, write to the Free Software Foundation, Inc.,
2251 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23*/
24
25#pragma once
26#include <atomic> /* std::atomic */
27#include <functional> /* std::function */
28#include <type_traits>
29#include <vector>
30#include "sql_class.h" /* THD, SYS_VAR */
31
32extern std::vector<std::function<void()>> innodb_sysvar_initializers;
33
34/** A helper class for numeric sysvars which can be read in thread-safe way. */
35template <typename T>
37 /** Contains all members of Atomic_sysvar<T> in a standard layout struct -
38 which, among other things, means we can't mix private with public, use virtual
39 methods, nor std::function<>. We need a struct with standard layout in which
40 the non-atomic variable is at offset 0, to make it possible to convert a
41 pointer to the non-atomic variable registered via plugin API, to a
42 pointer to the whole struct containing the atomic we need to update and
43 callback we need to call on each change of registered variable. */
44 struct Data {
45 /** InnoDB code should not look at this, nor modify this directly (except in
46 the update() function defined here).
47 This will be registered via plugin API and managed by Server layer.
48 It must be the first member.
49 Note: Server modifies this directly without calling update() at startup. */
51
52 /** This stores the atomic variable which InnoDB threads might access at any
53 moment via load(). It has a copy of m_nonatomic value, detected either
54 during innodb_init_params() or in update() handler. */
55 std::atomic<T> m_atomic;
56
57 /** This is a callback provided by InnoDB to be called after each change of
58 the value which happens after innodb_init_params(), i.e. when performing
59 SET. Note: this includes recovered values of SET PERSIST. */
60 void (*m_after_change)();
62
63 public:
64 /** Constructs the atomic sysvar, initializes its value to zero and makes sure
65 innodb_init_params() will remember to copy the nonatomic value to atomic value
66 once Server layer finishes modifying the nonatomic value during its
67 initialization.
68 @param[in] after_change
69 A callback to be called *after* value changed due to SET or
70 recovery of value stored with SET PERSIST. */
71 explicit Atomic_sysvar(void (*after_change)())
72 /* The values we set here do not matter as m_nontatomic will anyway be
73 overwritten by the Server layer several times without notifying us via
74 update(), before eventually Server calls innodb_init_params() at which
75 point the m_nonatomic is equal to the value the Server has settled for,
76 which reflects the combination the default, the command line arguments and
77 the config files, but not the values persisted via SET PERSIST - these are
78 handled even later, as if a user executed SET again, and thus that
79 triggers update(). We register our var in innodb_sysvar_initializers here,
80 which innodb_init_params() iterates over, to ensure m_atomic matches
81 m_nonatomic after the Server settles on the value, and any later updates
82 such as those resulting from handling values PERSISTed in mysqld-auto.cnf
83 are handled later via update() callback. */
84 : m_data{0, 0, after_change} {
86 [this]() { m_data.m_atomic.store(m_data.m_nonatomic); });
87 }
88
89 /** Get the current value of the sys-var without UB. */
90 [[nodiscard]] T load() const { return m_data.m_atomic.load(); }
91
92 /** Get the variable which we want to register via plugin API. Do not use this
93 method in InnoDB code - use load() instead. */
94 [[nodiscard]] T &registrable() { return m_data.m_nonatomic; }
95
96 /** This is on-update handler registered via plugin API for all sysvars of
97 this type. It is called after new value was validated, but before it was
98 assigned. It is the responsibility of this function to assign new_value to
99 target.
100 @param[in] target This points to Data::m_nonatomic
101 @param[in] new_value This is the new value to be assigned to the sysvar */
102 static void update(THD *, SYS_VAR *, void *target, const void *new_value) {
103 static_assert(std::is_standard_layout_v<Data>);
104 static_assert(offsetof(Data, m_nonatomic) == 0);
105 auto var = static_cast<Data *>(target);
106 ut_ad(&var->m_nonatomic == target);
107 var->m_nonatomic = *static_cast<const T *>(new_value);
108 var->m_atomic.store(var->m_nonatomic);
109 if (var->m_after_change) {
110 var->m_after_change();
111 }
112 }
113};
114
115/* Unfortunately, because there's no nice mapping from C++ type to macro name,
116we have to manually provide following declarations for each type. */
117
118#define ATOMIC_SYSVAR_ULONG(sysvar_name_suffix, flags, description, validate, \
119 after_change, default_value, min_value, max_value, \
120 value_granularity) \
121 Atomic_sysvar<ulong> innodb_##sysvar_name_suffix(after_change); \
122 static MYSQL_SYSVAR_ULONG( \
123 sysvar_name_suffix, innodb_##sysvar_name_suffix.registrable(), flags, \
124 description, validate, innodb_##sysvar_name_suffix.update, \
125 default_value, min_value, max_value, value_granularity)
A helper class for numeric sysvars which can be read in thread-safe way.
Definition: ut0atomic_sysvar.h:36
T & registrable()
Get the variable which we want to register via plugin API.
Definition: ut0atomic_sysvar.h:94
static void update(THD *, SYS_VAR *, void *target, const void *new_value)
This is on-update handler registered via plugin API for all sysvars of this type.
Definition: ut0atomic_sysvar.h:102
struct Atomic_sysvar::Data m_data
T load() const
Get the current value of the sys-var without UB.
Definition: ut0atomic_sysvar.h:90
Atomic_sysvar(void(*after_change)())
Constructs the atomic sysvar, initializes its value to zero and makes sure innodb_init_params() will ...
Definition: ut0atomic_sysvar.h:71
For each client connection we create a separate thread with THD serving as a thread/connection descri...
Definition: sql_lexer_thd.h:36
#define T
Definition: jit_executor_value.cc:373
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2724
Contains all members of Atomic_sysvar<T> in a standard layout struct - which, among other things,...
Definition: ut0atomic_sysvar.h:44
T m_nonatomic
InnoDB code should not look at this, nor modify this directly (except in the update() function define...
Definition: ut0atomic_sysvar.h:50
std::atomic< T > m_atomic
This stores the atomic variable which InnoDB threads might access at any moment via load().
Definition: ut0atomic_sysvar.h:55
void(* m_after_change)()
This is a callback provided by InnoDB to be called after each change of the value which happens after...
Definition: ut0atomic_sysvar.h:60
Definition: system_variables_bits.h:153
std::vector< std::function< void()> > innodb_sysvar_initializers
Set of callbacks to be executed in innodb_init_params() to react to changes server layer did directly...
Definition: ha_innodb.cc:4742
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:109