MySQL 26.7.0
Source Code Documentation
sync_bounded_queue_impl.hpp
Go to the documentation of this file.
1// Copyright (c) 2026, Oracle and/or its affiliates.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU General Public License, version 2.0,
5// as published by the Free Software Foundation.
6//
7// This program is designed to work with certain software (including
8// but not limited to OpenSSL) that is licensed under separate terms,
9// as designated in a particular file or component or in included license
10// documentation. The authors of MySQL hereby grant you an additional
11// permission to link the program and your derivative works with the
12// separately licensed software that they have either included with
13// the program or referenced in the documentation.
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, version 2.0, 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
25
26namespace mysql::concurrency {
27
28template <typename T, uint64_t capacity_tp>
29 requires Is_power_of_two<capacity_tp>
31
32template <typename T, uint64_t capacity_tp>
33 requires Is_power_of_two<capacity_tp>
34template <typename P>
35bool Sync_bounded_queue<T, capacity_tp>::enqueue(Element_type &&element,
36 P &&stop_predicate) {
37 auto idx = get_next_index(m_head);
38 auto &slot = m_slots[idx];
39 // In case we don't have space to save an item (unlikely to happen),
40 // we wait on condition variable
41 // @todo consider setting a stage
42 // @todo avoid blocking producer and return a boolean - implement try_enqueue
43 {
44 std::unique_lock<Mutex_type> lock(slot.validity_mt);
45 slot.producer_cv.wait(lock,
46 [&]() { return !slot.validity || stop_predicate(); });
47 if (slot.validity) {
48 return false;
49 }
50 // now we can insert
51 slot.element = std::move(element);
52 slot.validity = true;
53 }
54 // Notify consumers waiting for full slot
55 slot.consumer_cv.notify_one();
56 return true;
57}
58
59template <typename T, uint64_t capacity_tp>
60 requires Is_power_of_two<capacity_tp> bool
61Sync_bounded_queue<T, capacity_tp>::enqueue(Element_type &&element) {
62 return enqueue(std::move(element), []() { return false; });
63}
64
65template <typename T, uint64_t capacity_tp>
66 requires Is_power_of_two<capacity_tp>
67template <typename P>
69 P &&stop_predicate) {
70 auto idx = get_next_index(m_tail);
71 // we may block in case there are no elements, likely to happen when
72 // using a large amount of consumers
73 auto &slot = m_slots[idx];
74 std::unique_lock<Mutex_type> lock(slot.validity_mt);
75 // Wait for element or stop (exits immediately if either true)
76 slot.consumer_cv.wait(lock, [&stop_predicate, &slot]() {
77 return slot.validity || stop_predicate();
78 });
79 if (slot.validity) {
80 // Consume the element
81 T elem = std::move(slot.element);
82 slot.validity = false;
83 lock.unlock();
84 // Notify producers waiting for empty slot
85 slot.producer_cv.notify_one();
86 return {std::move(elem), true};
87 } else {
88 // Stop signaled, no element (predicate must be true since wait exited)
89 return {T{}, false};
90 }
91}
92
93template <typename T, uint64_t capacity_tp>
94 requires Is_power_of_two<capacity_tp> bool
96 // Exact emptiness check, handling wrap-around.
97 // Define M = std::numeric_limits<size_t>() + 1 - wrap point.
98 // Assumes max threads P < M/2 and ops N < M/2 between loads, where M is the
99 // wrap point. Returns true if no elements (head "ahead" of tail by less than
100 // half capacity).
101 auto tail_idx = m_tail.load();
102 auto head_idx = m_head.load();
103 return (tail_idx - head_idx) < (std::numeric_limits<size_t>::max() / 2);
104}
105
106template <typename T, uint64_t capacity_tp>
107 requires Is_power_of_two<capacity_tp>
109 std::atomic<std::size_t> &current) {
110 return current.fetch_add(1, std::memory_order_relaxed) % m_capacity;
111}
112
113template <typename T, uint64_t capacity_tp>
114 requires Is_power_of_two<capacity_tp>
116 // Wake all waiting threads to check stop_predicate
117 for (std::size_t idx = 0; idx < m_capacity; ++idx) {
118 m_slots[idx].producer_cv.notify_all();
119 m_slots[idx].consumer_cv.notify_all();
120 }
121}
122
123template <typename T, uint64_t capacity_tp>
124 requires Is_power_of_two<capacity_tp>
126 auto head = m_head.load();
127 auto tail = m_tail.load();
128 if (head < tail) {
129 if (tail - head >= std::numeric_limits<std::size_t>::max() / 2) {
130 // head wrapped
131 return head - tail;
132 } else {
133 // there are waiting consumers, and/or tail raced ahead of head between
134 // the two atomic loads
135 return 0;
136 }
137 } else {
138 // Normal case
139 return head - tail;
140 }
141}
142
143template <typename T, uint64_t capacity_tp>
144 requires Is_power_of_two<capacity_tp>
146 for (auto &slot : m_slots) {
147 std::unique_lock<Mutex_type> lock(slot.validity_mt);
148 slot.validity = false;
149 slot.element = T{};
150 }
151 m_head.store(0);
152 m_tail.store(0);
153}
154
155} // namespace mysql::concurrency
void notify_all()
Signal shutdown: Notifies all blocked consumers.
std::size_t get_next_index(std::atomic< std::size_t > &current)
Atomically increments the given position (m_head for producers, m_tail for consumers) and returns the...
bool enqueue(Element_type &&element, P &&stop_predicate)
Enqueue (push) an element into the queue.
Sync_bounded_queue(Memory_resource={})
Construct the queue.
void reset()
Reset the queue: Clears all slots (sets validity=false, elements to default), resets m_head and m_tai...
std::pair< Element_type, bool > dequeue(P &&stop_predicate)
Dequeue an element from the queue.
std::size_t size() const
Estimates the queue size based on m_head and m_tail positions.
bool empty()
Check if the queue is empty.
#define P
Definition: dtoa.cc:620
#define T
Definition: jit_executor_value.cc:373
Provides atomic access in shared-exclusive modes.
Definition: shared_spin_lock.h:79
ValueType max(X &&first)
Definition: gtid.h:103
Definition: cache_line_size.h:31
static std::mutex lock
Definition: net_ns.cc:56