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