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