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