MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
rpl_gtid.h
1 /* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or
4  modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation; version 2 of the
6  License.
7 
8  This program is distributed in the hope that it will be useful, but
9  WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
16  02110-1301 USA */
17 
18 
19 #ifndef RPL_GTID_H_INCLUDED
20 #define RPL_GTID_H_INCLUDED
21 
22 
23 #include <m_string.h>
24 #include <mysqld_error.h>
25 #include <my_global.h>
26 #ifdef MYSQL_SERVER
27 #include <mysqld.h>
28 #endif
29 
40 #ifdef MYSQL_CLIENT
41 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) error MYSQLBINLOG_ERROR
42 #else
43 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) my_error SERVER_ERROR
44 #endif
45 
46 
47 #include "hash.h"
48 #include "lf.h"
49 #include "my_atomic.h"
50 
55 #define SKIP_WHITESPACE() while (my_isspace(&my_charset_utf8_general_ci, *s)) s++
56 /*
57  This macro must be used to filter out parts of the code that
58  is not used now but may be useful in future. In other words,
59  we want to keep such code until we make up our minds on whether
60  it should be removed or not.
61 */
62 #undef NON_DISABLED_GTID
63 
64 /*
65  This macro must be used to filter out parts of the code that
66  is not used now but we are not sure if there is a bug around
67  them. In other words, we want to keep such code until we have
68  time to investigate it.
69 */
70 #undef NON_ERROR_GTID
71 
72 #ifndef MYSQL_CLIENT
73 class String;
74 class THD;
75 #endif // ifndef MYSQL_CLIENT
76 
77 
79 typedef int32 rpl_sidno;
81 typedef int64 rpl_gno;
83 typedef int64 rpl_binlog_pos;
84 
85 
102 enum enum_return_status
103 {
105  RETURN_STATUS_OK= 0,
107  RETURN_STATUS_UNREPORTED_ERROR= 1,
109  RETURN_STATUS_REPORTED_ERROR= 2
110 };
111 
129 #ifdef DBUG_OFF
130 #define __CHECK_RETURN_STATUS(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED)
131 #else
132 extern void check_return_status(enum_return_status status,
133  const char *action, const char *status_name,
134  int allow_unreported);
135 #define __CHECK_RETURN_STATUS(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED) \
136  check_return_status(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED);
137 #endif
138 
143 #define __PROPAGATE_ERROR(STATUS, RETURN_VALUE, ALLOW_UNREPORTED) \
144  do \
145  { \
146  enum_return_status __propagate_error_status= STATUS; \
147  if (__propagate_error_status != RETURN_STATUS_OK) { \
148  __CHECK_RETURN_STATUS(__propagate_error_status, "Propagating", \
149  #STATUS, ALLOW_UNREPORTED); \
150  DBUG_RETURN(RETURN_VALUE); \
151  } \
152  } while (0)
153 
154 #define __RETURN_STATUS(STATUS, ALLOW_UNREPORTED) \
155  do \
156  { \
157  enum_return_status __return_status_status= STATUS; \
158  __CHECK_RETURN_STATUS(__return_status_status, "Returning", \
159  #STATUS, ALLOW_UNREPORTED); \
160  DBUG_RETURN(__return_status_status); \
161  } while (0)
162 
166 #define PROPAGATE_ERROR(STATUS) \
167  __PROPAGATE_ERROR(STATUS, __propagate_error_status, true)
168 
173 #define PROPAGATE_REPORTED_ERROR(STATUS) \
174  __PROPAGATE_ERROR(STATUS, __propagate_error_status, false)
175 
180 #define PROPAGATE_REPORTED_ERROR_INT(STATUS) \
181  __PROPAGATE_ERROR(STATUS, 1, false)
182 
186 #define RETURN_STATUS(STATUS) __RETURN_STATUS(STATUS, true)
187 
192 #define RETURN_REPORTED_STATUS(STATUS) __RETURN_STATUS(STATUS, false)
193 
194 #define RETURN_OK DBUG_RETURN(RETURN_STATUS_OK)
195 
196 #define RETURN_REPORTED_ERROR RETURN_STATUS(RETURN_STATUS_REPORTED_ERROR)
197 
198 #define RETURN_UNREPORTED_ERROR RETURN_STATUS(RETURN_STATUS_UNREPORTED_ERROR)
199 
200 
202 const rpl_gno MAX_GNO= LONGLONG_MAX;
204 const int MAX_GNO_TEXT_LENGTH= 19;
206 const int MAX_THREAD_ID_TEXT_LENGTH= 19;
207 
208 
217 rpl_gno parse_gno(const char **s);
225 int format_gno(char *s, rpl_gno gno);
226 
227 
234 struct Uuid
235 {
241  enum_return_status parse(const char *string);
243  void clear() { memset(bytes, 0, BYTE_LENGTH); }
245  void copy_from(const uchar *data) { memcpy(bytes, data, BYTE_LENGTH); }
247  void copy_from(const Uuid &data) { copy_from(data.bytes); }
249  void copy_to(uchar *data) const { memcpy(data, bytes, BYTE_LENGTH); }
251  bool equals(const Uuid &other) const
252  { return memcmp(bytes, other.bytes, BYTE_LENGTH) == 0; }
259  size_t to_string(char *buf) const;
261  static size_t to_string(const uchar* bytes_arg, char *buf);
262 #ifndef DBUG_OFF
263 
264  void print() const
265  {
266  char buf[TEXT_LENGTH + 1];
267  to_string(buf);
268  printf("%s\n", buf);
269  }
270 #endif
271 
272  void dbug_print(const char *text= "") const
273  {
274 #ifndef DBUG_OFF
275  char buf[TEXT_LENGTH + 1];
276  to_string(buf);
277  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf));
278 #endif
279  }
284  static bool is_valid(const char *string);
286  static const size_t TEXT_LENGTH= 36;
288  static const size_t BYTE_LENGTH= 16;
290  static const size_t BIT_LENGTH= 128;
293 private:
294  static const int NUMBER_OF_SECTIONS= 5;
295  static const int bytes_per_section[NUMBER_OF_SECTIONS];
296  static const int hex_to_byte[256];
297 };
298 
299 
300 typedef Uuid rpl_sid;
301 
302 
318 {
319 public:
322  {
323 #ifndef DBUG_OFF
324  my_atomic_rwlock_init(&atomic_lock);
325  lock_state= 0;
326 #else
327  is_write_lock= false;
328 #endif
329 #ifdef MYSQL_SERVER
330  mysql_rwlock_init(key_rwlock_global_sid_lock, &rwlock);
331 #else
332  mysql_rwlock_init(0, &rwlock);
333 #endif
334  }
337  {
338 #ifndef DBUG_OFF
339  my_atomic_rwlock_destroy(&atomic_lock);
340 #endif
341  mysql_rwlock_destroy(&rwlock);
342  }
343 
345  inline void rdlock()
346  {
347  mysql_rwlock_rdlock(&rwlock);
349 #ifndef DBUG_OFF
350  my_atomic_rwlock_wrlock(&atomic_lock);
351  my_atomic_add32(&lock_state, 1);
352  my_atomic_rwlock_wrunlock(&atomic_lock);
353 #endif
354  }
356  inline void wrlock()
357  {
358  mysql_rwlock_wrlock(&rwlock);
359  assert_no_lock();
360 #ifndef DBUG_OFF
361  my_atomic_rwlock_wrlock(&atomic_lock);
362  my_atomic_store32(&lock_state, -1);
363  my_atomic_rwlock_wrunlock(&atomic_lock);
364 #else
365  is_write_lock= true;
366 #endif
367  }
369  inline void unlock()
370  {
372 #ifndef DBUG_OFF
373  my_atomic_rwlock_wrlock(&atomic_lock);
374  int val= my_atomic_load32(&lock_state);
375  if (val > 0)
376  my_atomic_add32(&lock_state, -1);
377  else if (val == -1)
378  my_atomic_store32(&lock_state, 0);
379  else
380  DBUG_ASSERT(0);
381  my_atomic_rwlock_wrunlock(&atomic_lock);
382 #else
383  is_write_lock= false;
384 #endif
385  mysql_rwlock_unlock(&rwlock);
386  }
391  inline bool is_wrlock()
392  {
394 #ifndef DBUG_OFF
395  return get_state() == -1;
396 #else
397  return is_write_lock;
398 #endif
399  }
400 
402  inline void assert_some_lock() const
403  { DBUG_ASSERT(get_state() != 0); }
405  inline void assert_some_rdlock() const
406  { DBUG_ASSERT(get_state() > 0); }
408  inline void assert_some_wrlock() const
409  { DBUG_ASSERT(get_state() == -1); }
411  inline void assert_no_wrlock() const
412  { DBUG_ASSERT(get_state() >= 0); }
414  inline void assert_no_rdlock() const
415  { DBUG_ASSERT(get_state() <= 0); }
417  inline void assert_no_lock() const
418  { DBUG_ASSERT(get_state() == 0); }
419 
420 private:
421 #ifndef DBUG_OFF
422 
428  volatile int32 lock_state;
430  mutable my_atomic_rwlock_t atomic_lock;
432  inline int32 get_state() const
433  {
434  int32 ret;
435  my_atomic_rwlock_rdlock(&atomic_lock);
436  ret= my_atomic_load32(const_cast<volatile int32*>(&lock_state));
437  my_atomic_rwlock_rdunlock(&atomic_lock);
438  return ret;
439  }
440 #else
441  bool is_write_lock;
442 #endif
443 
444  mysql_rwlock_t rwlock;
445 };
446 
447 
449 extern Checkable_rwlock *global_sid_lock;
450 
451 
467 class Sid_map
468 {
469 public:
476  Sid_map(Checkable_rwlock *sid_lock);
478  ~Sid_map();
479 #ifdef NON_DISABLED_GTID
480 
485  enum_return_status clear();
486 #endif
487 
500  rpl_sidno add_sid(const rpl_sid &sid);
511  rpl_sidno sid_to_sidno(const rpl_sid &sid) const
512  {
513  if (sid_lock != NULL)
514  sid_lock->assert_some_lock();
515  Node *node= (Node *)my_hash_search(&_sid_to_sidno, sid.bytes,
517  if (node == NULL)
518  return 0;
519  return node->sidno;
520  }
534  const rpl_sid &sidno_to_sid(rpl_sidno sidno) const
535  {
536  if (sid_lock != NULL)
537  sid_lock->assert_some_lock();
538  DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno());
539  return (*dynamic_element(&_sidno_to_sid, sidno - 1, Node **))->sid;
540  }
549  rpl_sidno get_sorted_sidno(rpl_sidno n) const
550  {
551  if (sid_lock != NULL)
552  sid_lock->assert_some_lock();
553  rpl_sidno ret= *dynamic_element(&_sorted, n, rpl_sidno *);
554  return ret;
555  }
562  rpl_sidno get_max_sidno() const
563  {
564  if (sid_lock != NULL)
565  sid_lock->assert_some_lock();
566  return _sidno_to_sid.elements;
567  }
568 
569 private:
571  struct Node
572  {
573  rpl_sidno sidno;
574  rpl_sid sid;
575  };
576 
588  enum_return_status add_node(rpl_sidno sidno, const rpl_sid &sid);
589 
591  mutable Checkable_rwlock *sid_lock;
592 
597  DYNAMIC_ARRAY _sidno_to_sid;
602  HASH _sid_to_sidno;
609  DYNAMIC_ARRAY _sorted;
610 };
611 
612 
613 extern Sid_map *global_sid_map;
614 
615 
637 {
638 public:
645  Mutex_cond_array(Checkable_rwlock *global_lock);
649  inline void lock(int n) const
650  {
651  assert_not_owner(n);
652  mysql_mutex_lock(&get_mutex_cond(n)->mutex);
653  }
655  inline void unlock(int n) const
656  {
657  assert_owner(n);
658  mysql_mutex_unlock(&get_mutex_cond(n)->mutex);
659  }
661  inline void broadcast(int n) const
662  {
663  mysql_cond_broadcast(&get_mutex_cond(n)->cond);
664  }
669  inline void assert_owner(int n) const
670  {
671 #ifndef DBUG_OFF
672  mysql_mutex_assert_owner(&get_mutex_cond(n)->mutex);
673 #endif
674  }
679  inline void assert_not_owner(int n) const
680  {
681 #ifndef DBUG_OFF
682  mysql_mutex_assert_not_owner(&get_mutex_cond(n)->mutex);
683 #endif
684  }
693  inline void wait(int n) const
694  {
695  DBUG_ENTER("Mutex_cond_array::wait");
696  Mutex_cond *mutex_cond= get_mutex_cond(n);
697  global_lock->unlock();
698  mysql_mutex_assert_owner(&mutex_cond->mutex);
699  mysql_cond_wait(&mutex_cond->cond, &mutex_cond->mutex);
700  mysql_mutex_assert_owner(&mutex_cond->mutex);
701  DBUG_VOID_RETURN;
702  }
703 #ifndef MYSQL_CLIENT
704 
705  void enter_cond(THD *thd, int n, PSI_stage_info *stage,
706  PSI_stage_info *old_stage) const;
707 #endif // ifndef MYSQL_CLIENT
708 
709  inline int get_max_index() const
710  {
711  global_lock->assert_some_lock();
712  return array.elements - 1;
713  }
724  enum_return_status ensure_index(int n);
725 private:
727  struct Mutex_cond
728  {
729  mysql_mutex_t mutex;
730  mysql_cond_t cond;
731  };
733  inline Mutex_cond *get_mutex_cond(int n) const
734  {
735  global_lock->assert_some_lock();
736  DBUG_ASSERT(n <= get_max_index());
737  Mutex_cond *ret= *dynamic_element(&array, n, Mutex_cond **);
738  DBUG_ASSERT(ret);
739  return ret;
740  }
742  mutable Checkable_rwlock *global_lock;
743  DYNAMIC_ARRAY array;
744 };
745 
746 
754 struct Gtid
755 {
757  rpl_sidno sidno;
759  rpl_gno gno;
760 
762  void clear() { sidno= 0; gno= 0; }
767  static const int MAX_TEXT_LENGTH= Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH;
772  static bool is_valid(const char *text);
780  int to_string(const rpl_sid &sid, char *buf) const;
788  int to_string(const Sid_map *sid_map, char *buf) const;
790  bool equals(const Gtid &other) const
791  { return sidno == other.sidno && gno == other.gno; }
798  enum_return_status parse(Sid_map *sid_map, const char *text);
799 
800 #ifndef DBUG_OFF
801 
802  void print(const Sid_map *sid_map) const
803  {
804  char buf[MAX_TEXT_LENGTH + 1];
805  to_string(sid_map, buf);
806  printf("%s\n", buf);
807  }
808 #endif
809 
810  void dbug_print(const Sid_map *sid_map, const char *text= "") const
811  {
812 #ifndef DBUG_OFF
813  char buf[MAX_TEXT_LENGTH + 1];
814  to_string(sid_map, buf);
815  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf));
816 #endif
817  }
818 };
819 
820 
842 class Gtid_set
843 {
844 public:
854  Gtid_set(Sid_map *sid_map, Checkable_rwlock *sid_lock= NULL);
871  Gtid_set(Sid_map *sid_map, const char *text, enum_return_status *status,
872  Checkable_rwlock *sid_lock= NULL);
873 private:
875  void init();
876 public:
878  ~Gtid_set();
885  void clear();
895  enum_return_status _add_gtid(rpl_sidno sidno, rpl_gno gno)
896  {
897  DBUG_ENTER("Gtid_set::_add_gtid(sidno, gno)");
898  Interval_iterator ivit(this, sidno);
899  Free_intervals_lock lock(this);
900  enum_return_status ret= add_gno_interval(&ivit, gno, gno + 1, &lock);
901  DBUG_RETURN(ret);
902  }
910  enum_return_status _remove_gtid(rpl_sidno sidno, rpl_gno gno)
911  {
912  DBUG_ENTER("Gtid_set::_remove_gtid(rpl_sidno, rpl_gno)");
913  if (sidno <= get_max_sidno())
914  {
915  Interval_iterator ivit(this, sidno);
916  Free_intervals_lock lock(this);
917  enum_return_status ret= remove_gno_interval(&ivit, gno, gno + 1, &lock);
918  DBUG_RETURN(ret);
919  }
920  RETURN_OK;
921  }
930  enum_return_status _add_gtid(const Gtid &gtid)
931  { return _add_gtid(gtid.sidno, gtid.gno); }
944  enum_return_status add_gtid_set(const Gtid_set *other);
951  enum_return_status remove_gtid_set(const Gtid_set *other);
980  enum_return_status add_gtid_text(const char *text, bool *anonymous= NULL);
992  enum_return_status add_gtid_encoding(const uchar *encoded, size_t length,
993  size_t *actual_length= NULL);
995  bool contains_gtid(rpl_sidno sidno, rpl_gno gno) const;
997  bool contains_gtid(const Gtid &gtid) const
998  { return contains_gtid(gtid.sidno, gtid.gno); }
1000  rpl_sidno get_max_sidno() const
1001  {
1002  if (sid_lock)
1003  sid_lock->assert_some_lock();
1004  return intervals.elements;
1005  }
1018  enum_return_status ensure_sidno(rpl_sidno sidno);
1020  bool is_subset(const Gtid_set *super) const;
1023  bool is_intersection_nonempty(const Gtid_set *other) const;
1031  enum_return_status intersection(const Gtid_set *other, Gtid_set *result);
1033  bool is_empty() const
1034  {
1035  Gtid_iterator git(this);
1036  return git.get().sidno == 0;
1037  }
1048  bool contains_sidno(rpl_sidno sidno) const
1049  {
1050  DBUG_ASSERT(sidno >= 1);
1051  if (sidno > get_max_sidno())
1052  return false;
1053  Const_interval_iterator ivit(this, sidno);
1054  return ivit.get() != NULL;
1055  }
1060  static bool is_valid(const char *text);
1065  char *to_string() const
1066  {
1067  char *str= (char *)my_malloc(get_string_length() + 1, MYF(MY_WME));
1068  if (str != NULL)
1069  to_string(str);
1070  return str;
1071  }
1072 #ifndef DBUG_OFF
1073 
1074  void print() const
1075  {
1076  char *str= to_string();
1077  printf("%s\n", str);
1078  my_free(str);
1079  }
1080 #endif
1081 
1085  void dbug_print(const char *text= "") const
1086  {
1087 #ifndef DBUG_OFF
1088  char *str= to_string();
1089  DBUG_PRINT("info", ("%s%s'%s'", text, *text ? ": " : "", str));
1090  my_free(str);
1091 #endif
1092  }
1093 
1099  {
1101  const char *begin;
1103  const char *end;
1105  const char *sid_gno_separator;
1109  const char *gno_gno_separator;
1111  const char *gno_sid_separator;
1113  const char *empty_set_string;
1115  const int begin_length;
1116  const int end_length;
1117  const int sid_gno_separator_length;
1118  const int gno_start_end_separator_length;
1119  const int gno_gno_separator_length;
1120  const int gno_sid_separator_length;
1121  const int empty_set_string_length;
1122  };
1133  int get_string_length(const String_format *string_format= NULL) const;
1143  int to_string(char *buf, const String_format *string_format= NULL) const;
1144 
1152  int to_string(char **buf, const String_format *string_format= NULL) const;
1153 
1169 
1171  Sid_map *get_sid_map() const { return sid_map; }
1172 
1177  struct Interval
1178  {
1179  public:
1181  rpl_gno start;
1183  rpl_gno end;
1185  bool equals(const Interval &other) const
1186  {
1187  return start == other.start && end == other.end;
1188  }
1191  };
1192 
1202  void add_interval_memory(int n_intervals, Interval *intervals_param)
1203  {
1204  if (sid_lock != NULL)
1205  mysql_mutex_lock(&free_intervals_mutex);
1206  add_interval_memory_lock_taken(n_intervals, intervals_param);
1207  if (sid_lock != NULL)
1208  mysql_mutex_unlock(&free_intervals_mutex);
1209  }
1210 
1211 
1222  template<typename Gtid_set_p, typename Interval_p> class Interval_iterator_base
1223  {
1224  public:
1231  Interval_iterator_base(Gtid_set_p gtid_set, rpl_sidno sidno)
1232  {
1233  DBUG_ASSERT(sidno >= 1 && sidno <= gtid_set->get_max_sidno());
1234  init(gtid_set, sidno);
1235  }
1237  Interval_iterator_base(Gtid_set_p gtid_set)
1238  { p= const_cast<Interval_p *>(&gtid_set->free_intervals); }
1240  inline void init(Gtid_set_p gtid_set, rpl_sidno sidno)
1241  { p= dynamic_element(&gtid_set->intervals, sidno - 1, Interval_p *); }
1243  inline void next()
1244  {
1245  DBUG_ASSERT(*p != NULL);
1246  p= const_cast<Interval_p *>(&(*p)->next);
1247  }
1249  inline Interval_p get() const { return *p; }
1250  protected:
1256  Interval_p *p;
1257  };
1258 
1263  : public Interval_iterator_base<const Gtid_set *, const Interval *>
1264  {
1265  public:
1267  Const_interval_iterator(const Gtid_set *gtid_set, rpl_sidno sidno)
1268  : Interval_iterator_base<const Gtid_set *, const Interval *>(gtid_set, sidno) {}
1271  : Interval_iterator_base<const Gtid_set *, const Interval *>(gtid_set) {}
1272  };
1273 
1279  : public Interval_iterator_base<Gtid_set *, Interval *>
1280  {
1281  public:
1283  Interval_iterator(Gtid_set *gtid_set, rpl_sidno sidno)
1284  : Interval_iterator_base<Gtid_set *, Interval *>(gtid_set, sidno) {}
1287  : Interval_iterator_base<Gtid_set *, Interval *>(gtid_set) {}
1288  private:
1293  inline void set(Interval *iv) { *p= iv; }
1295  inline void insert(Interval *iv) { iv->next= *p; set(iv); }
1297  inline void remove(Gtid_set *gtid_set)
1298  {
1299  DBUG_ASSERT(get() != NULL);
1300  Interval *next= (*p)->next;
1301  gtid_set->put_free_interval(*p);
1302  set(next);
1303  }
1311  friend class Gtid_set;
1312  };
1313 
1314 
1320  {
1321  public:
1322  Gtid_iterator(const Gtid_set *gs)
1323  : gtid_set(gs), sidno(0), ivit(gs)
1324  {
1325  if (gs->sid_lock != NULL)
1326  gs->sid_lock->assert_some_wrlock();
1327  next_sidno();
1328  }
1330  inline void next()
1331  {
1332  DBUG_ASSERT(gno > 0 && sidno > 0);
1333  // go to next group in current interval
1334  gno++;
1335  // end of interval? then go to next interval for this sidno
1336  if (gno == ivit.get()->end)
1337  {
1338  ivit.next();
1339  const Interval *iv= ivit.get();
1340  // last interval for this sidno? then go to next sidno
1341  if (iv == NULL)
1342  {
1343  next_sidno();
1344  // last sidno? then don't try more
1345  if (sidno == 0)
1346  return;
1347  iv= ivit.get();
1348  }
1349  gno= iv->start;
1350  }
1351  }
1353  inline Gtid get() const
1354  {
1355  Gtid ret= { sidno, gno };
1356  return ret;
1357  }
1358  private:
1360  inline void next_sidno()
1361  {
1362  const Interval *iv;
1363  do
1364  {
1365  sidno++;
1366  if (sidno > gtid_set->get_max_sidno())
1367  {
1368  sidno= 0;
1369  gno= 0;
1370  return;
1371  }
1372  ivit.init(gtid_set, sidno);
1373  iv= ivit.get();
1374  } while (iv == NULL);
1375  gno= iv->start;
1376  }
1378  const Gtid_set *gtid_set;
1383  rpl_sidno sidno;
1388  rpl_gno gno;
1390  Const_interval_iterator ivit;
1391  };
1392 
1393 public:
1394 
1398  void encode(uchar *buf) const;
1403  size_t get_encoded_length() const;
1404 
1405 private:
1412  struct Interval_chunk
1413  {
1414  Interval_chunk *next;
1415  Interval intervals[1];
1416  };
1418  static const int CHUNK_GROW_SIZE= 8;
1419 
1420 /*
1421  Functions sidno_equals() and equals() are only used by unitests
1422 */
1423 #ifdef NON_DISABLED_UNITTEST_GTID
1424 
1433  bool sidno_equals(rpl_sidno sidno,
1434  const Gtid_set *other, rpl_sidno other_sidno) const;
1436  bool equals(const Gtid_set *other) const;
1437 #endif
1438 
1440  int get_n_intervals(rpl_sidno sidno) const
1441  {
1442  Const_interval_iterator ivit(this, sidno);
1443  int ret= 0;
1444  while (ivit.get() != NULL)
1445  {
1446  ret++;
1447  ivit.next();
1448  }
1449  return ret;
1450  }
1452  int get_n_intervals() const
1453  {
1454  if (sid_lock != NULL)
1455  sid_lock->assert_some_wrlock();
1456  rpl_sidno max_sidno= get_max_sidno();
1457  int ret= 0;
1458  for (rpl_sidno sidno= 1; sidno < max_sidno; sidno++)
1459  ret+= get_n_intervals(sidno);
1460  return ret;
1461  }
1469  enum_return_status create_new_chunk(int size);
1480  enum_return_status get_free_interval(Interval **out);
1485  void put_free_interval(Interval *iv);
1491  void add_interval_memory_lock_taken(int n_ivs, Interval *ivs);
1492 
1494  mutable Checkable_rwlock *sid_lock;
1499  mysql_mutex_t free_intervals_mutex;
1513  class Free_intervals_lock
1514  {
1515  public:
1517  Free_intervals_lock(Gtid_set *_gtid_set)
1518  : gtid_set(_gtid_set), locked(false) {}
1520  void lock_if_not_locked()
1521  {
1522  if (gtid_set->sid_lock && !locked)
1523  {
1524  mysql_mutex_lock(&gtid_set->free_intervals_mutex);
1525  locked= true;
1526  }
1527  }
1529  void unlock_if_locked()
1530  {
1531  if (gtid_set->sid_lock && locked)
1532  {
1533  mysql_mutex_unlock(&gtid_set->free_intervals_mutex);
1534  locked= false;
1535  }
1536  }
1538  ~Free_intervals_lock()
1539  {
1540  unlock_if_locked();
1541  }
1542  private:
1543  Gtid_set *gtid_set;
1544  bool locked;
1545  };
1546  void assert_free_intervals_locked()
1547  {
1548  if (sid_lock != NULL)
1549  mysql_mutex_assert_owner(&free_intervals_mutex);
1550  }
1551 
1571  enum_return_status add_gno_interval(Interval_iterator *ivitp,
1572  rpl_gno start, rpl_gno end,
1573  Free_intervals_lock *lock);
1596  enum_return_status remove_gno_interval(Interval_iterator *ivitp,
1597  rpl_gno start, rpl_gno end,
1598  Free_intervals_lock *lock);
1615  enum_return_status add_gno_intervals(rpl_sidno sidno,
1616  Const_interval_iterator ivit,
1617  Free_intervals_lock *lock);
1634  enum_return_status remove_gno_intervals(rpl_sidno sidno,
1635  Const_interval_iterator ivit,
1636  Free_intervals_lock *lock);
1637 
1640  static bool is_interval_subset(Const_interval_iterator *sub,
1641  Const_interval_iterator *super);
1643  static bool is_interval_intersection_nonempty(Const_interval_iterator *ivit1,
1644  Const_interval_iterator *ivit2);
1645 
1647  Sid_map *sid_map;
1652  DYNAMIC_ARRAY intervals;
1654  Interval *free_intervals;
1656  Interval_chunk *chunks;
1658  mutable int cached_string_length;
1660  mutable const String_format *cached_string_format;
1661 #ifndef DBUG_OFF
1662 
1666  int n_chunks;
1667 #endif
1668 
1670 #ifdef FRIEND_OF_GTID_SET
1671  friend FRIEND_OF_GTID_SET;
1672 #endif
1673 
1675 };
1676 
1677 
1699 {
1705  inline Gtid_set *get_gtid_set() const
1706  {
1707  DBUG_ASSERT(!(is_non_null && gtid_set == NULL));
1708  return is_non_null ? gtid_set : NULL;
1709  }
1716  {
1717  if (!is_non_null)
1718  {
1719  if (gtid_set == NULL)
1720  gtid_set= new Gtid_set(sm);
1721  else
1722  gtid_set->clear();
1723  }
1724  is_non_null= (gtid_set != NULL);
1725  return gtid_set;
1726  }
1728  inline void set_null() { is_non_null= false; }
1729 };
1730 
1731 
1748 {
1749 public:
1756  Owned_gtids(Checkable_rwlock *sid_lock);
1758  ~Owned_gtids();
1766  enum_return_status add_gtid_owner(const Gtid &gtid, my_thread_id owner);
1774  my_thread_id get_owner(const Gtid &gtid) const;
1783  void remove_gtid(const Gtid &gtid);
1796  enum_return_status ensure_sidno(rpl_sidno sidno);
1799  bool is_intersection_nonempty(const Gtid_set *other) const;
1801  bool is_empty() const
1802  {
1803  Gtid_iterator git(this);
1804  return git.get().sidno == 0;
1805  }
1807  rpl_sidno get_max_sidno() const
1808  {
1809  sid_lock->assert_some_lock();
1810  return sidno_to_hash.elements;
1811  }
1812 
1819  int to_string(char *out) const
1820  {
1821  char *p= out;
1822  rpl_sidno max_sidno= get_max_sidno();
1823  rpl_sidno sid_map_max_sidno= global_sid_map->get_max_sidno();
1824  for (rpl_sidno sid_i= 0; sid_i < sid_map_max_sidno; sid_i++)
1825  {
1826  rpl_sidno sidno= global_sid_map->get_sorted_sidno(sid_i);
1827  if (sidno > max_sidno)
1828  continue;
1829  HASH *hash= get_hash(sidno);
1830  bool printed_sid= false;
1831  for (uint i= 0; i < hash->records; i++)
1832  {
1833  Node *node= (Node *)my_hash_element(hash, i);
1834  DBUG_ASSERT(node != NULL);
1835  if (!printed_sid)
1836  {
1837  p+= global_sid_map->sidno_to_sid(sidno).to_string(p);
1838  printed_sid= true;
1839  }
1840  p+= sprintf(p, ":%lld#%lu", node->gno, node->owner);
1841  }
1842  }
1843  *p= 0;
1844  return (int)(p - out);
1845  }
1846 
1852  size_t get_max_string_length() const
1853  {
1854  rpl_sidno max_sidno= get_max_sidno();
1855  size_t ret= 0;
1856  for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
1857  {
1858  HASH *hash= get_hash(sidno);
1859  if (hash->records > 0)
1860  ret+= rpl_sid::TEXT_LENGTH +
1861  hash->records * (1 + MAX_GNO_TEXT_LENGTH +
1862  1 + MAX_THREAD_ID_TEXT_LENGTH);
1863  }
1864  return 1 + ret;
1865  }
1866 
1870  bool thread_owns_anything(my_thread_id thd_id) const
1871  {
1872  Gtid_iterator git(this);
1873  Node *node= git.get_node();
1874  while (node != NULL)
1875  {
1876  if (node->owner == thd_id)
1877  return true;
1878  git.next();
1879  node= git.get_node();
1880  }
1881  return false;
1882  }
1883 
1884 #ifndef DBUG_OFF
1885 
1889  char *to_string() const
1890  {
1891  char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME));
1892  DBUG_ASSERT(str != NULL);
1893  to_string(str);
1894  return str;
1895  }
1897  void print() const
1898  {
1899  char *str= to_string();
1900  printf("%s\n", str);
1901  my_free(str);
1902  }
1903 #endif
1904 
1908  void dbug_print(const char *text= "") const
1909  {
1910 #ifndef DBUG_OFF
1911  char *str= to_string();
1912  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str));
1913  my_free(str);
1914 #endif
1915  }
1916 private:
1918  struct Node
1919  {
1921  rpl_gno gno;
1923  my_thread_id owner;
1924  };
1926  mutable Checkable_rwlock *sid_lock;
1928  HASH *get_hash(rpl_sidno sidno) const
1929  {
1930  DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno());
1931  sid_lock->assert_some_lock();
1932  return *dynamic_element(&sidno_to_hash, sidno - 1, HASH **);
1933  }
1938  Node *get_node(const HASH *hash, rpl_gno gno) const
1939  {
1940  sid_lock->assert_some_lock();
1941  return (Node *)my_hash_search(hash, (const uchar *)&gno, sizeof(rpl_gno));
1942  }
1947  Node *get_node(const Gtid &gtid) const
1948  { return get_node(get_hash(gtid.sidno), gtid.gno); };
1950  bool contains_gtid(const Gtid &gtid) const { return get_node(gtid) != NULL; }
1952  DYNAMIC_ARRAY sidno_to_hash;
1953 
1954 public:
1960  {
1961  public:
1962  Gtid_iterator(const Owned_gtids* og)
1963  : owned_gtids(og), sidno(1), hash(NULL), node_index(0), node(NULL)
1964  {
1965  max_sidno= owned_gtids->get_max_sidno();
1966  if (sidno <= max_sidno)
1967  hash= owned_gtids->get_hash(sidno);
1968  next();
1969  }
1971  inline void next()
1972  {
1973 #ifndef DBUG_OFF
1974  if (owned_gtids->sid_lock)
1975  owned_gtids->sid_lock->assert_some_wrlock();
1976 #endif
1977 
1978  while (sidno <= max_sidno)
1979  {
1980  DBUG_ASSERT(hash != NULL);
1981  if (node_index < hash->records)
1982  {
1983  node= (Node *)my_hash_element(hash, node_index);
1984  DBUG_ASSERT(node != NULL);
1985  // Jump to next node on next iteration.
1986  node_index++;
1987  return;
1988  }
1989 
1990  node_index= 0;
1991  // hash is initialized on constructor or in previous iteration
1992  // for current SIDNO, so we must increment for next iteration.
1993  sidno++;
1994  if (sidno <= max_sidno)
1995  hash= owned_gtids->get_hash(sidno);
1996  }
1997  node= NULL;
1998  }
2000  inline Gtid get() const
2001  {
2002  Gtid ret= { 0, 0 };
2003  if (node)
2004  {
2005  ret.sidno= sidno;
2006  ret.gno= node->gno;
2007  }
2008  return ret;
2009  }
2011  inline Node* get_node() const
2012  {
2013  return node;
2014  }
2015  private:
2017  const Owned_gtids *owned_gtids;
2019  rpl_sidno sidno;
2021  rpl_sidno max_sidno;
2023  HASH *hash;
2025  uint node_index;
2027  Node *node;
2028  };
2029 };
2030 
2031 
2063 {
2064 public:
2072  Gtid_state(Checkable_rwlock *_sid_lock, Sid_map *_sid_map)
2073  : sid_lock(_sid_lock),
2074  sid_map(_sid_map),
2075  sid_locks(sid_lock),
2076  logged_gtids(sid_map, sid_lock),
2077  lost_gtids(sid_map, sid_lock),
2078  owned_gtids(sid_lock) {}
2091  int init();
2099  void clear();
2108  bool is_logged(const Gtid &gtid) const
2109  {
2110  DBUG_ENTER("Gtid_state::is_logged");
2111  bool ret= logged_gtids.contains_gtid(gtid);
2112  DBUG_RETURN(ret);
2113  }
2121  my_thread_id get_owner(const Gtid &gtid) const
2122  { return owned_gtids.get_owner(gtid); }
2123 #ifndef MYSQL_CLIENT
2124 
2133  enum_return_status acquire_ownership(THD *thd, const Gtid &gtid);
2146  enum_return_status update_on_flush(THD *thd);
2157  void update_on_commit(THD *thd);
2170  void update_on_rollback(THD *thd);
2171 #endif // ifndef MYSQL_CLIENT
2172 
2180  rpl_gno get_automatic_gno(rpl_sidno sidno) const;
2182  void lock_sidno(rpl_sidno sidno) { sid_locks.lock(sidno); }
2184  void unlock_sidno(rpl_sidno sidno) { sid_locks.unlock(sidno); }
2186  void broadcast_sidno(rpl_sidno sidno) { sid_locks.broadcast(sidno); }
2188  void assert_sidno_lock_owner(rpl_sidno sidno)
2189  { sid_locks.assert_owner(sidno); }
2190 #ifndef MYSQL_CLIENT
2191 
2202  void wait_for_gtid(THD *thd, const Gtid &gtid);
2203 #endif // ifndef MYSQL_CLIENT
2204 #ifdef HAVE_NDB_BINLOG
2205 
2209  void lock_sidnos(const Gtid_set *set);
2214  void unlock_sidnos(const Gtid_set *set);
2219  void broadcast_sidnos(const Gtid_set *set);
2220 #endif // ifdef HAVE_NDB_BINLOG
2221 
2235  enum_return_status ensure_sidno();
2246  enum_return_status add_lost_gtids(const char *text);
2248  const Gtid_set *get_logged_gtids() const { return &logged_gtids; }
2250  const Gtid_set *get_lost_gtids() const { return &lost_gtids; }
2252  const Owned_gtids *get_owned_gtids() const { return &owned_gtids; }
2254  rpl_sidno get_server_sidno() const { return server_sidno; }
2255 #ifndef DBUG_OFF
2256 
2261  size_t get_max_string_length() const
2262  {
2263  return owned_gtids.get_max_string_length() +
2264  logged_gtids.get_string_length() +
2265  lost_gtids.get_string_length() +
2266  100;
2267  }
2269  int to_string(char *buf) const
2270  {
2271  char *p= buf;
2272  p+= sprintf(p, "Logged GTIDs:\n");
2273  p+= logged_gtids.to_string(p);
2274  p+= sprintf(p, "\nOwned GTIDs:\n");
2275  p+= owned_gtids.to_string(p);
2276  p+= sprintf(p, "\nLost GTIDs:\n");
2277  p+= lost_gtids.to_string(p);
2278  return (int)(p - buf);
2279  }
2281  char *to_string() const
2282  {
2283  char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME));
2284  to_string(str);
2285  return str;
2286  }
2288  void print() const
2289  {
2290  char *str= to_string();
2291  printf("%s", str);
2292  my_free(str);
2293  }
2294 #endif
2295 
2299  void dbug_print(const char *text= "") const
2300  {
2301 #ifndef DBUG_OFF
2302  sid_lock->assert_some_wrlock();
2303  char *str= to_string();
2304  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str));
2305  my_free(str);
2306 #endif
2307  }
2308 private:
2309 #ifdef HAVE_NDB_BINLOG
2310 
2311  void lock_owned_sidnos(const THD *thd);
2312 #endif
2313 
2314  void unlock_owned_sidnos(const THD *thd);
2316  void broadcast_owned_sidnos(const THD *thd);
2324  void update_owned_gtids_impl(THD *thd, bool is_commit);
2325 
2326 
2328  mutable Checkable_rwlock *sid_lock;
2330  mutable Sid_map *sid_map;
2332  Mutex_cond_array sid_locks;
2334  Gtid_set logged_gtids;
2339  Gtid_set lost_gtids;
2341  Owned_gtids owned_gtids;
2343  rpl_sidno server_sidno;
2344 
2346 #ifdef FRIEND_OF_GTID_STATE
2347  friend FRIEND_OF_GTID_STATE;
2348 #endif
2349 };
2350 
2351 
2353 extern Gtid_state *gtid_state;
2354 
2355 
2359 enum enum_group_type
2360 {
2365  AUTOMATIC_GROUP= 0, GTID_GROUP, ANONYMOUS_GROUP, INVALID_GROUP, UNDEFINED_GROUP
2366 };
2367 
2368 
2376 {
2378  enum_group_type type;
2386  void set(rpl_sidno sidno, rpl_gno gno)
2387  { type= GTID_GROUP; gtid.sidno= sidno; gtid.gno= gno; }
2389  void set(const Gtid &gtid_param) { set(gtid_param.sidno, gtid_param.gno); }
2392  {
2393  type= AUTOMATIC_GROUP;
2394  }
2397  {
2398  if (type == GTID_GROUP)
2399  type= UNDEFINED_GROUP;
2400  }
2402  void clear() { set(0, 0); }
2404  bool equals(const Gtid_specification &other) const
2405  {
2406  return (type == other.type &&
2407  (type != GTID_GROUP || gtid.equals(other.gtid)));
2408  }
2413  bool equals(const Gtid &other_gtid) const
2414  { return type == GTID_GROUP && gtid.equals(other_gtid); }
2415 #ifndef MYSQL_CLIENT
2416 
2422  enum_return_status parse(Sid_map *sid_map, const char *text);
2426  static enum_group_type get_type(const char *text);
2428  static bool is_valid(const char *text)
2429  { return Gtid_specification::get_type(text) != INVALID_GROUP; }
2430 #endif
2431  static const int MAX_TEXT_LENGTH= Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH;
2440  int to_string(const Sid_map *sid_map, char *buf) const;
2451  int to_string(const rpl_sid *sid, char *buf) const;
2452 #ifndef DBUG_OFF
2453 
2454  void print() const
2455  {
2456  char buf[MAX_TEXT_LENGTH + 1];
2457  to_string(global_sid_map, buf);
2458  printf("%s\n", buf);
2459  }
2460 #endif
2461 
2465  void dbug_print(const char *text= "") const
2466  {
2467 #ifndef DBUG_OFF
2468  char buf[MAX_TEXT_LENGTH + 1];
2469  to_string(global_sid_map, buf);
2470  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf));
2471 #endif
2472  }
2473 };
2474 
2475 
2485 {
2492  rpl_binlog_pos binlog_offset;
2493 };
2494 
2495 
2501 {
2502 public:
2504  Group_cache();
2506  ~Group_cache();
2508  void clear();
2510  inline int get_n_groups() const { return groups.elements; }
2512  inline bool is_empty() const { return get_n_groups() == 0; }
2527  {
2528  EXTEND_EXISTING_GROUP, APPEND_NEW_GROUP, ERROR
2529  };
2530 #ifndef MYSQL_CLIENT
2532  add_logged_group(const THD *thd, my_off_t binlog_offset);
2533 #endif // ifndef MYSQL_CLIENT
2534 #ifdef NON_DISABLED_GTID
2535 
2542  enum_add_group_status add_empty_group(const Gtid &gtid);
2543 #endif // ifdef NON_DISABLED_GTID
2544 #ifndef MYSQL_CLIENT
2545 
2549  enum_return_status write_to_gtid_state() const;
2561  enum_return_status generate_automatic_gno(THD *thd);
2562 #endif // ifndef MYSQL_CLIENT
2563 
2570  bool contains_gtid(const Gtid &gtid) const;
2577  enum_return_status get_gtids(Gtid_set *gs) const;
2578 
2579 #ifndef DBUG_OFF
2580 
2584  size_t to_string(const Sid_map *sm, char *buf) const
2585  {
2586  int n_groups= get_n_groups();
2587  char *s= buf;
2588 
2589  s += sprintf(s, "%d groups = {\n", n_groups);
2590  for (int i= 0; i < n_groups; i++)
2591  {
2593  char uuid[Uuid::TEXT_LENGTH + 1]= "[]";
2594  if (group->spec.gtid.sidno)
2595  sm->sidno_to_sid(group->spec.gtid.sidno).to_string(uuid);
2596  s += sprintf(s, " %s:%lld [offset %lld] %s\n",
2597  uuid, group->spec.gtid.gno, group->binlog_offset,
2598  group->spec.type == GTID_GROUP ? "GTID" :
2599  group->spec.type == ANONYMOUS_GROUP ? "ANONYMOUS" :
2600  group->spec.type == AUTOMATIC_GROUP ? "AUTOMATIC" :
2601  "INVALID-GROUP-TYPE");
2602  }
2603  sprintf(s, "}\n");
2604  return s - buf;
2605  }
2610  size_t get_max_string_length() const
2611  {
2612  return (2 + Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH + 4 + 2 +
2613  40 + 10 + 21 + 1 + 100/*margin*/) * get_n_groups() + 100/*margin*/;
2614  }
2620  char *to_string(const Sid_map *sm) const
2621  {
2622  char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME));
2623  if (str)
2624  to_string(sm, str);
2625  return str;
2626  }
2628  void print(const Sid_map *sm) const
2629  {
2630  char *str= to_string(sm);
2631  printf("%s\n", str);
2632  my_free(str);
2633  }
2634 #endif
2635 
2639  void dbug_print(const Sid_map *sid_map, const char *text= "") const
2640  {
2641 #ifndef DBUG_OFF
2642  char *str= to_string(sid_map);
2643  DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str));
2644  my_free(str);
2645 #endif
2646  }
2647 
2655  {
2656  DBUG_ASSERT(index >= 0 && index < get_n_groups());
2657  return dynamic_element(&groups, index, Cached_group *);
2658  }
2659 
2660 private:
2662  DYNAMIC_ARRAY groups;
2663 
2668  Cached_group *get_last_group()
2669  {
2670  int n_groups= get_n_groups();
2671  return n_groups == 0 ? NULL : get_unsafe_pointer(n_groups - 1);
2672  }
2673 
2678  Cached_group *allocate_group()
2679  {
2680  Cached_group *ret= (Cached_group *)alloc_dynamic(&groups);
2681  if (ret == NULL)
2682  BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
2683  return ret;
2684  }
2685 
2693  enum_return_status add_group(const Cached_group *group);
2702  enum_return_status
2703  write_to_log_prepare(Group_cache *trx_group_cache,
2704  rpl_binlog_pos offset_after_last_statement,
2705  Cached_group **last_non_empty_group);
2706 
2708 #ifdef FRIEND_OF_GROUP_CACHE
2709  friend FRIEND_OF_GROUP_CACHE;
2710 #endif
2711 };
2712 
2717 enum enum_gtid_statement_status
2718 {
2720  GTID_STATEMENT_EXECUTE,
2722  GTID_STATEMENT_CANCEL,
2727  GTID_STATEMENT_SKIP
2728 };
2729 
2730 
2731 #ifndef MYSQL_CLIENT
2732 
2743 enum_gtid_statement_status
2744 gtid_before_statement(THD *thd, Group_cache *gsc, Group_cache *gtc);
2745 
2754 enum_gtid_statement_status gtid_pre_statement_checks(const THD *thd);
2755 
2762 void gtid_post_statement_checks(THD *thd);
2763 
2768 int gtid_rollback(THD *thd);
2769 
2770 int gtid_acquire_ownership_single(THD *thd);
2771 #ifdef HAVE_NDB_BINLOG
2772 int gtid_acquire_ownership_multiple(THD *thd);
2773 #endif
2774 
2775 #endif // ifndef MYSQL_CLIENT
2776 
2777 #endif /* RPL_GTID_H_INCLUDED */