1 /* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
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
22 02110-1301 USA */
23
24 #include "rpl_gtid.h"
25
26 #include <ctype.h>
27 #include <algorithm>
28 #include "my_dbug.h"
29 #include "mysqld_error.h"
30 #include <algorithm>
31
32 using std::min;
33 using std::max;
34
35 const Gtid_set::String_format Gtid_set::default_string_format=
36 {
37 "", "", ":", "-", ":", ",\n", "",
38 0, 0, 1, 1, 1, 2, 0
39 };
40
41
42 const Gtid_set::String_format Gtid_set::sql_string_format=
43 {
44 "'", "'", ":", "-", ":", "',\n'", "''",
45 1, 1, 1, 1, 1, 4, 2
46 };
47
48
49 const Gtid_set::String_format Gtid_set::commented_string_format=
50 {
51 "# ", "", ":", "-", ":", ",\n# ", "# [empty]",
52 2, 0, 1, 1, 1, 4, 9
53 };
54
55
Gtid_set(Sid_map * _sid_map,Checkable_rwlock * _sid_lock)56 Gtid_set::Gtid_set(Sid_map *_sid_map, Checkable_rwlock *_sid_lock)
57 : sid_lock(_sid_lock), sid_map(_sid_map)
58 {
59 init();
60 }
61
62
Gtid_set(Sid_map * _sid_map,const char * text,enum_return_status * status,Checkable_rwlock * _sid_lock)63 Gtid_set::Gtid_set(Sid_map *_sid_map, const char *text,
64 enum_return_status *status, Checkable_rwlock *_sid_lock)
65 : sid_lock(_sid_lock), sid_map(_sid_map)
66 {
67 DBUG_ASSERT(_sid_map != NULL);
68 init();
69 *status= add_gtid_text(text);
70 }
71
72
init()73 void Gtid_set::init()
74 {
75 DBUG_ENTER("Gtid_set::init");
76 cached_string_length= -1;
77 cached_string_format= NULL;
78 chunks= NULL;
79 free_intervals= NULL;
80 my_init_dynamic_array(&intervals, sizeof(Interval *), 0, 8);
81 if (sid_lock)
82 mysql_mutex_init(0, &free_intervals_mutex, NULL);
83 #ifndef DBUG_OFF
84 n_chunks= 0;
85 #endif
86 DBUG_VOID_RETURN;
87 }
88
89
~Gtid_set()90 Gtid_set::~Gtid_set()
91 {
92 DBUG_ENTER("Gtid_set::~Gtid_set");
93 Interval_chunk *chunk= chunks;
94 while (chunk != NULL)
95 {
96 Interval_chunk *next_chunk= chunk->next;
97 free(chunk);
98 chunk= next_chunk;
99 #ifndef DBUG_OFF
100 n_chunks--;
101 #endif
102 }
103 DBUG_ASSERT(n_chunks == 0);
104 delete_dynamic(&intervals);
105 if (sid_lock)
106 mysql_mutex_destroy(&free_intervals_mutex);
107 DBUG_VOID_RETURN;
108 }
109
110
ensure_sidno(rpl_sidno sidno)111 enum_return_status Gtid_set::ensure_sidno(rpl_sidno sidno)
112 {
113 DBUG_ENTER("Gtid_set::ensure_sidno");
114 if (sid_lock != NULL)
115 sid_lock->assert_some_lock();
116 DBUG_PRINT("info", ("sidno=%d get_max_sidno()=%d sid_map=%p "
117 "sid_map->get_max_sidno()=%d",
118 sidno, get_max_sidno(), sid_map,
119 sid_map != NULL ? sid_map->get_max_sidno() : 0));
120 DBUG_ASSERT(sid_map == NULL || sidno <= sid_map->get_max_sidno());
121 DBUG_ASSERT(sid_map == NULL || get_max_sidno() <= sid_map->get_max_sidno());
122 rpl_sidno max_sidno= get_max_sidno();
123 if (sidno > max_sidno)
124 {
125 /*
126 Not all Gtid_sets are protected by an rwlock. But if this
127 Gtid_set is, we assume that the read lock has been taken.
128 Then we temporarily upgrade it to a write lock while resizing
129 the array, and then we restore it to a read lock at the end.
130 */
131 bool is_wrlock= false;
132 if (sid_lock != NULL)
133 {
134 is_wrlock= sid_lock->is_wrlock();
135 if (!is_wrlock)
136 {
137 sid_lock->unlock();
138 sid_lock->wrlock();
139 // maybe a concurrent thread already resized the Gtid_set
140 // while we released the lock; check the condition again
141 if (sidno <= max_sidno)
142 {
143 sid_lock->unlock();
144 sid_lock->rdlock();
145 RETURN_OK;
146 }
147 }
148 }
149 if (allocate_dynamic(&intervals,
150 sid_map == NULL ? sidno : sid_map->get_max_sidno()))
151 goto error;
152 Interval *null_p= NULL;
153 for (rpl_sidno i= max_sidno; i < sidno; i++)
154 if (insert_dynamic(&intervals, &null_p))
155 goto error;
156 if (sid_lock != NULL)
157 {
158 if (!is_wrlock)
159 {
160 sid_lock->unlock();
161 sid_lock->rdlock();
162 }
163 }
164 }
165 RETURN_OK;
166 error:
167 BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
168 RETURN_REPORTED_ERROR;
169 }
170
171
add_interval_memory_lock_taken(int n_ivs,Interval * ivs)172 void Gtid_set::add_interval_memory_lock_taken(int n_ivs, Interval *ivs)
173 {
174 DBUG_ENTER("Gtid_set::add_interval_memory");
175 assert_free_intervals_locked();
176 // make ivs a linked list
177 for (int i= 0; i < n_ivs - 1; i++)
178 ivs[i].next= &(ivs[i + 1]);
179 Interval_iterator ivit(this);
180 ivs[n_ivs - 1].next= ivit.get();
181 // add intervals to list of free intervals
182 ivit.set(&(ivs[0]));
183 DBUG_VOID_RETURN;
184 }
185
186
create_new_chunk(int size)187 enum_return_status Gtid_set::create_new_chunk(int size)
188 {
189 DBUG_ENTER("Gtid_set::create_new_chunk");
190 // allocate the new chunk. one element is already pre-allocated, so
191 // we only add size-1 elements to the size of the struct.
192 assert_free_intervals_locked();
193 Interval_chunk *new_chunk=
194 (Interval_chunk *)my_malloc(sizeof(Interval_chunk) +
195 sizeof(Interval) * (size - 1),
196 MYF(MY_WME));
197 if (new_chunk == NULL)
198 RETURN_REPORTED_ERROR;
199 // store the chunk in the list of chunks
200 new_chunk->next= chunks;
201 chunks= new_chunk;
202 #ifndef DBUG_OFF
203 n_chunks++;
204 #endif
205 // add the intervals in the chunk to the list of free intervals
206 add_interval_memory_lock_taken(size, new_chunk->intervals);
207 RETURN_OK;
208 }
209
210
get_free_interval(Interval ** out)211 enum_return_status Gtid_set::get_free_interval(Interval **out)
212 {
213 DBUG_ENTER("Gtid_set::get_free_interval");
214 assert_free_intervals_locked();
215 Interval_iterator ivit(this);
216 if (ivit.get() == NULL)
217 PROPAGATE_REPORTED_ERROR(create_new_chunk(CHUNK_GROW_SIZE));
218 *out= ivit.get();
219 ivit.set((*out)->next);
220 RETURN_OK;
221 }
222
223
put_free_interval(Interval * iv)224 void Gtid_set::put_free_interval(Interval *iv)
225 {
226 DBUG_ENTER("Gtid_set::put_free_interval");
227 assert_free_intervals_locked();
228 Interval_iterator ivit(this);
229 iv->next= ivit.get();
230 ivit.set(iv);
231 DBUG_VOID_RETURN;
232 }
233
234
clear()235 void Gtid_set::clear()
236 {
237 DBUG_ENTER("Gtid_set::clear");
238 cached_string_length= -1;
239 rpl_sidno max_sidno= get_max_sidno();
240 if (max_sidno == 0)
241 DBUG_VOID_RETURN;
242 Interval_iterator free_ivit(this);
243 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
244 {
245 /*
246 Link in this list of intervals at the end of the list of
247 free intervals.
248 */
249 Interval_iterator ivit(this, sidno);
250 Interval *iv= ivit.get();
251 if (iv != NULL)
252 {
253 // find the end of the list of free intervals
254 while (free_ivit.get() != NULL)
255 free_ivit.next();
256 // append the present list
257 free_ivit.set(iv);
258 // clear the pointer to the head of this list
259 ivit.set(NULL);
260 }
261 }
262 DBUG_VOID_RETURN;
263 }
264
265
266 enum_return_status
add_gno_interval(Interval_iterator * ivitp,rpl_gno start,rpl_gno end,Free_intervals_lock * lock)267 Gtid_set::add_gno_interval(Interval_iterator *ivitp,
268 rpl_gno start, rpl_gno end,
269 Free_intervals_lock *lock)
270 {
271 DBUG_ENTER("Gtid_set::add_gno_interval(Interval_iterator*, rpl_gno, rpl_gno)");
272 DBUG_ASSERT(start > 0);
273 DBUG_ASSERT(start < end);
274 DBUG_PRINT("info", ("start=%lld end=%lld", start, end));
275 Interval *iv;
276 Interval_iterator ivit= *ivitp;
277 cached_string_length= -1;
278
279 while ((iv= ivit.get()) != NULL)
280 {
281 if (iv->end >= start)
282 {
283 if (iv->start > end)
284 // (start, end) is strictly before the current interval
285 break;
286 // (start, end) and (iv->start, iv->end) touch or intersect.
287 // Save the start of the merged interval.
288 if (iv->start < start)
289 start= iv->start;
290 // Remove the current interval as long as the new interval
291 // intersects with the next interval.
292 while (iv->next && end >= iv->next->start)
293 {
294 lock->lock_if_not_locked();
295 ivit.remove(this);
296 iv= ivit.get();
297 }
298 // Store the interval in the current interval.
299 iv->start= start;
300 if (iv->end < end)
301 iv->end= end;
302 *ivitp= ivit;
303 RETURN_OK;
304 }
305 ivit.next();
306 }
307 /*
308 We come here if the interval cannot be combined with any existing
309 interval: it is after the previous interval (if any) and before
310 the current interval (if any). So we allocate a new interval and
311 insert it at the current position.
312 */
313 Interval *new_iv;
314 lock->lock_if_not_locked();
315 PROPAGATE_REPORTED_ERROR(get_free_interval(&new_iv));
316 new_iv->start= start;
317 new_iv->end= end;
318 ivit.insert(new_iv);
319 *ivitp= ivit;
320 RETURN_OK;
321 }
322
323
remove_gno_interval(Interval_iterator * ivitp,rpl_gno start,rpl_gno end,Free_intervals_lock * lock)324 enum_return_status Gtid_set::remove_gno_interval(Interval_iterator *ivitp,
325 rpl_gno start, rpl_gno end,
326 Free_intervals_lock *lock)
327 {
328 DBUG_ENTER("Gtid_set::remove_gno_interval(Interval_iterator *ivitp, rpl_gno start, rpl_gno end)");
329 DBUG_ASSERT(start < end);
330 Interval_iterator ivit= *ivitp;
331 Interval *iv;
332 cached_string_length= -1;
333
334 // Skip intervals of 'this' that are completely before the removed interval.
335 while (1)
336 {
337 iv= ivit.get();
338 if (iv == NULL)
339 goto ok;
340 if (iv->end > start)
341 break;
342 ivit.next();
343 }
344
345 // Now iv ends after the beginning of the removed interval.
346 DBUG_ASSERT(iv != NULL && iv->end > start);
347 if (iv->start < start)
348 {
349 if (iv->end > end)
350 {
351 // iv cuts also the end of the removed interval: split iv in two
352 Interval *new_iv;
353 lock->lock_if_not_locked();
354 PROPAGATE_REPORTED_ERROR(get_free_interval(&new_iv));
355 new_iv->start= end;
356 new_iv->end= iv->end;
357 iv->end= start;
358 ivit.next();
359 ivit.insert(new_iv);
360 goto ok;
361 }
362 // iv cuts the beginning but not the end of the removed interval:
363 // truncate iv, and iterate one step to next interval
364 iv->end= start;
365 ivit.next();
366 iv= ivit.get();
367 if (iv == NULL)
368 goto ok;
369 }
370
371 // Now iv starts after the beginning of the removed interval.
372 DBUG_ASSERT(iv != NULL && iv->start >= start);
373 while (iv->end <= end)
374 {
375 // iv ends before the end of the removed interval, so it is
376 // completely covered: remove iv.
377 lock->lock_if_not_locked();
378 ivit.remove(this);
379 iv= ivit.get();
380 if (iv == NULL)
381 goto ok;
382 }
383
384 // Now iv ends after the removed interval.
385 DBUG_ASSERT(iv != NULL && iv->end > end);
386 if (iv->start < end)
387 {
388 // iv begins before the end of the removed interval: truncate iv
389 iv->start= end;
390 }
391
392 ok:
393 *ivitp= ivit;
394 RETURN_OK;
395 }
396
397
parse_gno(const char ** s)398 rpl_gno parse_gno(const char **s)
399 {
400 char *endp;
401 rpl_gno ret= strtoll(*s, &endp, 0);
402 if (ret < 0 || ret == LLONG_MAX)
403 return -1;
404 *s= endp;
405 return ret;
406 }
407
408
format_gno(char * s,rpl_gno gno)409 int format_gno(char *s, rpl_gno gno)
410 {
411 return (int)(ll2str(gno, s, 10, 1) - s);
412 }
413
414
add_gtid_text(const char * text,bool * anonymous)415 enum_return_status Gtid_set::add_gtid_text(const char *text, bool *anonymous)
416 {
417 DBUG_ENTER("Gtid_set::add_gtid_text(const char *, bool *)");
418 DBUG_ASSERT(sid_map != NULL);
419 if (sid_lock != NULL)
420 sid_lock->assert_some_wrlock();
421 const char *s= text;
422
423 DBUG_PRINT("info", ("adding '%s'", text));
424
425 if (anonymous != NULL)
426 *anonymous= false;
427
428 SKIP_WHITESPACE();
429 if (*s == 0)
430 {
431 DBUG_PRINT("info", ("'%s' is empty", text));
432 RETURN_OK;
433 }
434
435 Free_intervals_lock lock(this);
436
437 DBUG_PRINT("info", ("'%s' not only whitespace", text));
438 // Allocate space for all intervals at once, if nothing is allocated.
439 if (chunks == NULL)
440 {
441 // compute number of intervals in text: it is equal to the number of
442 // colons
443 int n_intervals= 0;
444 text= s;
445 for (; *s; s++)
446 if (*s == ':')
447 n_intervals++;
448 // allocate all intervals in one chunk
449 lock.lock_if_not_locked();
450 create_new_chunk(n_intervals);
451 lock.unlock_if_locked();
452 s= text;
453 }
454
455 while (1)
456 {
457 // Skip commas (we allow empty SID:GNO specifications).
458 while (*s == ',')
459 {
460 s++;
461 SKIP_WHITESPACE();
462 }
463
464 // We allow empty Gtid_sets containing only commas.
465 if (*s == 0)
466 {
467 DBUG_PRINT("info", ("successfully parsed"));
468 RETURN_OK;
469 }
470
471 // Parse SID.
472 if (anonymous != NULL && strncmp(s, "ANONYMOUS", 9) == 0)
473 {
474 *anonymous= true;
475 s+= 9;
476 }
477 else
478 {
479 rpl_sid sid;
480 if (sid.parse(s) != 0)
481 {
482 DBUG_PRINT("info", ("expected UUID; found garbage '%.80s' at char %d in '%s'", s, (int)(s - text), text));
483 goto parse_error;
484 }
485 s += rpl_sid::TEXT_LENGTH;
486 rpl_sidno sidno= sid_map->add_sid(sid);
487 if (sidno <= 0)
488 {
489 RETURN_REPORTED_ERROR;
490 }
491 PROPAGATE_REPORTED_ERROR(ensure_sidno(sidno));
492 SKIP_WHITESPACE();
493
494 // Iterate over intervals.
495 Interval_iterator ivit(this, sidno);
496 while (*s == ':')
497 {
498 // Skip ':'.
499 s++;
500
501 // Read start of interval.
502 rpl_gno start= parse_gno(&s);
503 if (start <= 0)
504 {
505 if (start == 0)
506 DBUG_PRINT("info", ("expected positive NUMBER; found zero ('%.80s') at char %d in '%s'", s - 1, (int)(s - text) - 1, text));
507 else
508 DBUG_PRINT("info", ("expected positive NUMBER; found zero or garbage '%.80s' at char %d in '%s'", s, (int)(s - text), text));
509
510 goto parse_error;
511 }
512 SKIP_WHITESPACE();
513
514 // Read end of interval.
515 rpl_gno end;
516 if (*s == '-')
517 {
518 s++;
519 end= parse_gno(&s);
520 if (end < 0)
521 {
522 DBUG_PRINT("info", ("expected NUMBER; found garbage '%.80s' at char %d in '%s'", s, (int)(s - text), text));
523 goto parse_error;
524 }
525 end++;
526 SKIP_WHITESPACE();
527 }
528 else
529 end= start + 1;
530
531 if (end > start)
532 {
533 // Add interval. Use the existing iterator position if the
534 // current interval does not begin before it. Otherwise iterate
535 // from the beginning.
536 Interval *current= ivit.get();
537 if (current == NULL || start < current->start)
538 ivit.init(this, sidno);
539 if (add_gno_interval(&ivit, start, end, &lock) != RETURN_STATUS_OK)
540 {
541 RETURN_REPORTED_ERROR;
542 }
543 }
544 }
545 }
546
547 // Must be end of string or comma. (Commas are consumed and
548 // end-of-loop is detected at the beginning of the loop.)
549 if (*s != ',' && *s != 0)
550 {
551 DBUG_PRINT("info", ("expected end of string, UUID, or :NUMBER; found garbage '%.80s' at char %d in '%s'", s, (int)(s - text), text));
552 goto parse_error;
553 }
554 }
555 DBUG_ASSERT(0);
556
557 parse_error:
558 BINLOG_ERROR(("Malformed Gtid_set specification '%.200s'.", text),
559 (ER_MALFORMED_GTID_SET_SPECIFICATION, MYF(0), text));
560 RETURN_REPORTED_ERROR;
561 }
562
is_valid(const char * text)563 bool Gtid_set::is_valid(const char *text)
564 {
565 DBUG_ENTER("Gtid_set::is_valid(const char*)");
566
567 const char *s= text;
568
569 SKIP_WHITESPACE();
570 do
571 {
572 // Skip commas (we allow empty SID:GNO specifications).
573 while (*s == ',')
574 {
575 s++;
576 SKIP_WHITESPACE();
577 }
578 if (*s == 0)
579 DBUG_RETURN(true);
580
581 // Parse SID.
582 if (!rpl_sid::is_valid(s))
583 DBUG_RETURN(false);
584 s += rpl_sid::TEXT_LENGTH;
585 SKIP_WHITESPACE();
586
587 // Iterate over intervals.
588 while (*s == ':')
589 {
590 // Skip ':'.
591 s++;
592
593 // Read start of interval.
594 if (parse_gno(&s) <= 0)
595 DBUG_RETURN(false);
596 SKIP_WHITESPACE();
597
598 // Read end of interval
599 if (*s == '-')
600 {
601 s++;
602 if (parse_gno(&s) < 0)
603 DBUG_RETURN(false);
604 SKIP_WHITESPACE();
605 }
606 }
607 } while (*s == ',');
608 if (*s != 0)
609 DBUG_RETURN(false);
610
611 DBUG_RETURN(true);
612 }
613
614
615 enum_return_status
add_gno_intervals(rpl_sidno sidno,Const_interval_iterator other_ivit,Free_intervals_lock * lock)616 Gtid_set::add_gno_intervals(rpl_sidno sidno,
617 Const_interval_iterator other_ivit,
618 Free_intervals_lock *lock)
619 {
620 DBUG_ENTER("Gtid_set::add_gno_intervals(rpl_sidno, Const_interval_iterator, bool *)");
621 DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno());
622 const Interval *other_iv;
623 Interval_iterator ivit(this, sidno);
624 while ((other_iv= other_ivit.get()) != NULL)
625 {
626 PROPAGATE_REPORTED_ERROR(add_gno_interval(&ivit,
627 other_iv->start, other_iv->end,
628 lock));
629 other_ivit.next();
630 }
631 RETURN_OK;
632 }
633
634
635 enum_return_status
remove_gno_intervals(rpl_sidno sidno,Const_interval_iterator other_ivit,Free_intervals_lock * lock)636 Gtid_set::remove_gno_intervals(rpl_sidno sidno,
637 Const_interval_iterator other_ivit,
638 Free_intervals_lock *lock)
639 {
640 DBUG_ENTER("Gtid_set::remove_gno_intervals(rpl_sidno, Interval_iterator, bool *)");
641 DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno());
642 const Interval *other_iv;
643 Interval_iterator ivit(this, sidno);
644 while ((other_iv= other_ivit.get()) != NULL)
645 {
646 PROPAGATE_REPORTED_ERROR(remove_gno_interval(&ivit,
647 other_iv->start, other_iv->end,
648 lock));
649 other_ivit.next();
650 }
651 RETURN_OK;
652 }
653
654
add_gtid_set(const Gtid_set * other)655 enum_return_status Gtid_set::add_gtid_set(const Gtid_set *other)
656 {
657 DBUG_ENTER("Gtid_set::add_gtid_set(const Gtid_set *)");
658 if (sid_lock != NULL)
659 sid_lock->assert_some_wrlock();
660 rpl_sidno max_other_sidno= other->get_max_sidno();
661 Free_intervals_lock lock(this);
662 if (other->sid_map == sid_map || other->sid_map == NULL || sid_map == NULL)
663 {
664 PROPAGATE_REPORTED_ERROR(ensure_sidno(max_other_sidno));
665 for (rpl_sidno sidno= 1; sidno <= max_other_sidno; sidno++)
666 PROPAGATE_REPORTED_ERROR(
667 add_gno_intervals(sidno, Const_interval_iterator(other, sidno),
668 &lock));
669 }
670 else
671 {
672 /*
673 This code is not being used but we will keep it as it may be
674 useful to optimize gtids by avoiding sharing mappings from
675 sid to sidno. For instance, the IO Thread and the SQL Thread
676 may have different mappings in the future.
677 */
678 Sid_map *other_sid_map= other->sid_map;
679 for (rpl_sidno other_sidno= 1; other_sidno <= max_other_sidno;
680 other_sidno++)
681 {
682 Const_interval_iterator other_ivit(other, other_sidno);
683 if (other_ivit.get() != NULL)
684 {
685 const rpl_sid &sid= other_sid_map->sidno_to_sid(other_sidno);
686 rpl_sidno this_sidno= sid_map->add_sid(sid);
687 if (this_sidno <= 0)
688 RETURN_REPORTED_ERROR;
689 PROPAGATE_REPORTED_ERROR(ensure_sidno(this_sidno));
690 PROPAGATE_REPORTED_ERROR(add_gno_intervals(this_sidno, other_ivit,
691 &lock));
692 }
693 }
694 }
695 RETURN_OK;
696 }
697
698
remove_gtid_set(const Gtid_set * other)699 enum_return_status Gtid_set::remove_gtid_set(const Gtid_set *other)
700 {
701 DBUG_ENTER("Gtid_set::remove_gtid_set(Gtid_set *)");
702 if (sid_lock != NULL)
703 sid_lock->assert_some_wrlock();
704 rpl_sidno max_other_sidno= other->get_max_sidno();
705 Free_intervals_lock lock(this);
706 if (other->sid_map == sid_map || other->sid_map == NULL || sid_map == NULL)
707 {
708 rpl_sidno max_sidno= min(max_other_sidno, get_max_sidno());
709 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
710 PROPAGATE_REPORTED_ERROR(
711 remove_gno_intervals(sidno, Const_interval_iterator(other, sidno),
712 &lock));
713 }
714 else
715 {
716 Sid_map *other_sid_map= other->sid_map;
717 for (rpl_sidno other_sidno= 1; other_sidno <= max_other_sidno;
718 other_sidno++)
719 {
720 Const_interval_iterator other_ivit(other, other_sidno);
721 if (other_ivit.get() != NULL)
722 {
723 const rpl_sid &sid= other_sid_map->sidno_to_sid(other_sidno);
724 rpl_sidno this_sidno= sid_map->sid_to_sidno(sid);
725 if (this_sidno != 0)
726 PROPAGATE_REPORTED_ERROR(
727 remove_gno_intervals(this_sidno, other_ivit, &lock));
728 }
729 }
730 }
731 RETURN_OK;
732 }
733
734
contains_gtid(rpl_sidno sidno,rpl_gno gno) const735 bool Gtid_set::contains_gtid(rpl_sidno sidno, rpl_gno gno) const
736 {
737 DBUG_ENTER("Gtid_set::contains_gtid");
738 DBUG_ASSERT(sidno >= 1 && gno >= 1);
739 if (sid_lock != NULL)
740 sid_lock->assert_some_lock();
741 if (sidno > get_max_sidno())
742 DBUG_RETURN(false);
743 Const_interval_iterator ivit(this, sidno);
744 const Interval *iv;
745 while ((iv= ivit.get()) != NULL)
746 {
747 if (gno < iv->start)
748 DBUG_RETURN(false);
749 else if (gno < iv->end)
750 DBUG_RETURN(true);
751 ivit.next();
752 }
753 DBUG_RETURN(false);
754 }
755
to_string(char ** buf_arg,const Gtid_set::String_format * sf_arg) const756 int Gtid_set::to_string(char **buf_arg, const Gtid_set::String_format *sf_arg) const
757 {
758 DBUG_ENTER("Gtid_set::to_string");
759 int len= get_string_length(sf_arg);
760 *buf_arg= (char *)my_malloc(len + 1, MYF(MY_WME));
761 if (*buf_arg == NULL)
762 DBUG_RETURN(-1);
763 to_string(*buf_arg, sf_arg);
764 DBUG_RETURN(len);
765 }
766
to_string(char * buf,const Gtid_set::String_format * sf) const767 int Gtid_set::to_string(char *buf, const Gtid_set::String_format *sf) const
768 {
769 DBUG_ENTER("Gtid_set::to_string");
770 DBUG_ASSERT(sid_map != NULL);
771 if (sid_lock != NULL)
772 sid_lock->assert_some_wrlock();
773 if (sf == NULL)
774 sf= &default_string_format;
775 if (sf->empty_set_string != NULL && is_empty())
776 {
777 memcpy(buf, sf->empty_set_string, sf->empty_set_string_length);
778 buf[sf->empty_set_string_length]= '\0';
779 DBUG_RETURN(sf->empty_set_string_length);
780 }
781 rpl_sidno map_max_sidno= sid_map->get_max_sidno();
782 DBUG_ASSERT(get_max_sidno() <= map_max_sidno);
783 memcpy(buf, sf->begin, sf->begin_length);
784 char *s= buf + sf->begin_length;
785 bool first_sidno= true;
786 for (int sid_i= 0; sid_i < map_max_sidno; sid_i++)
787 {
788 rpl_sidno sidno= sid_map->get_sorted_sidno(sid_i);
789 if (contains_sidno(sidno))
790 {
791 Const_interval_iterator ivit(this, sidno);
792 const Interval *iv= ivit.get();
793 if (first_sidno)
794 first_sidno= false;
795 else
796 {
797 memcpy(s, sf->gno_sid_separator, sf->gno_sid_separator_length);
798 s+= sf->gno_sid_separator_length;
799 }
800 s+= sid_map->sidno_to_sid(sidno).to_string(s);
801 bool first_gno= true;
802 do
803 {
804 if (first_gno)
805 {
806 memcpy(s, sf->sid_gno_separator, sf->sid_gno_separator_length);
807 s+= sf->sid_gno_separator_length;
808 }
809 else
810 {
811 memcpy(s, sf->gno_gno_separator, sf->gno_gno_separator_length);
812 s+= sf->gno_gno_separator_length;
813 }
814 s+= format_gno(s, iv->start);
815 if (iv->end > iv->start + 1)
816 {
817 memcpy(s, sf->gno_start_end_separator,
818 sf->gno_start_end_separator_length);
819 s+= sf->gno_start_end_separator_length;
820 s+= format_gno(s, iv->end - 1);
821 }
822 ivit.next();
823 iv= ivit.get();
824 } while (iv != NULL);
825 }
826 }
827 memcpy(s, sf->end, sf->end_length);
828 s += sf->end_length;
829 *s= '\0';
830 DBUG_PRINT("info", ("ret='%s' strlen(s)=%lu s-buf=%lu get_string_length=%d", buf,
831 (ulong) strlen(buf), (ulong) (s - buf), get_string_length(sf)));
832 DBUG_ASSERT(s - buf == get_string_length(sf));
833 DBUG_RETURN((int)(s - buf));
834 }
835
836
837 /**
838 Returns the length that the given rpl_sidno (64 bit integer) would
839 have, if it was encoded as a string.
840 */
get_string_length(rpl_gno gno)841 static int get_string_length(rpl_gno gno)
842 {
843 DBUG_ASSERT(gno >= 1 && gno < MAX_GNO);
844 rpl_gno tmp_gno= gno;
845 int len= 0;
846 do
847 {
848 tmp_gno /= 10;
849 len++;
850 } while (tmp_gno != 0);
851 #ifndef DBUG_OFF
852 char buf[22];
853 DBUG_ASSERT(snprintf(buf, 22, "%lld", gno) == len);
854 #endif
855 return len;
856 }
857
858
get_string_length(const Gtid_set::String_format * sf) const859 int Gtid_set::get_string_length(const Gtid_set::String_format *sf) const
860 {
861 DBUG_ASSERT(sid_map != NULL);
862 if (sid_lock != NULL)
863 sid_lock->assert_some_wrlock();
864 if (sf == NULL)
865 sf= &default_string_format;
866 if (cached_string_length == -1 || cached_string_format != sf)
867 {
868 int n_sids= 0, n_intervals= 0, n_long_intervals= 0;
869 int total_interval_length= 0;
870 rpl_sidno max_sidno= get_max_sidno();
871 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
872 {
873 Const_interval_iterator ivit(this, sidno);
874 const Interval *iv= ivit.get();
875 if (iv != NULL)
876 {
877 n_sids++;
878 do
879 {
880 n_intervals++;
881 total_interval_length += ::get_string_length(iv->start);
882 if (iv->end - 1 > iv->start)
883 {
884 n_long_intervals++;
885 total_interval_length += ::get_string_length(iv->end - 1);
886 }
887 ivit.next();
888 iv= ivit.get();
889 } while (iv != NULL);
890 }
891 }
892 if (n_sids == 0 && sf->empty_set_string != NULL)
893 cached_string_length= sf->empty_set_string_length;
894 else
895 {
896 cached_string_length= sf->begin_length + sf->end_length;
897 if (n_sids > 0)
898 cached_string_length+=
899 total_interval_length +
900 n_sids * (rpl_sid::TEXT_LENGTH + sf->sid_gno_separator_length) +
901 (n_sids - 1) * sf->gno_sid_separator_length +
902 (n_intervals - n_sids) * sf->gno_gno_separator_length +
903 n_long_intervals * sf->gno_start_end_separator_length;
904 }
905 cached_string_format= sf;
906 }
907 return cached_string_length;
908 }
909
910 /*
911 Functions sidno_equals() and equals() are only used by unitests
912 */
913 #ifdef NON_DISABLED_UNITTEST_GTID
sidno_equals(rpl_sidno sidno,const Gtid_set * other,rpl_sidno other_sidno) const914 bool Gtid_set::sidno_equals(rpl_sidno sidno, const Gtid_set *other,
915 rpl_sidno other_sidno) const
916 {
917 DBUG_ENTER("Gtid_set::sidno_equals");
918 Const_interval_iterator ivit(this, sidno);
919 Const_interval_iterator other_ivit(other, other_sidno);
920 const Interval *iv= ivit.get();
921 const Interval *other_iv= other_ivit.get();
922 while (iv != NULL && other_iv != NULL)
923 {
924 if (!iv->equals(*other_iv))
925 DBUG_RETURN(false);
926 ivit.next();
927 other_ivit.next();
928 iv= ivit.get();
929 other_iv= other_ivit.get();
930 }
931 if (iv != NULL || other_iv != NULL)
932 DBUG_RETURN(false);
933 DBUG_RETURN(true);
934 }
935
936
equals(const Gtid_set * other) const937 bool Gtid_set::equals(const Gtid_set *other) const
938 {
939 DBUG_ENTER("Gtid_set::equals");
940
941 if (sid_lock != NULL)
942 sid_lock->assert_some_wrlock();
943 if (other->sid_lock != NULL)
944 other->sid_lock->assert_some_wrlock();
945 if (sid_map == NULL || other->sid_map == NULL || sid_map == other->sid_map)
946 {
947 // in this case, we don't need to translate sidnos
948 rpl_sidno max_sidno= get_max_sidno();
949 rpl_sidno other_max_sidno= other->get_max_sidno();
950 rpl_sidno common_max_sidno= min(max_sidno, other_max_sidno);
951 if (max_sidno > common_max_sidno)
952 {
953 for (rpl_sidno sidno= common_max_sidno + 1; sidno < max_sidno; sidno++)
954 if (contains_sidno(sidno))
955 DBUG_RETURN(false);
956 }
957 else if (other_max_sidno > common_max_sidno)
958 {
959 for (rpl_sidno sidno= common_max_sidno + 1;
960 sidno < other_max_sidno; sidno++)
961 if (other->contains_sidno(sidno))
962 DBUG_RETURN(false);
963 }
964 for (rpl_sidno sidno= 1; sidno <= common_max_sidno; sidno++)
965 if (!sidno_equals(sidno, other, sidno))
966 DBUG_RETURN(false);
967 DBUG_RETURN(true);
968 }
969
970 Sid_map *other_sid_map= other->sid_map;
971 rpl_sidno map_max_sidno= sid_map->get_max_sidno();
972 rpl_sidno other_map_max_sidno= other_sid_map->get_max_sidno();
973
974 int sid_i= 0, other_sid_i= 0;
975 while (1)
976 {
977 rpl_sidno sidno= 0, other_sidno= 0; // set to 0 to avoid compilation warning
978 // find next sidno (in order of increasing sid) for this set
979 while (sid_i < map_max_sidno &&
980 !contains_sidno(sidno= sid_map->get_sorted_sidno(sid_i)))
981 sid_i++;
982 // find next sidno (in order of increasing sid) for other set
983 while (other_sid_i < other_map_max_sidno &&
984 !other->contains_sidno(other_sidno=
985 other_sid_map->get_sorted_sidno(other_sid_i)))
986 other_sid_i++;
987 // at least one of this and other reached the max sidno
988 if (sid_i == map_max_sidno || other_sid_i == other_map_max_sidno)
989 // return true iff both sets reached the max sidno
990 DBUG_RETURN(sid_i == map_max_sidno && other_sid_i == other_map_max_sidno);
991 // check if sids are equal
992 const rpl_sid &sid= sid_map->sidno_to_sid(sidno);
993 const rpl_sid &other_sid= other_sid_map->sidno_to_sid(other_sidno);
994 if (!sid.equals(other_sid))
995 DBUG_RETURN(false);
996 // check if all intervals are equal
997 if (!sidno_equals(sidno, other, other_sidno))
998 DBUG_RETURN(false);
999 sid_i++;
1000 other_sid_i++;
1001 }
1002 DBUG_ASSERT(0); // not reached
1003 DBUG_RETURN(true);
1004 }
1005 #endif
1006
1007
is_interval_subset(Const_interval_iterator * sub,Const_interval_iterator * super)1008 bool Gtid_set::is_interval_subset(Const_interval_iterator *sub,
1009 Const_interval_iterator *super)
1010 {
1011 DBUG_ENTER("is_interval_subset");
1012 // check if all intervals for this sidno are contained in some
1013 // interval of super
1014 const Interval *super_iv= super->get();
1015 const Interval *sub_iv= sub->get();
1016
1017 /*
1018 Algorithm: Let sub_iv iterate over intervals of sub. For each
1019 sub_iv, skip over intervals of super that end before sub_iv. When we
1020 find the first super-interval that does not end before sub_iv,
1021 check if it covers sub_iv.
1022 */
1023 do
1024 {
1025 if (super_iv == NULL)
1026 DBUG_RETURN(false);
1027
1028 // Skip over 'smaller' intervals of super.
1029 while (sub_iv->start > super_iv->end)
1030 {
1031 super->next();
1032 super_iv= super->get();
1033 // If we reach end of super, then no interal covers sub_iv, so
1034 // sub is not a subset of super.
1035 if (super_iv == NULL)
1036 DBUG_RETURN(false);
1037 }
1038
1039 // If super_iv does not cover sub_iv, then sub is not a subset of
1040 // super.
1041 if (sub_iv->start < super_iv->start || sub_iv->end > super_iv->end)
1042 DBUG_RETURN(false);
1043
1044 // Next iteration.
1045 sub->next();
1046 sub_iv= sub->get();
1047
1048 } while (sub_iv != NULL);
1049
1050 // If every GNO in sub also exists in super, then it was a subset.
1051 DBUG_RETURN(true);
1052 }
1053
is_subset_for_sid(const Gtid_set * super,rpl_sidno superset_sidno,rpl_sidno subset_sidno) const1054 bool Gtid_set::is_subset_for_sid(const Gtid_set *super,
1055 rpl_sidno superset_sidno,
1056 rpl_sidno subset_sidno) const
1057 {
1058 DBUG_ENTER("Gtid_set::is_subset_for_sidno");
1059 /*
1060 The following assert code is to see that caller acquired
1061 either write or read lock on global_sid_lock.
1062 Note that if it is read lock, then it should also
1063 acquire lock on sidno.
1064 i.e., the caller must acquire lock either A1 way or A2 way.
1065 A1. global_sid_lock.wrlock()
1066 A2. global_sid_lock.rdlock(); gtid_state.lock_sidno(sidno)
1067 */
1068 if (sid_lock != NULL)
1069 super->sid_lock->assert_some_lock();
1070 if (super->sid_lock != NULL)
1071 super->sid_lock->assert_some_lock();
1072 /*
1073 If subset(i.e, this object) does not have required sid in it, i.e.,
1074 subset_sidno is zero, then it means it is subset of any given
1075 super set. Hence return true.
1076 */
1077 if (subset_sidno == 0)
1078 DBUG_RETURN(true);
1079 /*
1080 If superset (i.e., the passed gtid_set) does not have given sid in it,
1081 i.e., superset_sidno is zero, then it means it cannot be superset
1082 to any given subset. Hence return false.
1083 */
1084 if (superset_sidno == 0)
1085 DBUG_RETURN(false);
1086 /*
1087 Once we have valid(non-zero) subset's and superset's sid numbers, call
1088 is_interval_subset().
1089 */
1090 Const_interval_iterator subset_ivit(this, subset_sidno);
1091 Const_interval_iterator superset_ivit(super, superset_sidno);
1092 if (!is_interval_subset(&subset_ivit, &superset_ivit))
1093 DBUG_RETURN(false);
1094
1095 DBUG_RETURN(true);
1096 }
1097
is_subset(const Gtid_set * super) const1098 bool Gtid_set::is_subset(const Gtid_set *super) const
1099 {
1100 DBUG_ENTER("Gtid_set::is_subset");
1101 if (sid_lock != NULL)
1102 sid_lock->assert_some_wrlock();
1103 if (super->sid_lock != NULL)
1104 super->sid_lock->assert_some_wrlock();
1105
1106 Sid_map *super_sid_map= super->sid_map;
1107 rpl_sidno max_sidno= get_max_sidno();
1108 rpl_sidno super_max_sidno= super->get_max_sidno();
1109
1110 /*
1111 Iterate over sidnos of this Gtid_set where there is at least one
1112 interval. For each such sidno, get the corresponding sidno of
1113 super, and then use is_interval_subset to look for GTIDs that
1114 exist in this but not in super.
1115 */
1116 for (int sidno= 1; sidno <= max_sidno; sidno++)
1117 {
1118 Const_interval_iterator ivit(this, sidno);
1119 const Interval *iv= ivit.get();
1120 if (iv != NULL)
1121 {
1122
1123 // Get the corresponding super_sidno
1124 int super_sidno;
1125 if (super_sid_map == sid_map || super_sid_map == NULL || sid_map == NULL)
1126 super_sidno= sidno;
1127 else
1128 {
1129 super_sidno= super_sid_map->sid_to_sidno(sid_map->sidno_to_sid(sidno));
1130 if (super_sidno == 0)
1131 DBUG_RETURN(false);
1132 }
1133 if (super_sidno > super_max_sidno)
1134 DBUG_RETURN(false);
1135
1136 // Check if all GNOs in this Gtid_set for sidno exist in other
1137 // Gtid_set for super_
1138 Const_interval_iterator super_ivit(super, super_sidno);
1139 if (!is_interval_subset(&ivit, &super_ivit))
1140 DBUG_RETURN(false);
1141 }
1142 }
1143
1144 // If the GNOs for every SIDNO of sub existed in super, then it was
1145 // a subset.
1146 DBUG_RETURN(true);
1147 }
1148
1149
is_interval_intersection_nonempty(Const_interval_iterator * ivit1,Const_interval_iterator * ivit2)1150 bool Gtid_set::is_interval_intersection_nonempty(Const_interval_iterator *ivit1,
1151 Const_interval_iterator *ivit2)
1152 {
1153 DBUG_ENTER("is_interval_intersection_nonempty");
1154 const Interval *iv1= ivit1->get();
1155 const Interval *iv2= ivit2->get();
1156 DBUG_ASSERT(iv1 != NULL);
1157 if (iv2 == NULL)
1158 DBUG_RETURN(false);
1159
1160 /*
1161 Algorithm: Let iv1 iterate over all intervals of ivit1. For each
1162 iv1, skip over intervals of iv2 that end before iv1. When we
1163 reach the first interval that does not end before iv1, check if it
1164 intersects with iv1.
1165 */
1166 do
1167 {
1168
1169 // Skip over intervals of iv2 that end before iv1.
1170 while (iv2->end <= iv1->start)
1171 {
1172 ivit2->next();
1173 iv2= ivit2->get();
1174 // If we reached the end of ivit2, then there is no intersection.
1175 if (iv2 == NULL)
1176 DBUG_RETURN(false);
1177 }
1178
1179 // If iv1 and iv2 intersect, return true.
1180 if (iv2->start < iv1->end)
1181 DBUG_RETURN(true);
1182
1183 // Next iteration.
1184 ivit1->next();
1185 iv1= ivit1->get();
1186
1187 } while (iv1 != NULL);
1188
1189 // If we iterated over all intervals of ivit1 without finding any
1190 // intersection with ivit2, then there is no intersection.
1191 DBUG_RETURN(false);
1192 }
1193
1194
is_intersection_nonempty(const Gtid_set * other) const1195 bool Gtid_set::is_intersection_nonempty(const Gtid_set *other) const
1196 {
1197 DBUG_ENTER("Gtid_set::is_intersection_nonempty(Gtid_set *)");
1198 /*
1199 This could in principle be implemented as follows:
1200
1201 Gtid_set this_minus_other(sid_map);
1202 this_minus_other.add_gtid_set(this);
1203 this_minus_other.remove_gtid_set(other);
1204 bool ret= equals(&this_minus_other);
1205 DBUG_RETURN(ret);
1206
1207 However, that does not check the return values from add_gtid_set
1208 or remove_gtid_set, and there is no way for this function to
1209 return an error.
1210 */
1211 if (sid_lock != NULL)
1212 sid_lock->assert_some_wrlock();
1213 if (other->sid_lock != NULL)
1214 other->sid_lock->assert_some_wrlock();
1215
1216 Sid_map *other_sid_map= other->sid_map;
1217 rpl_sidno max_sidno= get_max_sidno();
1218 rpl_sidno other_max_sidno= other->get_max_sidno();
1219
1220 /*
1221 Algorithm: iterate over all sidnos of this Gtid_set where there is
1222 at least one interval. For each such sidno, find the
1223 corresponding sidno of the other set. Then use
1224 is_interval_intersection_nonempty to check if there are any GTIDs
1225 that are common to the two sets for this sidno.
1226 */
1227 for (int sidno= 1; sidno <= max_sidno; sidno++)
1228 {
1229 Const_interval_iterator ivit(this, sidno);
1230 const Interval *iv= ivit.get();
1231 if (iv != NULL)
1232 {
1233
1234 // Get the corresponding other_sidno.
1235 int other_sidno= 0;
1236 if (other_sid_map == sid_map || other_sid_map == NULL || sid_map == NULL)
1237 other_sidno= sidno;
1238 else
1239 {
1240 other_sidno= other_sid_map->sid_to_sidno(sid_map->sidno_to_sid(sidno));
1241 if (other_sidno == 0)
1242 continue;
1243 }
1244 if (other_sidno > other_max_sidno)
1245 continue;
1246
1247 // Check if there is any GNO in this for sidno that also exists
1248 // in other for other_sidno.
1249 Const_interval_iterator other_ivit(other, other_sidno);
1250 if (is_interval_intersection_nonempty(&ivit, &other_ivit))
1251 DBUG_RETURN(true);
1252 }
1253 }
1254 DBUG_RETURN(false);
1255 }
1256
1257
1258 enum_return_status
intersection(const Gtid_set * other,Gtid_set * result)1259 Gtid_set::intersection(const Gtid_set *other, Gtid_set *result)
1260 {
1261 DBUG_ENTER("Gtid_set::intersection(Gtid_set *, Gtid_set *)");
1262 if (sid_lock != NULL)
1263 sid_lock->assert_some_wrlock();
1264 DBUG_ASSERT(result != NULL);
1265 DBUG_ASSERT(other != NULL);
1266 DBUG_ASSERT(result != this);
1267 DBUG_ASSERT(result != other);
1268 DBUG_ASSERT(other != this);
1269 /**
1270 @todo: This algorithm is simple, a little bit slower than
1271 necessary. It would be more efficient to iterate over intervals
1272 of 'this' and 'other' similar to add_gno_interval(). At the moment
1273 the performance of this is not super-important. /Sven
1274 */
1275 Gtid_set this_minus_other(sid_map);
1276 Gtid_set intersection(sid_map);
1277 // In set theory, intersection(A, B) == A - (A - B)
1278 PROPAGATE_REPORTED_ERROR(this_minus_other.add_gtid_set(this));
1279 PROPAGATE_REPORTED_ERROR(this_minus_other.remove_gtid_set(other));
1280 PROPAGATE_REPORTED_ERROR(intersection.add_gtid_set(this));
1281 PROPAGATE_REPORTED_ERROR(intersection.remove_gtid_set(&this_minus_other));
1282 PROPAGATE_REPORTED_ERROR(result->add_gtid_set(&intersection));
1283 RETURN_OK;
1284 }
1285
1286
encode(uchar * buf) const1287 void Gtid_set::encode(uchar *buf) const
1288 {
1289 DBUG_ENTER("Gtid_set::encode(uchar *)");
1290 if (sid_lock != NULL)
1291 sid_lock->assert_some_wrlock();
1292 // make place for number of sids
1293 uint64 n_sids= 0;
1294 uchar *n_sids_p= buf;
1295 buf+= 8;
1296 // iterate over sidnos
1297 rpl_sidno sidmap_max_sidno= sid_map->get_max_sidno();
1298 rpl_sidno max_sidno= get_max_sidno();
1299 for (rpl_sidno sid_i= 0; sid_i < sidmap_max_sidno; sid_i++)
1300 {
1301 rpl_sidno sidno= sid_map->get_sorted_sidno(sid_i);
1302 // it is possible that the sid_map has more SIDNOs than the set.
1303 if (sidno > max_sidno)
1304 continue;
1305 DBUG_PRINT("info", ("sid_i=%d sidno=%d max_sidno=%d sid_map->max_sidno=%d",
1306 sid_i, sidno, max_sidno, sid_map->get_max_sidno()));
1307 Const_interval_iterator ivit(this, sidno);
1308 const Interval *iv= ivit.get();
1309 if (iv != NULL)
1310 {
1311 n_sids++;
1312 // store SID
1313 sid_map->sidno_to_sid(sidno).copy_to(buf);
1314 buf+= rpl_sid::BYTE_LENGTH;
1315 // make place for number of intervals
1316 uint64 n_intervals= 0;
1317 uchar *n_intervals_p= buf;
1318 buf+= 8;
1319 // iterate over intervals
1320 do
1321 {
1322 n_intervals++;
1323 // store one interval
1324 int8store(buf, iv->start);
1325 buf+= 8;
1326 int8store(buf, iv->end);
1327 buf+= 8;
1328 // iterate to next interval
1329 ivit.next();
1330 iv= ivit.get();
1331 } while (iv != NULL);
1332 // store number of intervals
1333 int8store(n_intervals_p, n_intervals);
1334 }
1335 }
1336 // store number of sids
1337 int8store(n_sids_p, n_sids);
1338 DBUG_ASSERT(buf - n_sids_p == (int)get_encoded_length());
1339 DBUG_VOID_RETURN;
1340 }
1341
1342
add_gtid_encoding(const uchar * encoded,size_t length,size_t * actual_length)1343 enum_return_status Gtid_set::add_gtid_encoding(const uchar *encoded,
1344 size_t length,
1345 size_t *actual_length)
1346 {
1347 DBUG_ENTER("Gtid_set::add_gtid_encoding(const uchar *, size_t)");
1348 if (sid_lock != NULL)
1349 sid_lock->assert_some_wrlock();
1350 size_t pos= 0;
1351 uint64 n_sids;
1352 Free_intervals_lock lock(this);
1353 // read number of SIDs
1354 if (length < 8)
1355 {
1356 DBUG_PRINT("error", ("(length=%lu) < 8", (ulong) length));
1357 goto report_error;
1358 }
1359 n_sids= uint8korr(encoded);
1360 pos+= 8;
1361 // iterate over SIDs
1362 for (uint i= 0; i < n_sids; i++)
1363 {
1364 // read SID and number of intervals
1365 if (length - pos < 16 + 8)
1366 {
1367 DBUG_PRINT("error", ("(length=%lu) - (pos=%lu) < 16 + 8. "
1368 "[n_sids=%llu i=%u]",
1369 (ulong) length, (ulong) pos, n_sids, i));
1370 goto report_error;
1371 }
1372 rpl_sid sid;
1373 sid.copy_from(encoded + pos);
1374 pos+= 16;
1375 uint64 n_intervals= uint8korr(encoded + pos);
1376 pos+= 8;
1377 rpl_sidno sidno= sid_map->add_sid(sid);
1378 if (sidno < 0)
1379 {
1380 DBUG_PRINT("error", ("sidno=%d", sidno));
1381 RETURN_REPORTED_ERROR;
1382 }
1383 PROPAGATE_REPORTED_ERROR(ensure_sidno(sidno));
1384 // iterate over intervals
1385 if (length - pos < 2 * 8 * n_intervals)
1386 {
1387 DBUG_PRINT("error", ("(length=%lu) - (pos=%lu) < 2 * 8 * (n_intervals=%llu)",
1388 (ulong) length, (ulong) pos, n_intervals));
1389 goto report_error;
1390 }
1391 Interval_iterator ivit(this, sidno);
1392 rpl_gno last= 0;
1393 for (uint i= 0; i < n_intervals; i++)
1394 {
1395 // read one interval
1396 rpl_gno start= sint8korr(encoded + pos);
1397 pos+= 8;
1398 rpl_gno end= sint8korr(encoded + pos);
1399 pos+= 8;
1400 if (start <= last || end <= start)
1401 {
1402 DBUG_PRINT("error", ("last=%lld start=%lld end=%lld",
1403 last, start, end));
1404 goto report_error;
1405 }
1406 last= end;
1407 // Add interval. Use the existing iterator position if the
1408 // current interval does not begin before it. Otherwise iterate
1409 // from the beginning.
1410 Interval *current= ivit.get();
1411 if (current == NULL || start < current->start)
1412 ivit.init(this, sidno);
1413 DBUG_PRINT("info", ("adding %d:%lld-%lld", sidno, start, end - 1));
1414 PROPAGATE_REPORTED_ERROR(add_gno_interval(&ivit, start, end, &lock));
1415 }
1416 }
1417 DBUG_ASSERT(pos <= length);
1418 if (actual_length == NULL)
1419 {
1420 if (pos != length)
1421 {
1422 DBUG_PRINT("error", ("(pos=%lu) != (length=%lu)", (ulong) pos,
1423 (ulong) length));
1424 goto report_error;
1425 }
1426 }
1427 else
1428 *actual_length= pos;
1429
1430 RETURN_OK;
1431
1432 report_error:
1433 BINLOG_ERROR(("Malformed GTID_set encoding."),
1434 (ER_MALFORMED_GTID_SET_ENCODING, MYF(0)));
1435 RETURN_REPORTED_ERROR;
1436 }
1437
1438
get_encoded_length() const1439 size_t Gtid_set::get_encoded_length() const
1440 {
1441 if (sid_lock != NULL)
1442 sid_lock->assert_some_wrlock();
1443 size_t ret= 8;
1444 rpl_sidno max_sidno= get_max_sidno();
1445 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
1446 if (contains_sidno(sidno))
1447 ret+= 16 + 8 + 2 * 8 * get_n_intervals(sidno);
1448 return ret;
1449 }
1450