MySQL 9.1.0
Source Code Documentation
bgc_ticket_manager.h
Go to the documentation of this file.
1/* Copyright (c) 2022, 2024, 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
24#ifndef BINLOG_BCG_TICKET_MANAGER_H
25#define BINLOG_BCG_TICKET_MANAGER_H
26
29
30namespace binlog {
31/**
32 Enumeration for passing options to `Bgc_ticket_manager` operations.
33 */
34enum class BgcTmOptions {
35 /** No options */
36 empty = 0,
37 /**
38 While performing some other operation (e.g. push, pop), atomically
39 increment the related session counter.
40 */
42};
43
44/**
45 @class Bgc_ticket_manager
46
47 Singleton class that manages the grouping of sessions for the Binlog
48 Group Commit (BGC), using a ticketing system.
49
50 Entities
51 --------
52 The envolved abstract entities are:
53 - Ticket: represented by a number, it has a processing window within
54 which one may decide the amount of sessions one wish to have processed.
55 - Session: the unit for what will be processed within a ticket processing
56 window. Usually, it represent THD sessions reaching the beginning of
57 the binlog group commit but it's just an abstract concept.
58 - Front Ticket: the ticket for which the processing window is active.
59 - Back Ticket: the ticket that is open to assigning more sessions, it may
60 or may not have it's processing window active.
61 - On-wait Tickets: tickets that aren't open to assigning more sessions
62 and haven't, yet, had their processing window activacted.
63 - Session-count Queue: a queue keeping the total sessions assigned to
64 each ticket that is closed to assignments (front + on-wait).
65
66 Operations
67 ----------
68 The overall set of available operations are:
69 - Request a session to be assigned to a ticket.
70 - Initialize a new back ticket, meaning that after such operation any
71 subsequent requests to assign a session to a ticket will assign to the
72 newly created ticket.
73 - Mark a given session or a set of sessions as processed within the front
74 ticket window.
75 - Close the processing window for the front ticket and activate the
76 processing window for the next ticket in line.
77
78 Members
79 -------
80 The class variable members are:
81 - A pointer to the front ticket.
82 - A pointer to the back ticket.
83 - A counter for the amount of sessions processed within the front ticket
84 window.
85 - A counter for the amount of sessions assigned to the back ticket.
86 - A queue that holds the amount of sessions assigned to all the tickets
87 that are closed for assginment (front + on-wait).
88
89 There is always an active back ticket and an active front ticket. At
90 instance initialization, both are set to `1` and, in the possibility of
91 the underlying ticket counter variable to wrap around, the first number
92 will still be `1`. The maximum value for a ticket is 2^63-1.
93
94 Thread-safe and serialization
95 -----------------------------
96 All operations are thread-safe. The operations of assigning a session to
97 the back ticket (`assign_sesssion_to_ticket`) and of closing the back
98 ticket to assignments and creating a new one (`push_new_ticket`) are
99 serialized between them. The operations of adding a session to the front
100 ticket processed sessions count (`add_processed_sessions_to_front_ticket`) and
101 of closing the front ticket processing window (`pop_front_ticket`) are
102 serialized between them. Any other type of concurrence between operations is
103 serialized only at the atomic variable level.
104
105 Serialization between the above described operations is necessary to keep
106 consistent and in-sync the class member values while changing or
107 checkings the ticket session counters and changing the ticket pointers.
108
109 Operations are serialized by using the most significant bit of each of
110 the ticket pointer atomic variables and mark them as in use (set to `1`)
111 or not in use (set to `0`). The first thread to be able to compare the
112 ticket pointer atomic variable with a value that has the most significant
113 bit unset and exchange it by a value with the most significant bit set
114 (using a CAS) gets the ownership over the pointer operations. This
115 mechanism allows us to atomically compare two distinct values, the ticket
116 value in itself and whether or not it's in use by another thread.
117
118 Usage patterns
119 --------------
120 The API usage may be divided in three common patterns:
121 1. Processing-window-wait: assign a session to a ticket, wait for the
122 assigned ticket to get to the front and have an active processing
123 window and add the session to the front ticket processed sessions.
124 2. Front-ticket-closing: assign a session to a ticket, wait for the
125 assigned ticket to get to the front, finish the front ticket
126 processing window and notify all waiting threads that a new front
127 ticket processing window is activated.
128 3. Back-ticket-closing: close the back ticket to assigments and create a
129 new back ticket.
130
131 Processing-window-wait
132 ----------------------
133 In this pattern, the back ticket assigned sessions counter is incremented
134 and the back ticket is returned to the API caller. The caller should wait
135 for the returned ticket to be the front ticket, in order to be able to
136 add the session to the front ticket processed sessions counter. The code
137 pattern is something along the lines:
138
139 // Global shared scope
140 std::mutex ticket_processing_window_mtx;
141 std::condition_variable ticket_processing_window;
142 ...
143 auto &ticket_manager = binlog::Bgc_ticket_manager::instance();
144 auto this_thread_ticket = ticket_manager.assign_session_to_ticket();
145
146 while (this_thread_ticket != ticket_manager.get_front_ticket()) {
147 std::unique_lock lock{ticket_processing_window_mtx};
148 ticket_processing_window.wait(lock);
149 }
150 ticket_manager.add_processed_sessions_to_front_ticket(1);
151 ...
152
153 Front-ticket-closing
154 --------------------
155 In this pattern, the back ticket assigned sessions counter is incremented
156 and the back ticket is returned to the API caller. The caller should wait
157 for the returned ticket to be the front ticket, in order to be able to
158 add the session to the front ticket processed sessions counter. Only
159 then, it is in a position to close the front ticket processing window,
160 start a new front ticket processing window and notify all threads. The
161 code pattern is something along the lines:
162
163 // Global shared scope
164 std::mutex ticket_processing_window_mtx;
165 std::condition_variable ticket_processing_window;
166 ...
167 auto &ticket_manager = binlog::Bgc_ticket_manager::instance();
168 auto this_thread_ticket = ticket_manager.assign_session_to_ticket();
169
170 while (this_thread_ticket != ticket_manager.get_front_ticket()) {
171 std::this_thread::yield();
172 }
173 ticket_manager.add_processed_sessions_to_front_ticket(1);
174
175 while (std::get<1>(ticket_manager.pop_front_ticket()) ==
176 this_thread_ticket) {
177 {
178 std::unique_lock lock{ticket_processing_window_mtx};
179 ticket_processing_window.notify_all();
180 }
181 std::this_thread::yield();
182 }
183 ...
184
185 Note that there is a loop associated with `pop_front_ticket`. This
186 operation only closes the front ticket processing window if the counter
187 for the front ticket assigned sessions equals the counter for the front
188 ticket processed sessions. Since the function returns an `std::pair` with
189 the front ticket values before and after the operation, one may need to
190 check if the values are different.
191
192 When `pop_front_ticket` returns different before and after values, it
193 means that the front ticket pointer now points to the after value and
194 that the assigned sessions count for the before value was poped from the
195 session-count queue.
196
197 Back-ticket-closing
198 -------------------
199 In this pattern, the back ticket assigned sessions count is pushed into
200 the session-count queue, set to `0` and the back ticket pointer is set to
201 the next value. The code pattern is something along the lines:
202
203 auto [before_ticket, after_ticket] = ticket_manager.push_new_ticket();
204
205 If there is the need to assign a session to the finishing back ticket
206 before it's finished and do it atomically with the finish operation, the
207 following code pattern is also supported:
208
209 auto [before_ticket, after_ticket] = ticket_manager.push_new_ticket(
210 binlog::BgcTmOptions::inc_session_count);
211
212 The above means that a session was assigned to the `before_ticket` (added
213 to assigned sessions counter) before such value was pushed to the
214 session-count queue.
215
216 @see unittest/gunit/bgc_ticket_manager-t.cc
217 */
219 public:
220 using queue_value_type = std::uint64_t;
222
223 /**
224 Maximum allowed number of on-wait tickets and the capacity of the
225 underlying session-count queue.
226 */
227 static constexpr size_t max_concurrent_tickets = 1024;
228
229 /**
230 Default destructor.
231 */
232 virtual ~Bgc_ticket_manager() = default;
233
234 // Remove copy-move semantics
239
240 /**
241 Coalesces all tickets into a single ticket and opens new processing and
242 assignment windows.
243
244 @return The ticket manager instance, for chaining purposes.
245 */
247 /**
248 Assigns a session to the back ticket. It increments the back ticket
249 assigned sessions counter.
250
251 @return The ticket the session was assigned to.
252 */
254 /**
255 Sets given session count as processed within the front ticket
256 processing window. It adds the given sessions parameter to the front
257 ticket processed sessions counter.
258
259 @param sessions_to_add The number of sessions to set as processed with
260 the front ticket window.
261 @param ticket The session ticket (used for validations).
262
263
264 @return The number of sessions processed in the front ticket window
265 after the operation sucessfully concluded.
266 */
268 queue_value_type sessions_to_add, const binlog::BgcTicket &ticket);
269 /**
270 Retrieves the front ticket, for which the processing window is open.
271
272 @return The front ticket.
273 */
275 /**
276 Retrieves the back ticket, which is open to session assignments.
277
278 @return The back ticket.
279 */
281 /**
282 Retrieves the coalesced ticket, if any coalesce.
283
284 @return The coalesced ticket, which may be 0 if no coalesce operation has
285 been performed.
286 */
288 /**
289 Closes the current back ticket to sesssion assignments, pushes the back
290 ticket assgined sessions counter to the session-count queue, set it to
291 `0` and sets the back ticket pointer to the next value.
292
293 If the back ticket assigned sessions counter is `0` just before pushing
294 it to the session-count queue and changing the back ticket pointer,
295 none of these two operations will happen and the returned pair will
296 have matching values.
297
298 If the `options` parameter has the `inc_session_count` option
299 set, the back ticket assigned sessions count is incremented before
300 being pusheed to the session-count queue.
301
302 @param options Allowed values are combinations of `empty` and
303 `inc_session_count`
304
305 @return A pair holding the before and after invocation back ticket
306 pointer values.
307 */
308 std::pair<binlog::BgcTicket, binlog::BgcTicket> push_new_ticket(
310 /**
311 Closes the current front ticket processing window, pops the front
312 ticket assigned sessions count from the session-count queue, sets the
313 front ticket processed sessions counter to `0` and sets the front
314 ticket pointer to the next value in lne.
315
316 If the front ticket processed sessions count doesn't match the front
317 ticket assgined sessions count, this function is a no-op and the
318 returned pair will have matching values.
319
320 If the `options` parameter has the `inc_session_count` option
321 set, the front ticket processed sessions count is incremented before
322 being compared with the front ticket assigned sessions count.
323
324 @param options Allowed values are combinations of `empty` and
325 `inc_session_count`
326
327 @return A pair holding the before and after invocation front ticket
328 pointer values.
329 */
330 std::pair<binlog::BgcTicket, binlog::BgcTicket> pop_front_ticket(
332 /**
333 Returns the textual representation of this object.
334
335 @return a string containing the textual representation of this object.
336 */
337 std::string to_string() const;
338 /**
339 Dumps the textual representation of this object into the given output
340 stream.
341
342 @param out The stream to dump this object into.
343 */
344 void to_string(std::ostream &out) const;
345 /**
346 Dumps the textual representation of an instance of this class into the
347 given output stream.
348
349 @param out The output stream to dump the instance to.
350 @param to_dump The class instance to dump to the output stream.
351
352 @return The output stream to which the instance was dumped to.
353 */
354 inline friend std::ostream &operator<<(std::ostream &out,
355 Bgc_ticket_manager const &to_dump) {
356 to_dump.to_string(out);
357 return out;
358 }
359
360 /**
361 Retrieves the single instance of the class.
362
363 @return The single instance of the class.
364 */
366
367 private:
368 /** The pointer to the ticket that is open to assigning more sessions. */
370 /** The pointer to the ticket for which the processing window is active. */
372 /**
373 The pointer to the coalesced ticket, 0 means that the coalescing has not
374 been requested yet.
375 */
377 /** The number of sessions assigned to the back ticket. */
379 /** The number of sessions processed in the front ticket window. */
381 /**
382 The queue keeping the total sessions assigned to each ticket that is
383 closed to assignments (front + on-wait).
384 */
386
387 /**
388 Default constructor.
389 */
391};
392} // namespace binlog
393#endif // BINLOG_BCG_TICKET_MANAGER_H
Implements atomic ops on BgcTicket object.
Definition: atomic_bgc_ticket.h:43
Represents the Binlog Group Commit Ticket - BGC Ticket.
Definition: bgc_ticket.h:54
static constexpr ValueType first_ticket_value
Minimum allowed value for a ticket.
Definition: bgc_ticket.h:153
Singleton class that manages the grouping of sessions for the Binlog Group Commit (BGC),...
Definition: bgc_ticket_manager.h:218
binlog::BgcTicket get_back_ticket() const
Retrieves the back ticket, which is open to session assignments.
Definition: bgc_ticket_manager.cc:65
std::pair< binlog::BgcTicket, binlog::BgcTicket > pop_front_ticket(BgcTmOptions options=BgcTmOptions::empty)
Closes the current front ticket processing window, pops the front ticket assigned sessions count from...
Definition: bgc_ticket_manager.cc:91
AtomicBgcTicket m_coalesced_ticket
The pointer to the coalesced ticket, 0 means that the coalescing has not been requested yet.
Definition: bgc_ticket_manager.h:376
queue_type m_sessions_per_ticket
The queue keeping the total sessions assigned to each ticket that is closed to assignments (front + o...
Definition: bgc_ticket_manager.h:385
Bgc_ticket_manager()=default
Default constructor.
Bgc_ticket_manager(Bgc_ticket_manager const &)=delete
queue_value_type add_processed_sessions_to_front_ticket(queue_value_type sessions_to_add, const binlog::BgcTicket &ticket)
Sets given session count as processed within the front ticket processing window.
Definition: bgc_ticket_manager.cc:52
AtomicBgcTicket m_back_ticket
The pointer to the ticket that is open to assigning more sessions.
Definition: bgc_ticket_manager.h:369
friend std::ostream & operator<<(std::ostream &out, Bgc_ticket_manager const &to_dump)
Dumps the textual representation of an instance of this class into the given output stream.
Definition: bgc_ticket_manager.h:354
std::string to_string() const
Returns the textual representation of this object.
Definition: bgc_ticket_manager.cc:108
queue_value_type m_back_ticket_sessions_count
The number of sessions assigned to the back ticket.
Definition: bgc_ticket_manager.h:378
Bgc_ticket_manager & operator=(Bgc_ticket_manager &&)=delete
Bgc_ticket_manager(Bgc_ticket_manager &&)=delete
static constexpr size_t max_concurrent_tickets
Maximum allowed number of on-wait tickets and the capacity of the underlying session-count queue.
Definition: bgc_ticket_manager.h:227
binlog::BgcTicket get_coalesced_ticket() const
Retrieves the coalesced ticket, if any coalesce.
Definition: bgc_ticket_manager.cc:69
static Bgc_ticket_manager & instance()
Retrieves the single instance of the class.
Definition: bgc_ticket_manager.cc:128
std::pair< binlog::BgcTicket, binlog::BgcTicket > push_new_ticket(BgcTmOptions options=BgcTmOptions::empty)
Closes the current back ticket to sesssion assignments, pushes the back ticket assgined sessions coun...
Definition: bgc_ticket_manager.cc:74
binlog::BgcTicket assign_session_to_ticket()
Assigns a session to the back ticket.
Definition: bgc_ticket_manager.cc:45
std::uint64_t queue_value_type
Definition: bgc_ticket_manager.h:220
virtual ~Bgc_ticket_manager()=default
Default destructor.
Bgc_ticket_manager & operator=(Bgc_ticket_manager const &)=delete
Bgc_ticket_manager & coalesce()
Coalesces all tickets into a single ticket and opens new processing and assignment windows.
Definition: bgc_ticket_manager.cc:28
queue_value_type m_front_ticket_processed_sessions_count
The number of sessions processed in the front ticket window.
Definition: bgc_ticket_manager.h:380
AtomicBgcTicket m_front_ticket
The pointer to the ticket for which the processing window is active.
Definition: bgc_ticket_manager.h:371
binlog::BgcTicket get_front_ticket() const
Retrieves the front ticket, for which the processing window is open.
Definition: bgc_ticket_manager.cc:61
Definition: pfs.cc:38
BgcTmOptions
Enumeration for passing options to Bgc_ticket_manager operations.
Definition: bgc_ticket_manager.h:34
@ empty
No options.
@ inc_session_count
While performing some other operation (e.g.
Definition: options.cc:57