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