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