My Project
|
00001 /* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 00002 00003 This program is free software; you can redistribute it and/or 00004 modify it under the terms of the GNU General Public License as 00005 published by the Free Software Foundation; version 2 of the 00006 License. 00007 00008 This program is distributed in the hope that it will be useful, but 00009 WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00016 02110-1301 USA */ 00017 00018 00019 #ifndef RPL_GTID_H_INCLUDED 00020 #define RPL_GTID_H_INCLUDED 00021 00022 00023 #include <m_string.h> 00024 #include <mysqld_error.h> 00025 #include <my_global.h> 00026 #ifdef MYSQL_SERVER 00027 #include <mysqld.h> 00028 #endif 00029 00040 #ifdef MYSQL_CLIENT 00041 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) error MYSQLBINLOG_ERROR 00042 #else 00043 #define BINLOG_ERROR(MYSQLBINLOG_ERROR, SERVER_ERROR) my_error SERVER_ERROR 00044 #endif 00045 00046 00047 #include "hash.h" 00048 #include "lf.h" 00049 #include "my_atomic.h" 00050 00055 #define SKIP_WHITESPACE() while (my_isspace(&my_charset_utf8_general_ci, *s)) s++ 00056 /* 00057 This macro must be used to filter out parts of the code that 00058 is not used now but may be useful in future. In other words, 00059 we want to keep such code until we make up our minds on whether 00060 it should be removed or not. 00061 */ 00062 #undef NON_DISABLED_GTID 00063 00064 /* 00065 This macro must be used to filter out parts of the code that 00066 is not used now but we are not sure if there is a bug around 00067 them. In other words, we want to keep such code until we have 00068 time to investigate it. 00069 */ 00070 #undef NON_ERROR_GTID 00071 00072 #ifndef MYSQL_CLIENT 00073 class String; 00074 class THD; 00075 #endif // ifndef MYSQL_CLIENT 00076 00077 00079 typedef int32 rpl_sidno; 00081 typedef int64 rpl_gno; 00083 typedef int64 rpl_binlog_pos; 00084 00085 00102 enum enum_return_status 00103 { 00105 RETURN_STATUS_OK= 0, 00107 RETURN_STATUS_UNREPORTED_ERROR= 1, 00109 RETURN_STATUS_REPORTED_ERROR= 2 00110 }; 00111 00129 #ifdef DBUG_OFF 00130 #define __CHECK_RETURN_STATUS(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED) 00131 #else 00132 extern void check_return_status(enum_return_status status, 00133 const char *action, const char *status_name, 00134 int allow_unreported); 00135 #define __CHECK_RETURN_STATUS(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED) \ 00136 check_return_status(STATUS, ACTION, STATUS_NAME, ALLOW_UNREPORTED); 00137 #endif 00138 00143 #define __PROPAGATE_ERROR(STATUS, RETURN_VALUE, ALLOW_UNREPORTED) \ 00144 do \ 00145 { \ 00146 enum_return_status __propagate_error_status= STATUS; \ 00147 if (__propagate_error_status != RETURN_STATUS_OK) { \ 00148 __CHECK_RETURN_STATUS(__propagate_error_status, "Propagating", \ 00149 #STATUS, ALLOW_UNREPORTED); \ 00150 DBUG_RETURN(RETURN_VALUE); \ 00151 } \ 00152 } while (0) 00153 00154 #define __RETURN_STATUS(STATUS, ALLOW_UNREPORTED) \ 00155 do \ 00156 { \ 00157 enum_return_status __return_status_status= STATUS; \ 00158 __CHECK_RETURN_STATUS(__return_status_status, "Returning", \ 00159 #STATUS, ALLOW_UNREPORTED); \ 00160 DBUG_RETURN(__return_status_status); \ 00161 } while (0) 00162 00166 #define PROPAGATE_ERROR(STATUS) \ 00167 __PROPAGATE_ERROR(STATUS, __propagate_error_status, true) 00168 00173 #define PROPAGATE_REPORTED_ERROR(STATUS) \ 00174 __PROPAGATE_ERROR(STATUS, __propagate_error_status, false) 00175 00180 #define PROPAGATE_REPORTED_ERROR_INT(STATUS) \ 00181 __PROPAGATE_ERROR(STATUS, 1, false) 00182 00186 #define RETURN_STATUS(STATUS) __RETURN_STATUS(STATUS, true) 00187 00192 #define RETURN_REPORTED_STATUS(STATUS) __RETURN_STATUS(STATUS, false) 00193 00194 #define RETURN_OK DBUG_RETURN(RETURN_STATUS_OK) 00195 00196 #define RETURN_REPORTED_ERROR RETURN_STATUS(RETURN_STATUS_REPORTED_ERROR) 00197 00198 #define RETURN_UNREPORTED_ERROR RETURN_STATUS(RETURN_STATUS_UNREPORTED_ERROR) 00199 00200 00202 const rpl_gno MAX_GNO= LONGLONG_MAX; 00204 const int MAX_GNO_TEXT_LENGTH= 19; 00206 const int MAX_THREAD_ID_TEXT_LENGTH= 19; 00207 00208 00217 rpl_gno parse_gno(const char **s); 00225 int format_gno(char *s, rpl_gno gno); 00226 00227 00234 struct Uuid 00235 { 00241 enum_return_status parse(const char *string); 00243 void clear() { memset(bytes, 0, BYTE_LENGTH); } 00245 void copy_from(const uchar *data) { memcpy(bytes, data, BYTE_LENGTH); } 00247 void copy_from(const Uuid &data) { copy_from(data.bytes); } 00249 void copy_to(uchar *data) const { memcpy(data, bytes, BYTE_LENGTH); } 00251 bool equals(const Uuid &other) const 00252 { return memcmp(bytes, other.bytes, BYTE_LENGTH) == 0; } 00259 size_t to_string(char *buf) const; 00261 static size_t to_string(const uchar* bytes_arg, char *buf); 00262 #ifndef DBUG_OFF 00263 00264 void print() const 00265 { 00266 char buf[TEXT_LENGTH + 1]; 00267 to_string(buf); 00268 printf("%s\n", buf); 00269 } 00270 #endif 00271 00272 void dbug_print(const char *text= "") const 00273 { 00274 #ifndef DBUG_OFF 00275 char buf[TEXT_LENGTH + 1]; 00276 to_string(buf); 00277 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf)); 00278 #endif 00279 } 00284 static bool is_valid(const char *string); 00286 static const size_t TEXT_LENGTH= 36; 00288 static const size_t BYTE_LENGTH= 16; 00290 static const size_t BIT_LENGTH= 128; 00292 uchar bytes[BYTE_LENGTH]; 00293 private: 00294 static const int NUMBER_OF_SECTIONS= 5; 00295 static const int bytes_per_section[NUMBER_OF_SECTIONS]; 00296 static const int hex_to_byte[256]; 00297 }; 00298 00299 00300 typedef Uuid rpl_sid; 00301 00302 00317 class Checkable_rwlock 00318 { 00319 public: 00321 Checkable_rwlock() 00322 { 00323 #ifndef DBUG_OFF 00324 my_atomic_rwlock_init(&atomic_lock); 00325 lock_state= 0; 00326 #else 00327 is_write_lock= false; 00328 #endif 00329 #ifdef MYSQL_SERVER 00330 mysql_rwlock_init(key_rwlock_global_sid_lock, &rwlock); 00331 #else 00332 mysql_rwlock_init(0, &rwlock); 00333 #endif 00334 } 00336 ~Checkable_rwlock() 00337 { 00338 #ifndef DBUG_OFF 00339 my_atomic_rwlock_destroy(&atomic_lock); 00340 #endif 00341 mysql_rwlock_destroy(&rwlock); 00342 } 00343 00345 inline void rdlock() 00346 { 00347 mysql_rwlock_rdlock(&rwlock); 00348 assert_no_wrlock(); 00349 #ifndef DBUG_OFF 00350 my_atomic_rwlock_wrlock(&atomic_lock); 00351 my_atomic_add32(&lock_state, 1); 00352 my_atomic_rwlock_wrunlock(&atomic_lock); 00353 #endif 00354 } 00356 inline void wrlock() 00357 { 00358 mysql_rwlock_wrlock(&rwlock); 00359 assert_no_lock(); 00360 #ifndef DBUG_OFF 00361 my_atomic_rwlock_wrlock(&atomic_lock); 00362 my_atomic_store32(&lock_state, -1); 00363 my_atomic_rwlock_wrunlock(&atomic_lock); 00364 #else 00365 is_write_lock= true; 00366 #endif 00367 } 00369 inline void unlock() 00370 { 00371 assert_some_lock(); 00372 #ifndef DBUG_OFF 00373 my_atomic_rwlock_wrlock(&atomic_lock); 00374 int val= my_atomic_load32(&lock_state); 00375 if (val > 0) 00376 my_atomic_add32(&lock_state, -1); 00377 else if (val == -1) 00378 my_atomic_store32(&lock_state, 0); 00379 else 00380 DBUG_ASSERT(0); 00381 my_atomic_rwlock_wrunlock(&atomic_lock); 00382 #else 00383 is_write_lock= false; 00384 #endif 00385 mysql_rwlock_unlock(&rwlock); 00386 } 00391 inline bool is_wrlock() 00392 { 00393 assert_some_lock(); 00394 #ifndef DBUG_OFF 00395 return get_state() == -1; 00396 #else 00397 return is_write_lock; 00398 #endif 00399 } 00400 00402 inline void assert_some_lock() const 00403 { DBUG_ASSERT(get_state() != 0); } 00405 inline void assert_some_rdlock() const 00406 { DBUG_ASSERT(get_state() > 0); } 00408 inline void assert_some_wrlock() const 00409 { DBUG_ASSERT(get_state() == -1); } 00411 inline void assert_no_wrlock() const 00412 { DBUG_ASSERT(get_state() >= 0); } 00414 inline void assert_no_rdlock() const 00415 { DBUG_ASSERT(get_state() <= 0); } 00417 inline void assert_no_lock() const 00418 { DBUG_ASSERT(get_state() == 0); } 00419 00420 private: 00421 #ifndef DBUG_OFF 00422 00428 volatile int32 lock_state; 00430 mutable my_atomic_rwlock_t atomic_lock; 00432 inline int32 get_state() const 00433 { 00434 int32 ret; 00435 my_atomic_rwlock_rdlock(&atomic_lock); 00436 ret= my_atomic_load32(const_cast<volatile int32*>(&lock_state)); 00437 my_atomic_rwlock_rdunlock(&atomic_lock); 00438 return ret; 00439 } 00440 #else 00441 bool is_write_lock; 00442 #endif 00443 00444 mysql_rwlock_t rwlock; 00445 }; 00446 00447 00449 extern Checkable_rwlock *global_sid_lock; 00450 00451 00467 class Sid_map 00468 { 00469 public: 00476 Sid_map(Checkable_rwlock *sid_lock); 00478 ~Sid_map(); 00479 #ifdef NON_DISABLED_GTID 00480 00485 enum_return_status clear(); 00486 #endif 00487 00500 rpl_sidno add_sid(const rpl_sid &sid); 00511 rpl_sidno sid_to_sidno(const rpl_sid &sid) const 00512 { 00513 if (sid_lock != NULL) 00514 sid_lock->assert_some_lock(); 00515 Node *node= (Node *)my_hash_search(&_sid_to_sidno, sid.bytes, 00516 rpl_sid::BYTE_LENGTH); 00517 if (node == NULL) 00518 return 0; 00519 return node->sidno; 00520 } 00534 const rpl_sid &sidno_to_sid(rpl_sidno sidno) const 00535 { 00536 if (sid_lock != NULL) 00537 sid_lock->assert_some_lock(); 00538 DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno()); 00539 return (*dynamic_element(&_sidno_to_sid, sidno - 1, Node **))->sid; 00540 } 00549 rpl_sidno get_sorted_sidno(rpl_sidno n) const 00550 { 00551 if (sid_lock != NULL) 00552 sid_lock->assert_some_lock(); 00553 rpl_sidno ret= *dynamic_element(&_sorted, n, rpl_sidno *); 00554 return ret; 00555 } 00562 rpl_sidno get_max_sidno() const 00563 { 00564 if (sid_lock != NULL) 00565 sid_lock->assert_some_lock(); 00566 return _sidno_to_sid.elements; 00567 } 00568 00569 private: 00571 struct Node 00572 { 00573 rpl_sidno sidno; 00574 rpl_sid sid; 00575 }; 00576 00588 enum_return_status add_node(rpl_sidno sidno, const rpl_sid &sid); 00589 00591 mutable Checkable_rwlock *sid_lock; 00592 00597 DYNAMIC_ARRAY _sidno_to_sid; 00602 HASH _sid_to_sidno; 00609 DYNAMIC_ARRAY _sorted; 00610 }; 00611 00612 00613 extern Sid_map *global_sid_map; 00614 00615 00636 class Mutex_cond_array 00637 { 00638 public: 00645 Mutex_cond_array(Checkable_rwlock *global_lock); 00647 ~Mutex_cond_array(); 00649 inline void lock(int n) const 00650 { 00651 assert_not_owner(n); 00652 mysql_mutex_lock(&get_mutex_cond(n)->mutex); 00653 } 00655 inline void unlock(int n) const 00656 { 00657 assert_owner(n); 00658 mysql_mutex_unlock(&get_mutex_cond(n)->mutex); 00659 } 00661 inline void broadcast(int n) const 00662 { 00663 mysql_cond_broadcast(&get_mutex_cond(n)->cond); 00664 } 00669 inline void assert_owner(int n) const 00670 { 00671 #ifndef DBUG_OFF 00672 mysql_mutex_assert_owner(&get_mutex_cond(n)->mutex); 00673 #endif 00674 } 00679 inline void assert_not_owner(int n) const 00680 { 00681 #ifndef DBUG_OFF 00682 mysql_mutex_assert_not_owner(&get_mutex_cond(n)->mutex); 00683 #endif 00684 } 00693 inline void wait(int n) const 00694 { 00695 DBUG_ENTER("Mutex_cond_array::wait"); 00696 Mutex_cond *mutex_cond= get_mutex_cond(n); 00697 global_lock->unlock(); 00698 mysql_mutex_assert_owner(&mutex_cond->mutex); 00699 mysql_cond_wait(&mutex_cond->cond, &mutex_cond->mutex); 00700 mysql_mutex_assert_owner(&mutex_cond->mutex); 00701 DBUG_VOID_RETURN; 00702 } 00703 #ifndef MYSQL_CLIENT 00704 00705 void enter_cond(THD *thd, int n, PSI_stage_info *stage, 00706 PSI_stage_info *old_stage) const; 00707 #endif // ifndef MYSQL_CLIENT 00708 00709 inline int get_max_index() const 00710 { 00711 global_lock->assert_some_lock(); 00712 return array.elements - 1; 00713 } 00724 enum_return_status ensure_index(int n); 00725 private: 00727 struct Mutex_cond 00728 { 00729 mysql_mutex_t mutex; 00730 mysql_cond_t cond; 00731 }; 00733 inline Mutex_cond *get_mutex_cond(int n) const 00734 { 00735 global_lock->assert_some_lock(); 00736 DBUG_ASSERT(n <= get_max_index()); 00737 Mutex_cond *ret= *dynamic_element(&array, n, Mutex_cond **); 00738 DBUG_ASSERT(ret); 00739 return ret; 00740 } 00742 mutable Checkable_rwlock *global_lock; 00743 DYNAMIC_ARRAY array; 00744 }; 00745 00746 00754 struct Gtid 00755 { 00757 rpl_sidno sidno; 00759 rpl_gno gno; 00760 00762 void clear() { sidno= 0; gno= 0; } 00763 // Set both components to input values. 00764 void set(rpl_sidno sno, rpl_gno gtidno) { sidno= sno; gno= gtidno; } 00765 // check if both components are zero or not. 00766 bool empty() const { return (sidno == 0) && (gno == 0); } 00771 static const int MAX_TEXT_LENGTH= Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH; 00776 static bool is_valid(const char *text); 00784 int to_string(const rpl_sid &sid, char *buf) const; 00792 int to_string(const Sid_map *sid_map, char *buf) const; 00794 bool equals(const Gtid &other) const 00795 { return sidno == other.sidno && gno == other.gno; } 00802 enum_return_status parse(Sid_map *sid_map, const char *text); 00803 00804 #ifndef DBUG_OFF 00805 00806 void print(const Sid_map *sid_map) const 00807 { 00808 char buf[MAX_TEXT_LENGTH + 1]; 00809 to_string(sid_map, buf); 00810 printf("%s\n", buf); 00811 } 00812 #endif 00813 00814 void dbug_print(const Sid_map *sid_map, const char *text= "") const 00815 { 00816 #ifndef DBUG_OFF 00817 char buf[MAX_TEXT_LENGTH + 1]; 00818 to_string(sid_map, buf); 00819 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf)); 00820 #endif 00821 } 00822 }; 00823 00824 00846 class Gtid_set 00847 { 00848 public: 00858 Gtid_set(Sid_map *sid_map, Checkable_rwlock *sid_lock= NULL); 00875 Gtid_set(Sid_map *sid_map, const char *text, enum_return_status *status, 00876 Checkable_rwlock *sid_lock= NULL); 00877 private: 00879 void init(); 00880 public: 00882 ~Gtid_set(); 00889 void clear(); 00899 enum_return_status _add_gtid(rpl_sidno sidno, rpl_gno gno) 00900 { 00901 DBUG_ENTER("Gtid_set::_add_gtid(sidno, gno)"); 00902 Interval_iterator ivit(this, sidno); 00903 Free_intervals_lock lock(this); 00904 enum_return_status ret= add_gno_interval(&ivit, gno, gno + 1, &lock); 00905 DBUG_RETURN(ret); 00906 } 00914 enum_return_status _remove_gtid(rpl_sidno sidno, rpl_gno gno) 00915 { 00916 DBUG_ENTER("Gtid_set::_remove_gtid(rpl_sidno, rpl_gno)"); 00917 if (sidno <= get_max_sidno()) 00918 { 00919 Interval_iterator ivit(this, sidno); 00920 Free_intervals_lock lock(this); 00921 enum_return_status ret= remove_gno_interval(&ivit, gno, gno + 1, &lock); 00922 DBUG_RETURN(ret); 00923 } 00924 RETURN_OK; 00925 } 00934 enum_return_status _add_gtid(const Gtid >id) 00935 { return _add_gtid(gtid.sidno, gtid.gno); } 00942 enum_return_status _remove_gtid(const Gtid >id) 00943 { 00944 return _remove_gtid(gtid.sidno, gtid.gno); 00945 } 00958 enum_return_status add_gtid_set(const Gtid_set *other); 00965 enum_return_status remove_gtid_set(const Gtid_set *other); 00994 enum_return_status add_gtid_text(const char *text, bool *anonymous= NULL); 01006 enum_return_status add_gtid_encoding(const uchar *encoded, size_t length, 01007 size_t *actual_length= NULL); 01009 bool contains_gtid(rpl_sidno sidno, rpl_gno gno) const; 01011 bool contains_gtid(const Gtid >id) const 01012 { return contains_gtid(gtid.sidno, gtid.gno); } 01014 rpl_sidno get_max_sidno() const 01015 { 01016 if (sid_lock) 01017 sid_lock->assert_some_lock(); 01018 return intervals.elements; 01019 } 01032 enum_return_status ensure_sidno(rpl_sidno sidno); 01034 bool is_subset(const Gtid_set *super) const; 01035 01051 bool is_subset_for_sid(const Gtid_set *super, rpl_sidno superset_sidno, 01052 rpl_sidno subset_sidno) const; 01055 bool is_intersection_nonempty(const Gtid_set *other) const; 01063 enum_return_status intersection(const Gtid_set *other, Gtid_set *result); 01065 bool is_empty() const 01066 { 01067 Gtid_iterator git(this); 01068 return git.get().sidno == 0; 01069 } 01080 bool contains_sidno(rpl_sidno sidno) const 01081 { 01082 DBUG_ASSERT(sidno >= 1); 01083 if (sidno > get_max_sidno()) 01084 return false; 01085 Const_interval_iterator ivit(this, sidno); 01086 return ivit.get() != NULL; 01087 } 01092 static bool is_valid(const char *text); 01097 char *to_string() const 01098 { 01099 char *str= (char *)my_malloc(get_string_length() + 1, MYF(MY_WME)); 01100 if (str != NULL) 01101 to_string(str); 01102 return str; 01103 } 01104 #ifndef DBUG_OFF 01105 01106 void print() const 01107 { 01108 char *str= to_string(); 01109 printf("%s\n", str); 01110 my_free(str); 01111 } 01112 #endif 01113 01117 void dbug_print(const char *text= "") const 01118 { 01119 #ifndef DBUG_OFF 01120 char *str= to_string(); 01121 DBUG_PRINT("info", ("%s%s'%s'", text, *text ? ": " : "", str)); 01122 my_free(str); 01123 #endif 01124 } 01125 01130 struct String_format 01131 { 01133 const char *begin; 01135 const char *end; 01137 const char *sid_gno_separator; 01139 const char *gno_start_end_separator; 01141 const char *gno_gno_separator; 01143 const char *gno_sid_separator; 01145 const char *empty_set_string; 01147 const int begin_length; 01148 const int end_length; 01149 const int sid_gno_separator_length; 01150 const int gno_start_end_separator_length; 01151 const int gno_gno_separator_length; 01152 const int gno_sid_separator_length; 01153 const int empty_set_string_length; 01154 }; 01165 int get_string_length(const String_format *string_format= NULL) const; 01175 int to_string(char *buf, const String_format *string_format= NULL) const; 01176 01184 int to_string(char **buf, const String_format *string_format= NULL) const; 01185 01190 static const String_format default_string_format; 01195 static const String_format sql_string_format; 01200 static const String_format commented_string_format; 01201 01203 Sid_map *get_sid_map() const { return sid_map; } 01204 01209 struct Interval 01210 { 01211 public: 01213 rpl_gno start; 01215 rpl_gno end; 01217 bool equals(const Interval &other) const 01218 { 01219 return start == other.start && end == other.end; 01220 } 01222 Interval *next; 01223 }; 01224 01234 void add_interval_memory(int n_intervals, Interval *intervals_param) 01235 { 01236 if (sid_lock != NULL) 01237 mysql_mutex_lock(&free_intervals_mutex); 01238 add_interval_memory_lock_taken(n_intervals, intervals_param); 01239 if (sid_lock != NULL) 01240 mysql_mutex_unlock(&free_intervals_mutex); 01241 } 01242 01243 01254 template<typename Gtid_set_p, typename Interval_p> class Interval_iterator_base 01255 { 01256 public: 01263 Interval_iterator_base(Gtid_set_p gtid_set, rpl_sidno sidno) 01264 { 01265 DBUG_ASSERT(sidno >= 1 && sidno <= gtid_set->get_max_sidno()); 01266 init(gtid_set, sidno); 01267 } 01269 Interval_iterator_base(Gtid_set_p gtid_set) 01270 { p= const_cast<Interval_p *>(>id_set->free_intervals); } 01272 inline void init(Gtid_set_p gtid_set, rpl_sidno sidno) 01273 { p= dynamic_element(>id_set->intervals, sidno - 1, Interval_p *); } 01275 inline void next() 01276 { 01277 DBUG_ASSERT(*p != NULL); 01278 p= const_cast<Interval_p *>(&(*p)->next); 01279 } 01281 inline Interval_p get() const { return *p; } 01282 protected: 01288 Interval_p *p; 01289 }; 01290 01294 class Const_interval_iterator 01295 : public Interval_iterator_base<const Gtid_set *, const Interval *> 01296 { 01297 public: 01299 Const_interval_iterator(const Gtid_set *gtid_set, rpl_sidno sidno) 01300 : Interval_iterator_base<const Gtid_set *, const Interval *>(gtid_set, sidno) {} 01302 Const_interval_iterator(const Gtid_set *gtid_set) 01303 : Interval_iterator_base<const Gtid_set *, const Interval *>(gtid_set) {} 01304 }; 01305 01310 class Interval_iterator 01311 : public Interval_iterator_base<Gtid_set *, Interval *> 01312 { 01313 public: 01315 Interval_iterator(Gtid_set *gtid_set, rpl_sidno sidno) 01316 : Interval_iterator_base<Gtid_set *, Interval *>(gtid_set, sidno) {} 01318 Interval_iterator(Gtid_set *gtid_set) 01319 : Interval_iterator_base<Gtid_set *, Interval *>(gtid_set) {} 01320 private: 01325 inline void set(Interval *iv) { *p= iv; } 01327 inline void insert(Interval *iv) { iv->next= *p; set(iv); } 01329 inline void remove(Gtid_set *gtid_set) 01330 { 01331 DBUG_ASSERT(get() != NULL); 01332 Interval *next= (*p)->next; 01333 gtid_set->put_free_interval(*p); 01334 set(next); 01335 } 01343 friend class Gtid_set; 01344 }; 01345 01346 01351 class Gtid_iterator 01352 { 01353 public: 01354 Gtid_iterator(const Gtid_set *gs) 01355 : gtid_set(gs), sidno(0), ivit(gs) 01356 { 01357 if (gs->sid_lock != NULL) 01358 gs->sid_lock->assert_some_wrlock(); 01359 next_sidno(); 01360 } 01362 inline void next() 01363 { 01364 DBUG_ASSERT(gno > 0 && sidno > 0); 01365 // go to next group in current interval 01366 gno++; 01367 // end of interval? then go to next interval for this sidno 01368 if (gno == ivit.get()->end) 01369 { 01370 ivit.next(); 01371 const Interval *iv= ivit.get(); 01372 // last interval for this sidno? then go to next sidno 01373 if (iv == NULL) 01374 { 01375 next_sidno(); 01376 // last sidno? then don't try more 01377 if (sidno == 0) 01378 return; 01379 iv= ivit.get(); 01380 } 01381 gno= iv->start; 01382 } 01383 } 01385 inline Gtid get() const 01386 { 01387 Gtid ret= { sidno, gno }; 01388 return ret; 01389 } 01390 private: 01392 inline void next_sidno() 01393 { 01394 const Interval *iv; 01395 do 01396 { 01397 sidno++; 01398 if (sidno > gtid_set->get_max_sidno()) 01399 { 01400 sidno= 0; 01401 gno= 0; 01402 return; 01403 } 01404 ivit.init(gtid_set, sidno); 01405 iv= ivit.get(); 01406 } while (iv == NULL); 01407 gno= iv->start; 01408 } 01410 const Gtid_set *gtid_set; 01415 rpl_sidno sidno; 01420 rpl_gno gno; 01422 Const_interval_iterator ivit; 01423 }; 01424 01425 public: 01426 01430 void encode(uchar *buf) const; 01435 size_t get_encoded_length() const; 01436 01437 private: 01444 struct Interval_chunk 01445 { 01446 Interval_chunk *next; 01447 Interval intervals[1]; 01448 }; 01450 static const int CHUNK_GROW_SIZE= 8; 01451 01452 /* 01453 Functions sidno_equals() and equals() are only used by unitests 01454 */ 01455 #ifdef NON_DISABLED_UNITTEST_GTID 01456 01465 bool sidno_equals(rpl_sidno sidno, 01466 const Gtid_set *other, rpl_sidno other_sidno) const; 01468 bool equals(const Gtid_set *other) const; 01469 #endif 01470 01472 int get_n_intervals(rpl_sidno sidno) const 01473 { 01474 Const_interval_iterator ivit(this, sidno); 01475 int ret= 0; 01476 while (ivit.get() != NULL) 01477 { 01478 ret++; 01479 ivit.next(); 01480 } 01481 return ret; 01482 } 01484 int get_n_intervals() const 01485 { 01486 if (sid_lock != NULL) 01487 sid_lock->assert_some_wrlock(); 01488 rpl_sidno max_sidno= get_max_sidno(); 01489 int ret= 0; 01490 for (rpl_sidno sidno= 1; sidno < max_sidno; sidno++) 01491 ret+= get_n_intervals(sidno); 01492 return ret; 01493 } 01501 enum_return_status create_new_chunk(int size); 01512 enum_return_status get_free_interval(Interval **out); 01517 void put_free_interval(Interval *iv); 01523 void add_interval_memory_lock_taken(int n_ivs, Interval *ivs); 01524 01526 mutable Checkable_rwlock *sid_lock; 01531 mysql_mutex_t free_intervals_mutex; 01545 class Free_intervals_lock 01546 { 01547 public: 01549 Free_intervals_lock(Gtid_set *_gtid_set) 01550 : gtid_set(_gtid_set), locked(false) {} 01552 void lock_if_not_locked() 01553 { 01554 if (gtid_set->sid_lock && !locked) 01555 { 01556 mysql_mutex_lock(>id_set->free_intervals_mutex); 01557 locked= true; 01558 } 01559 } 01561 void unlock_if_locked() 01562 { 01563 if (gtid_set->sid_lock && locked) 01564 { 01565 mysql_mutex_unlock(>id_set->free_intervals_mutex); 01566 locked= false; 01567 } 01568 } 01570 ~Free_intervals_lock() 01571 { 01572 unlock_if_locked(); 01573 } 01574 private: 01575 Gtid_set *gtid_set; 01576 bool locked; 01577 }; 01578 void assert_free_intervals_locked() 01579 { 01580 if (sid_lock != NULL) 01581 mysql_mutex_assert_owner(&free_intervals_mutex); 01582 } 01583 01603 enum_return_status add_gno_interval(Interval_iterator *ivitp, 01604 rpl_gno start, rpl_gno end, 01605 Free_intervals_lock *lock); 01628 enum_return_status remove_gno_interval(Interval_iterator *ivitp, 01629 rpl_gno start, rpl_gno end, 01630 Free_intervals_lock *lock); 01647 enum_return_status add_gno_intervals(rpl_sidno sidno, 01648 Const_interval_iterator ivit, 01649 Free_intervals_lock *lock); 01666 enum_return_status remove_gno_intervals(rpl_sidno sidno, 01667 Const_interval_iterator ivit, 01668 Free_intervals_lock *lock); 01669 01672 static bool is_interval_subset(Const_interval_iterator *sub, 01673 Const_interval_iterator *super); 01675 static bool is_interval_intersection_nonempty(Const_interval_iterator *ivit1, 01676 Const_interval_iterator *ivit2); 01677 01679 Sid_map *sid_map; 01684 DYNAMIC_ARRAY intervals; 01686 Interval *free_intervals; 01688 Interval_chunk *chunks; 01690 mutable int cached_string_length; 01692 mutable const String_format *cached_string_format; 01693 #ifndef DBUG_OFF 01694 01698 int n_chunks; 01699 #endif 01700 01702 #ifdef FRIEND_OF_GTID_SET 01703 friend FRIEND_OF_GTID_SET; 01704 #endif 01705 01706 friend class Gtid_set::Free_intervals_lock; 01707 }; 01708 01709 01730 struct Gtid_set_or_null 01731 { 01733 Gtid_set *gtid_set; 01735 bool is_non_null; 01737 inline Gtid_set *get_gtid_set() const 01738 { 01739 DBUG_ASSERT(!(is_non_null && gtid_set == NULL)); 01740 return is_non_null ? gtid_set : NULL; 01741 } 01747 Gtid_set *set_non_null(Sid_map *sm) 01748 { 01749 if (!is_non_null) 01750 { 01751 if (gtid_set == NULL) 01752 gtid_set= new Gtid_set(sm); 01753 else 01754 gtid_set->clear(); 01755 } 01756 is_non_null= (gtid_set != NULL); 01757 return gtid_set; 01758 } 01760 inline void set_null() { is_non_null= false; } 01761 }; 01762 01763 01779 class Owned_gtids 01780 { 01781 public: 01788 Owned_gtids(Checkable_rwlock *sid_lock); 01790 ~Owned_gtids(); 01798 enum_return_status add_gtid_owner(const Gtid >id, my_thread_id owner); 01806 my_thread_id get_owner(const Gtid >id) const; 01815 void remove_gtid(const Gtid >id); 01828 enum_return_status ensure_sidno(rpl_sidno sidno); 01831 bool is_intersection_nonempty(const Gtid_set *other) const; 01833 bool is_empty() const 01834 { 01835 Gtid_iterator git(this); 01836 return git.get().sidno == 0; 01837 } 01839 rpl_sidno get_max_sidno() const 01840 { 01841 sid_lock->assert_some_lock(); 01842 return sidno_to_hash.elements; 01843 } 01844 01851 int to_string(char *out) const 01852 { 01853 char *p= out; 01854 rpl_sidno max_sidno= get_max_sidno(); 01855 rpl_sidno sid_map_max_sidno= global_sid_map->get_max_sidno(); 01856 for (rpl_sidno sid_i= 0; sid_i < sid_map_max_sidno; sid_i++) 01857 { 01858 rpl_sidno sidno= global_sid_map->get_sorted_sidno(sid_i); 01859 if (sidno > max_sidno) 01860 continue; 01861 HASH *hash= get_hash(sidno); 01862 bool printed_sid= false; 01863 for (uint i= 0; i < hash->records; i++) 01864 { 01865 Node *node= (Node *)my_hash_element(hash, i); 01866 DBUG_ASSERT(node != NULL); 01867 if (!printed_sid) 01868 { 01869 p+= global_sid_map->sidno_to_sid(sidno).to_string(p); 01870 printed_sid= true; 01871 } 01872 p+= sprintf(p, ":%lld#%lu", node->gno, node->owner); 01873 } 01874 } 01875 *p= 0; 01876 return (int)(p - out); 01877 } 01878 01884 size_t get_max_string_length() const 01885 { 01886 rpl_sidno max_sidno= get_max_sidno(); 01887 size_t ret= 0; 01888 for (rpl_sidno sidno= 1; sidno <= max_sidno; sidno++) 01889 { 01890 HASH *hash= get_hash(sidno); 01891 if (hash->records > 0) 01892 ret+= rpl_sid::TEXT_LENGTH + 01893 hash->records * (1 + MAX_GNO_TEXT_LENGTH + 01894 1 + MAX_THREAD_ID_TEXT_LENGTH); 01895 } 01896 return 1 + ret; 01897 } 01898 01902 bool thread_owns_anything(my_thread_id thd_id) const 01903 { 01904 Gtid_iterator git(this); 01905 Node *node= git.get_node(); 01906 while (node != NULL) 01907 { 01908 if (node->owner == thd_id) 01909 return true; 01910 git.next(); 01911 node= git.get_node(); 01912 } 01913 return false; 01914 } 01915 01916 #ifndef DBUG_OFF 01917 01921 char *to_string() const 01922 { 01923 char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME)); 01924 DBUG_ASSERT(str != NULL); 01925 to_string(str); 01926 return str; 01927 } 01929 void print() const 01930 { 01931 char *str= to_string(); 01932 printf("%s\n", str); 01933 my_free(str); 01934 } 01935 #endif 01936 01940 void dbug_print(const char *text= "") const 01941 { 01942 #ifndef DBUG_OFF 01943 char *str= to_string(); 01944 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str)); 01945 my_free(str); 01946 #endif 01947 } 01948 private: 01950 struct Node 01951 { 01953 rpl_gno gno; 01955 my_thread_id owner; 01956 }; 01958 mutable Checkable_rwlock *sid_lock; 01960 HASH *get_hash(rpl_sidno sidno) const 01961 { 01962 DBUG_ASSERT(sidno >= 1 && sidno <= get_max_sidno()); 01963 sid_lock->assert_some_lock(); 01964 return *dynamic_element(&sidno_to_hash, sidno - 1, HASH **); 01965 } 01970 Node *get_node(const HASH *hash, rpl_gno gno) const 01971 { 01972 sid_lock->assert_some_lock(); 01973 return (Node *)my_hash_search(hash, (const uchar *)&gno, sizeof(rpl_gno)); 01974 } 01979 Node *get_node(const Gtid >id) const 01980 { return get_node(get_hash(gtid.sidno), gtid.gno); }; 01982 bool contains_gtid(const Gtid >id) const { return get_node(gtid) != NULL; } 01984 DYNAMIC_ARRAY sidno_to_hash; 01985 01986 public: 01991 class Gtid_iterator 01992 { 01993 public: 01994 Gtid_iterator(const Owned_gtids* og) 01995 : owned_gtids(og), sidno(1), hash(NULL), node_index(0), node(NULL) 01996 { 01997 max_sidno= owned_gtids->get_max_sidno(); 01998 if (sidno <= max_sidno) 01999 hash= owned_gtids->get_hash(sidno); 02000 next(); 02001 } 02003 inline void next() 02004 { 02005 #ifndef DBUG_OFF 02006 if (owned_gtids->sid_lock) 02007 owned_gtids->sid_lock->assert_some_wrlock(); 02008 #endif 02009 02010 while (sidno <= max_sidno) 02011 { 02012 DBUG_ASSERT(hash != NULL); 02013 if (node_index < hash->records) 02014 { 02015 node= (Node *)my_hash_element(hash, node_index); 02016 DBUG_ASSERT(node != NULL); 02017 // Jump to next node on next iteration. 02018 node_index++; 02019 return; 02020 } 02021 02022 node_index= 0; 02023 // hash is initialized on constructor or in previous iteration 02024 // for current SIDNO, so we must increment for next iteration. 02025 sidno++; 02026 if (sidno <= max_sidno) 02027 hash= owned_gtids->get_hash(sidno); 02028 } 02029 node= NULL; 02030 } 02032 inline Gtid get() const 02033 { 02034 Gtid ret= { 0, 0 }; 02035 if (node) 02036 { 02037 ret.sidno= sidno; 02038 ret.gno= node->gno; 02039 } 02040 return ret; 02041 } 02043 inline Node* get_node() const 02044 { 02045 return node; 02046 } 02047 private: 02049 const Owned_gtids *owned_gtids; 02051 rpl_sidno sidno; 02053 rpl_sidno max_sidno; 02055 HASH *hash; 02057 uint node_index; 02059 Node *node; 02060 }; 02061 }; 02062 02063 02094 class Gtid_state 02095 { 02096 public: 02104 Gtid_state(Checkable_rwlock *_sid_lock, Sid_map *_sid_map) 02105 : sid_lock(_sid_lock), 02106 sid_map(_sid_map), 02107 sid_locks(sid_lock), 02108 logged_gtids(sid_map, sid_lock), 02109 lost_gtids(sid_map, sid_lock), 02110 owned_gtids(sid_lock) {} 02123 int init(); 02131 void clear(); 02140 bool is_logged(const Gtid >id) const 02141 { 02142 DBUG_ENTER("Gtid_state::is_logged"); 02143 bool ret= logged_gtids.contains_gtid(gtid); 02144 DBUG_RETURN(ret); 02145 } 02153 my_thread_id get_owner(const Gtid >id) const 02154 { return owned_gtids.get_owner(gtid); } 02155 #ifndef MYSQL_CLIENT 02156 02165 enum_return_status acquire_ownership(THD *thd, const Gtid >id); 02178 enum_return_status update_on_flush(THD *thd); 02189 void update_on_commit(THD *thd); 02202 void update_on_rollback(THD *thd); 02203 #endif // ifndef MYSQL_CLIENT 02204 02212 rpl_gno get_automatic_gno(rpl_sidno sidno) const; 02214 void lock_sidno(rpl_sidno sidno) { sid_locks.lock(sidno); } 02216 void unlock_sidno(rpl_sidno sidno) { sid_locks.unlock(sidno); } 02218 void broadcast_sidno(rpl_sidno sidno) { sid_locks.broadcast(sidno); } 02220 void assert_sidno_lock_owner(rpl_sidno sidno) 02221 { sid_locks.assert_owner(sidno); } 02222 #ifndef MYSQL_CLIENT 02223 02234 void wait_for_gtid(THD *thd, const Gtid >id); 02235 #endif // ifndef MYSQL_CLIENT 02236 #ifdef HAVE_NDB_BINLOG 02237 02241 void lock_sidnos(const Gtid_set *set); 02246 void unlock_sidnos(const Gtid_set *set); 02251 void broadcast_sidnos(const Gtid_set *set); 02252 #endif // ifdef HAVE_NDB_BINLOG 02253 02267 enum_return_status ensure_sidno(); 02278 enum_return_status add_lost_gtids(const char *text); 02280 const Gtid_set *get_logged_gtids() const { return &logged_gtids; } 02282 const Gtid_set *get_lost_gtids() const { return &lost_gtids; } 02284 const Owned_gtids *get_owned_gtids() const { return &owned_gtids; } 02286 rpl_sidno get_server_sidno() const { return server_sidno; } 02288 const rpl_sid &get_server_sid() const 02289 { 02290 return global_sid_map->sidno_to_sid(server_sidno); 02291 } 02292 #ifndef DBUG_OFF 02293 02298 size_t get_max_string_length() const 02299 { 02300 return owned_gtids.get_max_string_length() + 02301 logged_gtids.get_string_length() + 02302 lost_gtids.get_string_length() + 02303 100; 02304 } 02306 int to_string(char *buf) const 02307 { 02308 char *p= buf; 02309 p+= sprintf(p, "Logged GTIDs:\n"); 02310 p+= logged_gtids.to_string(p); 02311 p+= sprintf(p, "\nOwned GTIDs:\n"); 02312 p+= owned_gtids.to_string(p); 02313 p+= sprintf(p, "\nLost GTIDs:\n"); 02314 p+= lost_gtids.to_string(p); 02315 return (int)(p - buf); 02316 } 02318 char *to_string() const 02319 { 02320 char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME)); 02321 to_string(str); 02322 return str; 02323 } 02325 void print() const 02326 { 02327 char *str= to_string(); 02328 printf("%s", str); 02329 my_free(str); 02330 } 02331 #endif 02332 02336 void dbug_print(const char *text= "") const 02337 { 02338 #ifndef DBUG_OFF 02339 sid_lock->assert_some_wrlock(); 02340 char *str= to_string(); 02341 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str)); 02342 my_free(str); 02343 #endif 02344 } 02345 private: 02346 #ifdef HAVE_NDB_BINLOG 02347 02348 void lock_owned_sidnos(const THD *thd); 02349 #endif 02350 02351 void unlock_owned_sidnos(const THD *thd); 02353 void broadcast_owned_sidnos(const THD *thd); 02361 void update_owned_gtids_impl(THD *thd, bool is_commit); 02362 02363 02365 mutable Checkable_rwlock *sid_lock; 02367 mutable Sid_map *sid_map; 02369 Mutex_cond_array sid_locks; 02371 Gtid_set logged_gtids; 02376 Gtid_set lost_gtids; 02378 Owned_gtids owned_gtids; 02380 rpl_sidno server_sidno; 02381 02383 #ifdef FRIEND_OF_GTID_STATE 02384 friend FRIEND_OF_GTID_STATE; 02385 #endif 02386 }; 02387 02388 02390 extern Gtid_state *gtid_state; 02391 02392 02396 enum enum_group_type 02397 { 02402 AUTOMATIC_GROUP= 0, GTID_GROUP, ANONYMOUS_GROUP, INVALID_GROUP, UNDEFINED_GROUP 02403 }; 02404 02405 02412 struct Gtid_specification 02413 { 02415 enum_group_type type; 02421 Gtid gtid; 02423 void set(rpl_sidno sidno, rpl_gno gno) 02424 { type= GTID_GROUP; gtid.sidno= sidno; gtid.gno= gno; } 02426 void set(const Gtid >id_param) { set(gtid_param.sidno, gtid_param.gno); } 02428 void set_anonymous() 02429 { type= ANONYMOUS_GROUP; gtid.sidno= 0; gtid.gno= 0; } 02431 void set_automatic() 02432 { 02433 type= AUTOMATIC_GROUP; 02434 } 02436 void set_undefined() 02437 { 02438 if (type == GTID_GROUP) 02439 type= UNDEFINED_GROUP; 02440 } 02442 void clear() { set(0, 0); } 02444 bool equals(const Gtid_specification &other) const 02445 { 02446 return (type == other.type && 02447 (type != GTID_GROUP || gtid.equals(other.gtid))); 02448 } 02453 bool equals(const Gtid &other_gtid) const 02454 { return type == GTID_GROUP && gtid.equals(other_gtid); } 02455 #ifndef MYSQL_CLIENT 02456 02462 enum_return_status parse(Sid_map *sid_map, const char *text); 02466 static enum_group_type get_type(const char *text); 02468 static bool is_valid(const char *text) 02469 { return Gtid_specification::get_type(text) != INVALID_GROUP; } 02470 #endif 02471 static const int MAX_TEXT_LENGTH= Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH; 02480 int to_string(const Sid_map *sid_map, char *buf) const; 02491 int to_string(const rpl_sid *sid, char *buf) const; 02492 #ifndef DBUG_OFF 02493 02494 void print() const 02495 { 02496 char buf[MAX_TEXT_LENGTH + 1]; 02497 to_string(global_sid_map, buf); 02498 printf("%s\n", buf); 02499 } 02500 #endif 02501 02505 void dbug_print(const char *text= "") const 02506 { 02507 #ifndef DBUG_OFF 02508 char buf[MAX_TEXT_LENGTH + 1]; 02509 to_string(global_sid_map, buf); 02510 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", buf)); 02511 #endif 02512 } 02513 }; 02514 02515 02524 struct Cached_group 02525 { 02527 Gtid_specification spec; 02532 rpl_binlog_pos binlog_offset; 02533 }; 02534 02535 02540 class Group_cache 02541 { 02542 public: 02544 Group_cache(); 02546 ~Group_cache(); 02548 void clear(); 02550 inline int get_n_groups() const { return groups.elements; } 02552 inline bool is_empty() const { return get_n_groups() == 0; } 02566 enum enum_add_group_status 02567 { 02568 EXTEND_EXISTING_GROUP, APPEND_NEW_GROUP, ERROR 02569 }; 02570 #ifndef MYSQL_CLIENT 02571 enum_add_group_status 02572 add_logged_group(const THD *thd, my_off_t binlog_offset); 02573 #endif // ifndef MYSQL_CLIENT 02574 #ifdef NON_DISABLED_GTID 02575 02582 enum_add_group_status add_empty_group(const Gtid >id); 02583 #endif // ifdef NON_DISABLED_GTID 02584 #ifndef MYSQL_CLIENT 02585 02589 enum_return_status write_to_gtid_state() const; 02601 enum_return_status generate_automatic_gno(THD *thd); 02602 #endif // ifndef MYSQL_CLIENT 02603 02610 bool contains_gtid(const Gtid >id) const; 02617 enum_return_status get_gtids(Gtid_set *gs) const; 02618 02619 #ifndef DBUG_OFF 02620 02624 size_t to_string(const Sid_map *sm, char *buf) const 02625 { 02626 int n_groups= get_n_groups(); 02627 char *s= buf; 02628 02629 s += sprintf(s, "%d groups = {\n", n_groups); 02630 for (int i= 0; i < n_groups; i++) 02631 { 02632 Cached_group *group= get_unsafe_pointer(i); 02633 char uuid[Uuid::TEXT_LENGTH + 1]= "[]"; 02634 if (group->spec.gtid.sidno) 02635 sm->sidno_to_sid(group->spec.gtid.sidno).to_string(uuid); 02636 s += sprintf(s, " %s:%lld [offset %lld] %s\n", 02637 uuid, group->spec.gtid.gno, group->binlog_offset, 02638 group->spec.type == GTID_GROUP ? "GTID" : 02639 group->spec.type == ANONYMOUS_GROUP ? "ANONYMOUS" : 02640 group->spec.type == AUTOMATIC_GROUP ? "AUTOMATIC" : 02641 "INVALID-GROUP-TYPE"); 02642 } 02643 sprintf(s, "}\n"); 02644 return s - buf; 02645 } 02650 size_t get_max_string_length() const 02651 { 02652 return (2 + Uuid::TEXT_LENGTH + 1 + MAX_GNO_TEXT_LENGTH + 4 + 2 + 02653 40 + 10 + 21 + 1 + 100/*margin*/) * get_n_groups() + 100/*margin*/; 02654 } 02660 char *to_string(const Sid_map *sm) const 02661 { 02662 char *str= (char *)my_malloc(get_max_string_length(), MYF(MY_WME)); 02663 if (str) 02664 to_string(sm, str); 02665 return str; 02666 } 02668 void print(const Sid_map *sm) const 02669 { 02670 char *str= to_string(sm); 02671 printf("%s\n", str); 02672 my_free(str); 02673 } 02674 #endif 02675 02679 void dbug_print(const Sid_map *sid_map, const char *text= "") const 02680 { 02681 #ifndef DBUG_OFF 02682 char *str= to_string(sid_map); 02683 DBUG_PRINT("info", ("%s%s%s", text, *text ? ": " : "", str)); 02684 my_free(str); 02685 #endif 02686 } 02687 02694 inline Cached_group *get_unsafe_pointer(int index) const 02695 { 02696 DBUG_ASSERT(index >= 0 && index < get_n_groups()); 02697 return dynamic_element(&groups, index, Cached_group *); 02698 } 02699 02700 private: 02702 DYNAMIC_ARRAY groups; 02703 02708 Cached_group *get_last_group() 02709 { 02710 int n_groups= get_n_groups(); 02711 return n_groups == 0 ? NULL : get_unsafe_pointer(n_groups - 1); 02712 } 02713 02718 Cached_group *allocate_group() 02719 { 02720 Cached_group *ret= (Cached_group *)alloc_dynamic(&groups); 02721 if (ret == NULL) 02722 BINLOG_ERROR(("Out of memory."), (ER_OUT_OF_RESOURCES, MYF(0))); 02723 return ret; 02724 } 02725 02733 enum_return_status add_group(const Cached_group *group); 02742 enum_return_status 02743 write_to_log_prepare(Group_cache *trx_group_cache, 02744 rpl_binlog_pos offset_after_last_statement, 02745 Cached_group **last_non_empty_group); 02746 02748 #ifdef FRIEND_OF_GROUP_CACHE 02749 friend FRIEND_OF_GROUP_CACHE; 02750 #endif 02751 }; 02752 02757 enum enum_gtid_statement_status 02758 { 02760 GTID_STATEMENT_EXECUTE, 02762 GTID_STATEMENT_CANCEL, 02767 GTID_STATEMENT_SKIP 02768 }; 02769 02770 02771 #ifndef MYSQL_CLIENT 02772 02783 enum_gtid_statement_status 02784 gtid_before_statement(THD *thd, Group_cache *gsc, Group_cache *gtc); 02785 02794 enum_gtid_statement_status gtid_pre_statement_checks(const THD *thd); 02795 02802 void gtid_post_statement_checks(THD *thd); 02803 02808 int gtid_rollback(THD *thd); 02809 02810 int gtid_acquire_ownership_single(THD *thd); 02811 #ifdef HAVE_NDB_BINLOG 02812 int gtid_acquire_ownership_multiple(THD *thd); 02813 #endif 02814 02815 #endif // ifndef MYSQL_CLIENT 02816 02817 #endif /* RPL_GTID_H_INCLUDED */