My Project
rpl_gtid.h
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 &gtid)
00935   { return _add_gtid(gtid.sidno, gtid.gno); }
00942   enum_return_status _remove_gtid(const Gtid &gtid)
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 &gtid) 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 *>(&gtid_set->free_intervals); }
01272     inline void init(Gtid_set_p gtid_set, rpl_sidno sidno)
01273     { p= dynamic_element(&gtid_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(&gtid_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(&gtid_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 &gtid, my_thread_id owner);
01806   my_thread_id get_owner(const Gtid &gtid) const;
01815   void remove_gtid(const Gtid &gtid);
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 &gtid) const
01980   { return get_node(get_hash(gtid.sidno), gtid.gno); };
01982   bool contains_gtid(const Gtid &gtid) 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 &gtid) 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 &gtid) const
02154   { return owned_gtids.get_owner(gtid); }
02155 #ifndef MYSQL_CLIENT
02156 
02165   enum_return_status acquire_ownership(THD *thd, const Gtid &gtid);
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 &gtid);
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 &gtid_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 &gtid);
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 &gtid) 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 */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines