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