19 #ifndef RPL_GTID_H_INCLUDED
20 #define RPL_GTID_H_INCLUDED
24 #include <mysqld_error.h>
25 #include <my_global.h>
41 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) error MYSQLBINLOG_ERROR
43 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) my_error SERVER_ERROR
49 #include "my_atomic.h"
55 #define SKIP_WHITESPACE() while (my_isspace(&my_charset_utf8_general_ci, *s)) s++
62 #undef NON_DISABLED_GTID
75 #endif // ifndef MYSQL_CLIENT
79 typedef int32 rpl_sidno;
81 typedef int64 rpl_gno;
83 typedef int64 rpl_binlog_pos;
102 enum enum_return_status
107 RETURN_STATUS_UNREPORTED_ERROR= 1,
109 RETURN_STATUS_REPORTED_ERROR= 2
130 #define __CHECK_RETURN_STATUS(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED)
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);
143 #define __PROPAGATE_ERROR(STATUS, RETURN_VALUE, ALLOW_UNREPORTED) \
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); \
154 #define __RETURN_STATUS(STATUS, ALLOW_UNREPORTED) \
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); \
166 #define PROPAGATE_ERROR(STATUS) \
167 __PROPAGATE_ERROR(STATUS, __propagate_error_status, true)
173 #define PROPAGATE_REPORTED_ERROR(STATUS) \
174 __PROPAGATE_ERROR(STATUS, __propagate_error_status, false)
180 #define PROPAGATE_REPORTED_ERROR_INT(STATUS) \
181 __PROPAGATE_ERROR(STATUS, 1, false)
186 #define RETURN_STATUS(STATUS) __RETURN_STATUS(STATUS, true)
192 #define RETURN_REPORTED_STATUS(STATUS) __RETURN_STATUS(STATUS, false)
194 #define RETURN_OK DBUG_RETURN(RETURN_STATUS_OK)
196 #define RETURN_REPORTED_ERROR RETURN_STATUS(RETURN_STATUS_REPORTED_ERROR)
198 #define RETURN_UNREPORTED_ERROR RETURN_STATUS(RETURN_STATUS_UNREPORTED_ERROR)
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;
217 rpl_gno parse_gno(
const char **s);
225 int format_gno(
char *s, rpl_gno gno);
241 enum_return_status
parse(
const char *
string);
261 static size_t to_string(
const uchar* bytes_arg,
char *
buf);
277 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", buf));
284 static bool is_valid(
const char *
string);
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];
324 my_atomic_rwlock_init(&atomic_lock);
327 is_write_lock=
false;
339 my_atomic_rwlock_destroy(&atomic_lock);
350 my_atomic_rwlock_wrlock(&atomic_lock);
351 my_atomic_add32(&lock_state, 1);
352 my_atomic_rwlock_wrunlock(&atomic_lock);
361 my_atomic_rwlock_wrlock(&atomic_lock);
362 my_atomic_store32(&lock_state, -1);
363 my_atomic_rwlock_wrunlock(&atomic_lock);
373 my_atomic_rwlock_wrlock(&atomic_lock);
374 int val= my_atomic_load32(&lock_state);
376 my_atomic_add32(&lock_state, -1);
378 my_atomic_store32(&lock_state, 0);
381 my_atomic_rwlock_wrunlock(&atomic_lock);
383 is_write_lock=
false;
395 return get_state() == -1;
397 return is_write_lock;
403 { DBUG_ASSERT(get_state() != 0); }
406 { DBUG_ASSERT(get_state() > 0); }
409 { DBUG_ASSERT(get_state() == -1); }
412 { DBUG_ASSERT(get_state() >= 0); }
415 { DBUG_ASSERT(get_state() <= 0); }
418 { DBUG_ASSERT(get_state() == 0); }
428 volatile int32 lock_state;
432 inline int32 get_state()
const
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);
479 #ifdef NON_DISABLED_GTID
485 enum_return_status clear();
513 if (sid_lock != NULL)
515 Node *node= (Node *)my_hash_search(&_sid_to_sidno, sid.
bytes,
536 if (sid_lock != NULL)
539 return (*dynamic_element(&_sidno_to_sid, sidno - 1, Node **))->sid;
551 if (sid_lock != NULL)
553 rpl_sidno
ret= *dynamic_element(&_sorted, n, rpl_sidno *);
564 if (sid_lock != NULL)
566 return _sidno_to_sid.elements;
588 enum_return_status add_node(rpl_sidno sidno,
const rpl_sid &sid);
613 extern Sid_map *global_sid_map;
695 DBUG_ENTER(
"Mutex_cond_array::wait");
696 Mutex_cond *mutex_cond= get_mutex_cond(n);
707 #endif // ifndef MYSQL_CLIENT
712 return array.elements - 1;
733 inline Mutex_cond *get_mutex_cond(
int n)
const
737 Mutex_cond *
ret= *dynamic_element(&array, n, Mutex_cond **);
772 static bool is_valid(
const char *text);
798 enum_return_status
parse(
Sid_map *sid_map,
const char *text);
815 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", buf));
871 Gtid_set(
Sid_map *sid_map,
const char *text, enum_return_status *status,
895 enum_return_status
_add_gtid(rpl_sidno sidno, rpl_gno gno)
897 DBUG_ENTER(
"Gtid_set::_add_gtid(sidno, gno)");
899 Free_intervals_lock lock(
this);
900 enum_return_status
ret= add_gno_interval(&ivit, gno, gno + 1, &lock);
912 DBUG_ENTER(
"Gtid_set::_remove_gtid(rpl_sidno, rpl_gno)");
916 Free_intervals_lock lock(
this);
917 enum_return_status
ret= remove_gno_interval(&ivit, gno, gno + 1, &lock);
980 enum_return_status
add_gtid_text(
const char *text,
bool *anonymous= NULL);
993 size_t *actual_length= NULL);
1004 return intervals.elements;
1050 DBUG_ASSERT(sidno >= 1);
1054 return ivit.
get() != NULL;
1060 static bool is_valid(
const char *text);
1077 printf(
"%s\n", str);
1089 DBUG_PRINT(
"info", (
"%s%s'%s'", text, *text ?
": " :
"", str));
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;
1204 if (sid_lock != NULL)
1206 add_interval_memory_lock_taken(n_intervals, intervals_param);
1207 if (sid_lock != NULL)
1233 DBUG_ASSERT(sidno >= 1 && sidno <= gtid_set->
get_max_sidno());
1234 init(gtid_set, sidno);
1238 {
p=
const_cast<Interval_p *
>(>id_set->free_intervals); }
1240 inline void init(Gtid_set_p gtid_set, rpl_sidno sidno)
1241 {
p= dynamic_element(>id_set->intervals, sidno - 1, Interval_p *); }
1245 DBUG_ASSERT(*
p != NULL);
1246 p=
const_cast<Interval_p *
>(&(*p)->next);
1249 inline Interval_p
get()
const {
return *
p; }
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)
1299 DBUG_ASSERT(
get() != NULL);
1300 Interval *
next= (*p)->next;
1301 gtid_set->put_free_interval(*
p);
1323 : gtid_set(gs), sidno(0), ivit(gs)
1325 if (gs->sid_lock != NULL)
1332 DBUG_ASSERT(gno > 0 && sidno > 0);
1336 if (gno == ivit.
get()->
end)
1360 inline void next_sidno()
1372 ivit.
init(gtid_set, sidno);
1374 }
while (iv == NULL);
1390 Const_interval_iterator ivit;
1412 struct Interval_chunk
1414 Interval_chunk *next;
1415 Interval intervals[1];
1418 static const int CHUNK_GROW_SIZE= 8;
1423 #ifdef NON_DISABLED_UNITTEST_GTID
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;
1440 int get_n_intervals(rpl_sidno sidno)
const
1442 Const_interval_iterator ivit(
this, sidno);
1444 while (ivit.get() != NULL)
1452 int get_n_intervals()
const
1454 if (sid_lock != NULL)
1458 for (rpl_sidno sidno= 1; sidno < max_sidno; sidno++)
1459 ret+= get_n_intervals(sidno);
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);
1513 class Free_intervals_lock
1517 Free_intervals_lock(
Gtid_set *_gtid_set)
1518 : gtid_set(_gtid_set), locked(false) {}
1520 void lock_if_not_locked()
1522 if (gtid_set->sid_lock && !locked)
1529 void unlock_if_locked()
1531 if (gtid_set->sid_lock && locked)
1538 ~Free_intervals_lock()
1546 void assert_free_intervals_locked()
1548 if (sid_lock != NULL)
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);
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);
1654 Interval *free_intervals;
1656 Interval_chunk *chunks;
1658 mutable int cached_string_length;
1660 mutable const String_format *cached_string_format;
1670 #ifdef FRIEND_OF_GTID_SET
1671 friend FRIEND_OF_GTID_SET;
1810 return sidno_to_hash.elements;
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++)
1827 if (sidno > max_sidno)
1829 HASH *hash= get_hash(sidno);
1830 bool printed_sid=
false;
1831 for (uint
i= 0;
i < hash->records;
i++)
1833 Node *node= (Node *)my_hash_element(hash,
i);
1834 DBUG_ASSERT(node != NULL);
1840 p+= sprintf(p,
":%lld#%lu", node->gno, node->owner);
1844 return (
int)(p - out);
1856 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++)
1858 HASH *hash= get_hash(sidno);
1859 if (hash->records > 0)
1861 hash->records * (1 + MAX_GNO_TEXT_LENGTH +
1862 1 + MAX_THREAD_ID_TEXT_LENGTH);
1874 while (node != NULL)
1876 if (node->owner == thd_id)
1892 DBUG_ASSERT(str != NULL);
1900 printf(
"%s\n", str);
1912 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", str));
1928 HASH *get_hash(rpl_sidno sidno)
const
1932 return *dynamic_element(&sidno_to_hash, sidno - 1,
HASH **);
1938 Node *get_node(
const HASH *hash, rpl_gno gno)
const
1941 return (Node *)my_hash_search(hash, (
const uchar *)&gno,
sizeof(rpl_gno));
1947 Node *get_node(
const Gtid >id)
const
1948 {
return get_node(get_hash(gtid.
sidno), gtid.
gno); };
1950 bool contains_gtid(
const Gtid >id)
const {
return get_node(gtid) != NULL; }
1963 : owned_gtids(og), sidno(1), hash(NULL), node_index(0), node(NULL)
1966 if (sidno <= max_sidno)
1967 hash= owned_gtids->get_hash(sidno);
1974 if (owned_gtids->sid_lock)
1978 while (sidno <= max_sidno)
1980 DBUG_ASSERT(hash != NULL);
1981 if (node_index < hash->records)
1983 node= (Node *)my_hash_element(hash, node_index);
1984 DBUG_ASSERT(node != NULL);
1994 if (sidno <= max_sidno)
1995 hash= owned_gtids->get_hash(sidno);
2021 rpl_sidno max_sidno;
2073 : sid_lock(_sid_lock),
2075 sid_locks(sid_lock),
2076 logged_gtids(sid_map, sid_lock),
2077 lost_gtids(sid_map, sid_lock),
2078 owned_gtids(sid_lock) {}
2110 DBUG_ENTER(
"Gtid_state::is_logged");
2123 #ifndef MYSQL_CLIENT
2171 #endif // ifndef MYSQL_CLIENT
2190 #ifndef MYSQL_CLIENT
2203 #endif // ifndef MYSQL_CLIENT
2204 #ifdef HAVE_NDB_BINLOG
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
2272 p+= sprintf(p,
"Logged GTIDs:\n");
2274 p+= sprintf(p,
"\nOwned GTIDs:\n");
2276 p+= sprintf(p,
"\nLost GTIDs:\n");
2278 return (
int)(p -
buf);
2304 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", str));
2309 #ifdef HAVE_NDB_BINLOG
2311 void lock_owned_sidnos(
const THD *thd);
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);
2343 rpl_sidno server_sidno;
2346 #ifdef FRIEND_OF_GTID_STATE
2347 friend FRIEND_OF_GTID_STATE;
2359 enum enum_group_type
2365 AUTOMATIC_GROUP= 0, GTID_GROUP, ANONYMOUS_GROUP, INVALID_GROUP, UNDEFINED_GROUP
2386 void set(rpl_sidno sidno, rpl_gno gno)
2387 {
type= GTID_GROUP; gtid.
sidno= sidno; gtid.
gno= gno; }
2389 void set(
const Gtid >id_param) {
set(gtid_param.sidno, gtid_param.gno); }
2393 type= AUTOMATIC_GROUP;
2398 if (
type == GTID_GROUP)
2399 type= UNDEFINED_GROUP;
2414 {
return type == GTID_GROUP && gtid.
equals(other_gtid); }
2415 #ifndef MYSQL_CLIENT
2422 enum_return_status
parse(
Sid_map *sid_map,
const char *text);
2426 static enum_group_type
get_type(
const char *text);
2456 char buf[MAX_TEXT_LENGTH + 1];
2458 printf(
"%s\n", buf);
2468 char buf[MAX_TEXT_LENGTH + 1];
2470 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", buf));
2528 EXTEND_EXISTING_GROUP, APPEND_NEW_GROUP, ERROR
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
2543 #endif // ifdef NON_DISABLED_GTID
2544 #ifndef MYSQL_CLIENT
2562 #endif // ifndef MYSQL_CLIENT
2589 s += sprintf(s,
"%d groups = {\n", n_groups);
2590 for (
int i= 0;
i < n_groups;
i++)
2596 s += sprintf(s,
" %s:%lld [offset %lld] %s\n",
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");
2631 printf(
"%s\n", str);
2643 DBUG_PRINT(
"info", (
"%s%s%s", text, *text ?
": " :
"", str));
2657 return dynamic_element(&groups, index,
Cached_group *);
2682 BINLOG_ERROR((
"Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0)));
2703 write_to_log_prepare(
Group_cache *trx_group_cache,
2704 rpl_binlog_pos offset_after_last_statement,
2708 #ifdef FRIEND_OF_GROUP_CACHE
2709 friend FRIEND_OF_GROUP_CACHE;
2717 enum enum_gtid_statement_status
2720 GTID_STATEMENT_EXECUTE,
2722 GTID_STATEMENT_CANCEL,
2731 #ifndef MYSQL_CLIENT
2743 enum_gtid_statement_status
2754 enum_gtid_statement_status gtid_pre_statement_checks(
const THD *thd);
2762 void gtid_post_statement_checks(THD *thd);
2768 int gtid_rollback(THD *thd);
2770 int gtid_acquire_ownership_single(THD *thd);
2771 #ifdef HAVE_NDB_BINLOG
2772 int gtid_acquire_ownership_multiple(THD *thd);
2775 #endif // ifndef MYSQL_CLIENT