MySQL 8.4.0
Source Code Documentation
lock_free_type.h
Go to the documentation of this file.
1/* Copyright (c) 2020, 2024, 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/** @file storage/temptable/include/temptable/lock_free_type.h
25Lock-free type (selection) implementation. */
26
27#ifndef TEMPTABLE_LOCK_FREE_TYPE_H
28#define TEMPTABLE_LOCK_FREE_TYPE_H
29
30#include <atomic>
31#include <type_traits>
32
33#include "my_config.h"
35
36namespace temptable {
37
38/** Enum class describing alignment-requirements. */
40
41/** Lock-free type selector, a helper utility which evaluates during
42 * the compile-time whether the given type T has a property of being
43 * always-lock-free for given platform. If true, Lock_free_type_selector::Type
44 * will hold T, otherwise Lock_free_type_selector::Type will be inexisting in
45 * which case static-assert will be triggered with a hopefully descriptive
46 * error-message. In the event of static-assert, one can either try to select
47 * another type T or, if one does not care about the actual underlying
48 * type representation, simply utilize the `Largest_lock_free_type_selector`
49 * utility instead. This utility will work out those details automagically. For
50 * more information, see documentation on `Largest_lock_free_type_selector`.
51 *
52 * In short, reasoning behind this machinery lies in the fact that the standard
53 * cannot guarantee that underlying implementation of std::atomic<T> is going
54 * to be able to use lock-free atomic CPU instructions. That obviously depends
55 * on the given type T but also on the properties of concrete platform.
56 * Therefore, actual implementation is mostly platform-dependent and is
57 * free to choose any other locking operation (e.g. mutex) as long as it is
58 * able to fulfill the atomicity. Lock-freedom is not a pre-requisite. Only
59 * exception is std::atomic_flag.
60 *
61 * For certain types, however, lock-freedom can be claimed upfront during the
62 * compile-time phase, and this is where this utiliy kicks in. It is essentially
63 * a C++14 rewrite of std::atomic<T>::is_always_lock_free which is only
64 * available from C++17 onwards. Once moved to C++17 this utility will become
65 * obsolete and shall be replaced with standard-compliant implementation.
66 *
67 * More details and motivation can be found at:
68 * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0152r0.html
69 * */
70template <typename T, typename V = void>
72 static_assert(
73 !std::is_same<T, T>::value,
74 "No always-lock-free property could be found for given type. "
75 "Type provided is probably not a built-in (fundamental) type or a "
76 "pointer which makes it impossible for this particular check to be "
77 "excercised at compile-time.");
78};
79
80/** Template-specialization for trivially-copyable classes/structs.
81 *
82 * Subset of trivially-copyable classes/structs might have always-lock-free
83 * property but for this feature to be implemented we would have to go at great
84 * lengths to implement cross-platform support. Therefore, for simplicity
85 * reasons let's just detect the overload and fail gracefully.
86 * */
87template <typename T>
89 T, typename std::enable_if<std::is_class<T>::value and
90 std::is_trivially_copyable<T>::value>::type> {
91 static_assert(!std::is_same<T, T>::value,
92 "Querying always-lock-free property of trivially-copyable "
93 "classes or structs is not yet implemented!");
94};
95
96/** Template-specialization for pointer types. */
97template <typename T>
99 T, typename std::enable_if<std::is_pointer<T>::value>::type> {
100#if (ATOMIC_POINTER_LOCK_FREE == 2)
101 using Type = T;
102#else
103 static_assert(false,
104 "Pointer type on this platform does not have an "
105 "always-lock-free property. Bailing out ...");
106#endif
107};
108
109/** Template-specialization for long long types. */
110template <typename T>
112 T,
113 typename std::enable_if<std::is_same<T, long long>::value or
114 std::is_same<T, unsigned long long>::value>::type> {
115#if (ATOMIC_LLONG_LOCK_FREE == 2)
116 using Type = T;
117#else
118 static_assert(false,
119 "(unsigned) long long type on this platform does not have an "
120 "always-lock-free property. Bailing out ...");
121#endif
122};
123
124/** Template-specialization for long types. */
125template <typename T>
127 T, typename std::enable_if<std::is_same<T, long>::value or
128 std::is_same<T, unsigned long>::value>::type> {
129#if (ATOMIC_LONG_LOCK_FREE == 2)
130 using Type = T;
131#else
132 static_assert(false,
133 "(unsigned) long type on this platform does not have an "
134 "always-lock-free property. Bailing out ...");
135#endif
136};
137
138/** Template-specialization for int types. */
139template <typename T>
141 T, typename std::enable_if<std::is_same<T, int>::value or
142 std::is_same<T, unsigned int>::value>::type> {
143#if (ATOMIC_INT_LOCK_FREE == 2)
144 using Type = T;
145#else
146 static_assert(false,
147 "(unsigned) int type on this platform does not have an "
148 "always-lock-free property. Bailing out ...");
149#endif
150};
151
152/** Template-specialization for short types. */
153template <typename T>
155 T, typename std::enable_if<std::is_same<T, short>::value or
156 std::is_same<T, unsigned short>::value>::type> {
157#if (ATOMIC_SHORT_LOCK_FREE == 2)
158 using Type = T;
159#else
160 static_assert(false,
161 "(unsigned) short type on this platform does not have an "
162 "always-lock-free property. Bailing out ...");
163#endif
164};
165
166/** Template-specialization for char types. */
167template <typename T>
169 T, typename std::enable_if<std::is_same<T, char>::value or
170 std::is_same<T, unsigned char>::value>::type> {
171#if (ATOMIC_CHAR_LOCK_FREE == 2)
172 using Type = T;
173#else
174 static_assert(false,
175 "(unsigned) char type on this platform does not have an "
176 "always-lock-free property. Bailing out ...");
177#endif
178};
179
180/** Template-specialization for boolean types. */
181template <typename T>
183 T, typename std::enable_if<std::is_same<T, bool>::value>::type> {
184#if (ATOMIC_BOOL_LOCK_FREE == 2)
185 using Type = T;
186#else
187 static_assert(false,
188 "bool type on this platform does not have an "
189 "always-lock-free property. Bailing out ...");
190#endif
191};
192
193/** Largest lock-free type selector, a helper utility very much similar
194 * to Lock_free_type_selector with the difference being that it tries hard
195 * not to fail. E.g. it will try to find the largest available T for given
196 * platform which has a property of being always-lock-free. T which has been
197 * selected is then found in Largest_lock_free_type_selector::Type.
198 * Signedness of T is respected.
199 * */
200template <typename T, typename V = void>
202 static_assert(
203 !std::is_same<T, T>::value,
204 "No always-lock-free property could be found for given type. "
205 "Type provided is probably not a built-in (fundamental) type or a "
206 "pointer which makes it impossible for this particular check to be "
207 "excercised at compile-time.");
208};
209
210/** Template-specialization for pointer types. */
211template <typename T>
213 T, typename std::enable_if<std::is_pointer<T>::value>::type> {
214#if (ATOMIC_POINTER_LOCK_FREE == 2)
215 using Type = T;
216#else
217 static_assert(false,
218 "Pointer type on this platform does not have an "
219 "always-lock-free property. Bailing out ...");
220#endif
221};
222
223/** Template-specialization for integral types. */
224template <typename T>
226 T, typename std::enable_if<std::is_integral<T>::value>::type> {
227#if (ATOMIC_LLONG_LOCK_FREE == 2)
228 using Type = std::conditional_t<std::is_unsigned<T>::value,
229 unsigned long long, long long>;
230#elif (ATOMIC_LONG_LOCK_FREE == 2)
231 using Type =
232 std::conditional_t<std::is_unsigned<T>::value, unsigned long, long>;
233#elif (ATOMIC_INT_LOCK_FREE == 2)
234 using Type =
235 std::conditional_t<std::is_unsigned<T>::value, unsigned int, int>;
236#elif (ATOMIC_SHORT_LOCK_FREE == 2)
237 using Type =
238 std::conditional_t<std::is_unsigned<T>::value, unsigned short, short>;
239#elif (ATOMIC_CHAR_LOCK_FREE == 2)
240 using Type =
241 std::conditional_t<std::is_unsigned<T>::value, unsigned char, char>;
242#elif (ATOMIC_BOOL_LOCK_FREE == 2)
243 using Type = bool;
244#else
245 static_assert(
246 false,
247 "No suitable always-lock-free type was found for this platform. "
248 "Bailing out ...");
249#endif
250};
251
252/** Representation of an atomic type which is guaranteed to be always-lock-free.
253 * In case always-lock-free property cannot be satisfied for given T,
254 * Lock_free_type instantiation will fail with the compile-time error.
255 *
256 * Always-lock-free guarantee is implemented through the means of
257 * Lock_free_type_selector or Largest_lock_free_type_selector. User code can
258 * opt-in for any of those. By default, Lock_free_type_selector is used.
259 *
260 * In addition, this type provides an ability to redefine the
261 * alignment-requirement of the underlying always-lock-free type, basically
262 * making it possible to over-align T to the size of the L1-data cache-line
263 * size. By default, T has a natural alignment.
264 */
265template <typename T, Alignment ALIGN = Alignment::NATURAL,
266 template <typename, typename = void> class TypeSelector =
269 using Type = typename TypeSelector<T>::Type;
270 std::atomic<Type> m_value;
271};
272
273/*
274 * Template-specialization for Lock_free_type with alignment-requirement set to
275 * L1-data cache size.
276 * */
277template <typename T, template <typename, typename = void> class TypeSelector>
278struct Lock_free_type<T, Alignment::L1_DCACHE_SIZE, TypeSelector> {
279 using Type = typename TypeSelector<T>::Type;
280 alignas(L1_DCACHE_SIZE) std::atomic<Type> m_value;
281};
282
283} // namespace temptable
284
285#endif /* TEMPTABLE_LOCK_FREE_TYPE_H */
Type
Definition: resource_group_basic_types.h:33
Definition: gcs_xcom_synode.h:64
Definition: allocator.h:45
Alignment
Enum class describing alignment-requirements.
Definition: lock_free_type.h:39
constexpr size_t L1_DCACHE_SIZE
Store L1-dcache size information into the constexpr expression.
Definition: constants.h:82
required string type
Definition: replication_group_member_actions.proto:34
TempTable constants.
Largest lock-free type selector, a helper utility very much similar to Lock_free_type_selector with t...
Definition: lock_free_type.h:201
typename TypeSelector< T >::Type Type
Definition: lock_free_type.h:279
Lock-free type selector, a helper utility which evaluates during the compile-time whether the given t...
Definition: lock_free_type.h:71
Representation of an atomic type which is guaranteed to be always-lock-free.
Definition: lock_free_type.h:268
typename TypeSelector< T >::Type Type
Definition: lock_free_type.h:269
std::atomic< Type > m_value
Definition: lock_free_type.h:270