MySQL 9.6.0
Source Code Documentation
gtid.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2023, 2025, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef ROUTER_SRC_MYSQL_REST_SERVICE_SRC_MRS_DATABASE_HELPER_GTID_H_
27#define ROUTER_SRC_MYSQL_REST_SERVICE_SRC_MRS_DATABASE_HELPER_GTID_H_
28
29#include <array>
30#include <list>
31#include <optional>
32#include <string>
33#include <vector>
34
35#include "helper/string/from.h"
36#include "helper/string/hex.h" // unhex
39
40namespace mrs {
41namespace database {
42
43namespace inner {
44
46 public:
47 std::string to_string() const {
48 constexpr std::array<char, 16> hex_chars = {
49 '0', '1', '2', '3', '4', '5', '6', '7', //
50 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
51 };
52
53 std::string out;
54 out.reserve(raw.size() * 2 + 4);
55 size_t pos = 0;
56
57 for (uint8_t ch : raw) {
58 switch (pos++) {
59 case 4:
60 case 6:
61 case 8:
62 case 10:
63 out += '-';
64 }
65
66 out += hex_chars[ch >> 4];
67 out += hex_chars[ch & 0xf];
68 }
69
70 return out;
71 }
72};
73
74template <typename ValueType>
75ValueType abs(const ValueType v1, const ValueType v2) {
76 if (v1 < v2) return v2 - v1;
77 if (v1 > v2) return v1 - v2;
78
79 return 0;
80}
81
82template <typename ValueType>
83ValueType value(const std::optional<ValueType> &v) {
84 return v.value();
85}
86
87template <typename ValueType>
88inline ValueType value(const ValueType &v) {
89 return v;
90}
91
92template <typename ValueType>
93bool has_value(const std::optional<ValueType> &v) {
94 return v.has_value();
95}
96
97template <typename ValueType>
98inline bool has_value(const ValueType &) {
99 return true;
100}
101
102template <typename ValueType, typename X>
103ValueType max(X &&first) {
104 return value(first);
105}
106
107template <typename ValueType, typename X, typename... Args>
108ValueType max(X &&first, Args &&...rest) {
109 ValueType rest_value = inner::max<ValueType>(rest...);
110 if (!has_value(first)) return rest_value;
111 if (rest_value > value(first)) return rest_value;
112 return value(first);
113}
114
116 public:
117 GtidRange(uint64_t start = 0, std::optional<uint64_t> end = {})
118 : start_{start}, end_{end} {}
119
120 GtidRange(const GtidRange &other) : start_{other.start_}, end_{other.end_} {}
121
123 start_ = other.start_;
124 end_ = other.end_;
125 return *this;
126 }
127
128 bool operator==(const GtidRange &other) const {
129 if (start_ != other.start_) return false;
130 if (end_.has_value() != other.end_.has_value()) return false;
131 if (!end_.has_value()) return true;
132
133 return end_.value() == other.end_.value();
134 }
135
136 bool contains(const GtidRange &other) const {
137 if (start_ > other.start_) return false;
138
139 if (end_.has_value()) {
140 if (end_.value() < other.start_) return false;
141
142 if (!other.end_.has_value()) return true;
143
144 return other.end_.value() <= end_.value();
145 }
146
147 if (other.end_.has_value() && other.end_.value() != start_) return false;
148
149 return other.start_ == start_;
150 }
151
152 bool is_point() const { return !end_.has_value(); }
153
154 bool parse(const std::string &value) {
155 auto args = mysql_harness::split_string(value, '-', false);
156 switch (args.size()) {
157 case 2:
158 end_ = helper::to_uint64(args[1]);
159 [[fallthrough]];
160 case 1:
161 start_ = helper::to_uint64(args[0]);
162 break;
163 default:
164 return false;
165 }
166
167 if (0 == start_) return false;
168 if (end_.has_value() && 0 == end_.value()) return false;
169
170 return true;
171 }
172
173 bool try_merge(const GtidRange &other) {
174 // Not optimal implementation
175 if (contains(other)) return true;
176 if (other.contains(*this)) {
177 *this = other;
178 return true;
179 }
180
181 if (other.is_point()) {
182 if (1 == inner::abs(start_, other.start_)) {
183 start_ = std::min(start_, other.start_);
184 end_ = inner::max<uint64_t>(start_, end_, other.start_);
185
186 return true;
187 } else if (end_.has_value() && end_.value() == (other.start_ - 1)) {
188 end_ = other.start_;
189 return true;
190 }
191 return false;
192 }
193
194 if (is_point()) {
195 if (1 == inner::abs(start_, other.start_)) {
196 start_ = std::min(start_, other.start_);
197 end_ = inner::max<uint64_t>(start_, other.start_, other.end_);
198
199 return true;
200 } else if (other.end_.has_value() && start_ - 1 == other.end_) {
201 start_ = other.start_;
202 end_ = start_;
203 return true;
204 }
205 return false;
206 }
207
208 // This and other have two points and
209 // both ranges, doesn't contain each other
210 if (is_between(other.start_)) {
211 end_ = other.end_;
212 return true;
213 }
214
215 if (other.is_between(start_)) {
216 start_ = other.start_;
217 return true;
218 }
219
220 if (1 == static_cast<int64_t>(other.start_ - end_.value())) {
221 end_ = other.end_;
222 return true;
223 }
224
225 if (1 == static_cast<int64_t>(start_ - other.end_.value())) {
226 start_ = other.start_;
227 return true;
228 }
229
230 return false;
231 }
232
233 std::string to_string() const {
234 std::string result = ":" + std::to_string(start_);
235
236 if (end_.has_value()) {
237 result += "-" + std::to_string(end_.value());
238 }
239
240 return result;
241 }
242 uint64_t get_start() const { return start_; }
243 const std::optional<uint64_t> &get_end() const { return end_; }
244
245 GtidRange *begin() { return this; }
246 GtidRange *end() { return this + 1; }
247 const GtidRange *begin() const { return this; }
248 const GtidRange *end() const { return this + 1; }
249 uint64_t size() const { return 1; }
250
251 private:
252 bool is_between(const uint64_t value) const {
253 if (start_ <= value) {
254 if (end_.has_value() && end_.value() >= value) return true;
255 }
256 return false;
257 }
258 uint64_t start_;
259 std::optional<uint64_t> end_;
260};
261
263 public:
266
268 ranges_.clear();
269 ranges_.push_back(other);
270 return *this;
271 }
272
274 ranges_ = other.ranges_;
275 return *this;
276 }
277
278 bool operator==(const GtidSetOfRanges &other) const {
279 if (other.ranges_.size() != ranges_.size()) return false;
280
281 for (auto &r : ranges_) {
282 if (!other.has(r)) return false;
283 }
284
285 return true;
286 }
287
288 bool has(const GtidRange &other) const {
289 for (auto &r : ranges_) {
290 if (r == other) return true;
291 }
292 return false;
293 }
294
295 bool contains(const GtidRange &other) const {
296 for (auto &r : ranges_) {
297 if (r.contains(other)) return true;
298 }
299 return false;
300 }
301
302 bool contains(const GtidSetOfRanges &other) const {
303 for (auto &r : other.ranges_) {
304 if (!contains(r)) return false;
305 }
306 return true;
307 }
308
309 bool parse(const std::vector<std::string> &values) {
310 for (const auto &v : values) {
311 auto range = ranges_.emplace(ranges_.end());
312 if (!(*range).parse(v)) return false;
313 }
314 return true;
315 }
316
317 std::string to_string() const {
318 std::string result;
319 for (const auto &r : ranges_) {
320 result += r.to_string();
321 }
322 return result;
323 }
324
325 void insert(const GtidRange &other) {
326 auto it = ranges_.begin();
327
328 do {
329 if (other.get_start() < (*it).get_start()) {
330 ranges_.insert(it, other);
331 return;
332 }
333 ++it;
334 } while (it != ranges_.end());
335
336 ranges_.insert(it, other);
337 }
338
339 auto begin() { return ranges_.begin(); }
340 auto end() { return ranges_.end(); }
341 auto begin() const { return ranges_.begin(); }
342 auto end() const { return ranges_.end(); }
343 uint64_t size() const { return ranges_.size(); }
344
345 std::list<GtidRange> ranges_;
346};
347
348template <typename Range>
349class Gtid {
350 public:
351 template <typename... T>
352 Gtid(const GTIDuuid &uid, T &&...v) : uid_{uid}, range_{v...} {}
353
354 bool operator==(const Gtid &other) const {
355 if (uid_ != other.uid_) return false;
356
357 return range_ == other.range_;
358 }
359
360 template <typename OtherRange>
361 bool contains(const Gtid<OtherRange> &other) const {
362 if (uid_ != other.uid_) return false;
363 for (const auto &r : range_) {
364 bool all_matched = false;
365 for (const auto &orange : other.range_) {
366 if (!r.contains(orange)) break;
367 all_matched = true;
368 }
369 if (all_matched) return true;
370 }
371 return false;
372 }
373
374 bool parse(const std::string &gtid) {
375 auto result =
376 helper::string::unhex<std::string, helper::string::get_unhex_character>(
377 gtid);
378 if (result.size() != GTIDuuid::k_size) return false;
379
381 return true;
382 }
383
384 std::string to_string() const {
385 auto result = uid_.to_string();
386 result += range_.to_string();
387 return result;
388 }
389
390 bool try_merge(const GtidRange &range) {
391 for (auto &r : range_) {
392 if (r.try_merge(range)) return true;
393 }
394 return false;
395 }
396
397 template <typename SomeRange>
398 bool try_merge(const Gtid<SomeRange> &gtid) {
399 if (uid_ != gtid.uid_) return false;
400
401 return try_merge(gtid.range_);
402 }
403
404 template <typename SomeRange>
405 bool insert(const Gtid<SomeRange> &other) {
406 if (!(other.uid_ == uid_)) return false;
407
408 range_.insert(other.range_);
409
410 return true;
411 }
412
413 template <typename SomeRange>
414 void set(const Gtid<SomeRange> &other) {
415 uid_ = other.uid_;
416 range_ = other.range_;
417 }
418
419 uint64_t size() const { return range_.size(); }
420
421 const GTIDuuid &get_uid() const { return uid_; }
422 const Range &get_range() const { return range_; }
423
424 protected:
425 template <typename SomeRange>
426 friend class Gtid;
429};
430
431} // namespace inner
432
434
435class Gtid : public inner::Gtid<inner::GtidRange> {
436 public:
438
440 Gtid(const GTIDuuid &uid, const inner::GtidRange &r) : Parent(uid, r) {}
441 Gtid(const std::string &v) : Parent(GTIDuuid{}) {
442 if (!parse(v)) throw std::runtime_error("Invalid GTID");
443 }
444
445 public:
446 bool parse(const std::string &v) {
447 auto gtid_parts = mysql_harness::split_string(v, ':', false);
448 if (gtid_parts.size() != 2) return false;
449 if (!Parent::parse(gtid_parts[0])) return false;
450 return range_.parse(gtid_parts[1]);
451 }
452};
453
454class GtidSet : public inner::Gtid<inner::GtidSetOfRanges> {
455 public:
457
459
460 GtidSet(const std::string &v) : Gtid(GTIDuuid{}) {
461 if (!parse(v)) throw std::runtime_error("Invalid GTID-set");
462 }
463
464 public:
465 bool parse(const std::string &v) {
466 auto gtid_parts = mysql_harness::split_string(v, ':', false);
467 if (gtid_parts.size() < 2) return false;
468 if (!Parent::parse(gtid_parts[0])) return false;
469 gtid_parts.erase(gtid_parts.begin());
470 return range_.parse(gtid_parts);
471 }
472};
473
474using Gtids = std::vector<Gtid>;
475using GtidSets = std::vector<GtidSet>;
476
477} // namespace database
478} // namespace mrs
479
480#endif // ROUTER_SRC_MYSQL_REST_SERVICE_SRC_MRS_DATABASE_HELPER_GTID_H_
Definition: gtid.h:454
GtidSet()
Definition: gtid.h:458
bool parse(const std::string &v)
Definition: gtid.h:465
Gtid< inner::GtidSetOfRanges > Parent
Definition: gtid.h:456
GtidSet(const std::string &v)
Definition: gtid.h:460
Definition: gtid.h:435
bool parse(const std::string &v)
Definition: gtid.h:446
Gtid(const GTIDuuid &uid, const inner::GtidRange &r)
Definition: gtid.h:440
Gtid(const std::string &v)
Definition: gtid.h:441
Gtid()
Definition: gtid.h:439
Definition: gtid.h:45
std::string to_string() const
Definition: gtid.h:47
Definition: gtid.h:115
bool try_merge(const GtidRange &other)
Definition: gtid.h:173
uint64_t get_start() const
Definition: gtid.h:242
std::optional< uint64_t > end_
Definition: gtid.h:259
GtidRange & operator=(const GtidRange &other)
Definition: gtid.h:122
bool parse(const std::string &value)
Definition: gtid.h:154
GtidRange * end()
Definition: gtid.h:246
std::string to_string() const
Definition: gtid.h:233
GtidRange(const GtidRange &other)
Definition: gtid.h:120
const std::optional< uint64_t > & get_end() const
Definition: gtid.h:243
bool contains(const GtidRange &other) const
Definition: gtid.h:136
GtidRange(uint64_t start=0, std::optional< uint64_t > end={})
Definition: gtid.h:117
GtidRange * begin()
Definition: gtid.h:245
uint64_t size() const
Definition: gtid.h:249
const GtidRange * begin() const
Definition: gtid.h:247
bool is_point() const
Definition: gtid.h:152
uint64_t start_
Definition: gtid.h:258
const GtidRange * end() const
Definition: gtid.h:248
bool operator==(const GtidRange &other) const
Definition: gtid.h:128
bool is_between(const uint64_t value) const
Definition: gtid.h:252
GtidSetOfRanges(const GtidSetOfRanges &other)
Definition: gtid.h:265
bool has(const GtidRange &other) const
Definition: gtid.h:288
GtidSetOfRanges()
Definition: gtid.h:264
auto end()
Definition: gtid.h:340
bool operator==(const GtidSetOfRanges &other) const
Definition: gtid.h:278
bool contains(const GtidSetOfRanges &other) const
Definition: gtid.h:302
GtidSetOfRanges & operator=(const GtidSetOfRanges &other)
Definition: gtid.h:273
bool contains(const GtidRange &other) const
Definition: gtid.h:295
bool parse(const std::vector< std::string > &values)
Definition: gtid.h:309
GtidSetOfRanges & operator=(const GtidRange &other)
Definition: gtid.h:267
uint64_t size() const
Definition: gtid.h:343
std::string to_string() const
Definition: gtid.h:317
auto begin() const
Definition: gtid.h:341
std::list< GtidRange > ranges_
Definition: gtid.h:345
void insert(const GtidRange &other)
Definition: gtid.h:325
auto end() const
Definition: gtid.h:342
auto begin()
Definition: gtid.h:339
Definition: gtid.h:349
const GTIDuuid & get_uid() const
Definition: gtid.h:421
bool insert(const Gtid< SomeRange > &other)
Definition: gtid.h:405
Range range_
Definition: gtid.h:428
bool operator==(const Gtid &other) const
Definition: gtid.h:354
GTIDuuid uid_
Definition: gtid.h:427
bool try_merge(const Gtid< SomeRange > &gtid)
Definition: gtid.h:398
const Range & get_range() const
Definition: gtid.h:422
uint64_t size() const
Definition: gtid.h:419
Gtid(const GTIDuuid &uid, T &&...v)
Definition: gtid.h:352
bool parse(const std::string &gtid)
Definition: gtid.h:374
void set(const Gtid< SomeRange > &other)
Definition: gtid.h:414
std::string to_string() const
Definition: gtid.h:384
bool contains(const Gtid< OtherRange > &other) const
Definition: gtid.h:361
bool try_merge(const GtidRange &range)
Definition: gtid.h:390
static void start(mysql_harness::PluginFuncEnv *env)
Definition: http_auth_backend_plugin.cc:180
#define T
Definition: jit_executor_value.cc:373
static std::string to_string(const LEX_STRING &str)
Definition: lex_string.h:51
std::pair< os_offset_t, os_offset_t > Range
Represents the chunk in bytes : first element represents the beginning offset of the chunk and,...
Definition: ddl0impl-file-reader.h:44
uint64_t to_uint64(const String &str)
Definition: from.h:36
ValueType abs(const ValueType v1, const ValueType v2)
Definition: gtid.h:75
ValueType value(const std::optional< ValueType > &v)
Definition: gtid.h:83
bool has_value(const std::optional< ValueType > &v)
Definition: gtid.h:93
ValueType max(X &&first)
Definition: gtid.h:103
std::vector< Gtid > Gtids
Definition: gtid.h:474
inner::GTIDuuid GTIDuuid
Definition: gtid.h:433
std::vector< GtidSet > GtidSets
Definition: gtid.h:475
Definition: authorize_manager.h:48
mrs::database::entry::UniversalId UniversalId
Definition: universal_id.h:33
HARNESS_EXPORT std::vector< std::string > split_string(const std::string_view &data, const char delimiter, bool allow_empty=true)
Splits a string using a delimiter.
Definition: string_utils.cc:37
bool parse(MYSQL_THD thd, const string &query, bool is_prepared, Condition_handler *handler)
Definition: services.cc:81
const mysql_service_registry_t * r
Definition: pfs_example_plugin_employee.cc:86
struct result result
Definition: result.h:34
Array raw
Definition: universal_id.h:58
constexpr static uint64_t k_size
Definition: universal_id.h:46
static void from_raw(UniversalId *uid, const char *binray)
Definition: universal_id.h:97
Definition: gen_lex_token.cc:149
Definition: result.h:30
#define X(b)
Definition: xcom_base.cc:9207