1 /* Copyright 2015 Codership Oy <http://www.codership.com>
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; version 2 of the License.
6 
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11 
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16 
17 //! @file some utility functions and classes not directly related to replication
18 
19 #include "wsrep_xid.h"
20 #include "sql_class.h"
21 #include "wsrep_mysqld.h" // for logging macros
22 
23 /*
24  * WSREPXid
25  */
26 
27 #define WSREP_XID_PREFIX "WSREPXid"
28 #define WSREP_XID_PREFIX_LEN MYSQL_XID_PREFIX_LEN
29 #define WSREP_XID_UUID_OFFSET 8
30 #define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
31 #define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
32 
wsrep_xid_init(XID * xid,const wsrep_uuid_t & uuid,wsrep_seqno_t seqno)33 void wsrep_xid_init(XID* xid, const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
34 {
35   xid->formatID= 1;
36   xid->gtrid_length= WSREP_XID_GTRID_LEN;
37   xid->bqual_length= 0;
38   memset(xid->data, 0, sizeof(xid->data));
39   memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
40   memcpy(xid->data + WSREP_XID_UUID_OFFSET,  &uuid,  sizeof(wsrep_uuid_t));
41   memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t));
42 }
43 
wsrep_is_wsrep_xid(const void * xid_ptr)44 int wsrep_is_wsrep_xid(const void* xid_ptr)
45 {
46   const XID* xid= reinterpret_cast<const XID*>(xid_ptr);
47   return (xid->formatID      == 1                   &&
48           xid->gtrid_length  == WSREP_XID_GTRID_LEN &&
49           xid->bqual_length  == 0                   &&
50           !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN));
51 }
52 
wsrep_xid_uuid(const XID & xid)53 const wsrep_uuid_t* wsrep_xid_uuid(const XID& xid)
54 {
55   if (wsrep_is_wsrep_xid(&xid))
56     return reinterpret_cast<const wsrep_uuid_t*>(xid.data
57                                                  + WSREP_XID_UUID_OFFSET);
58   else
59     return &WSREP_UUID_UNDEFINED;
60 }
61 
wsrep_xid_seqno(const XID & xid)62 wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
63 {
64   if (wsrep_is_wsrep_xid(&xid))
65   {
66     wsrep_seqno_t seqno;
67     memcpy(&seqno, xid.data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t));
68     return seqno;
69   }
70   else
71   {
72     return WSREP_SEQNO_UNDEFINED;
73   }
74 }
75 
set_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)76 static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
77 {
78   XID* xid= static_cast<XID*>(arg);
79   handlerton* hton= plugin_data(plugin, handlerton *);
80 
81   if (hton->db_type == DB_TYPE_INNODB)
82   {
83     const wsrep_uuid_t* uuid(wsrep_xid_uuid(*xid));
84     char uuid_str[40] = {0, };
85     wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
86     WSREP_DEBUG("Set WSREPXid for InnoDB:  %s:%lld",
87                 uuid_str, (long long)wsrep_xid_seqno(*xid));
88     hton->wsrep_set_checkpoint(hton, xid);
89   }
90 
91   return FALSE;
92 }
93 
wsrep_set_SE_checkpoint(XID & xid)94 void wsrep_set_SE_checkpoint(XID& xid)
95 {
96   plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, &xid);
97 }
98 
wsrep_set_SE_checkpoint(const wsrep_uuid_t & uuid,wsrep_seqno_t seqno)99 void wsrep_set_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
100 {
101   XID xid;
102   wsrep_xid_init(&xid, uuid, seqno);
103   wsrep_set_SE_checkpoint(xid);
104 }
105 
get_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)106 static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
107 {
108   XID* xid= reinterpret_cast<XID*>(arg);
109   handlerton* hton= plugin_data(plugin, handlerton *);
110 
111   if (hton->db_type == DB_TYPE_INNODB)
112   {
113     hton->wsrep_get_checkpoint(hton, xid);
114     const wsrep_uuid_t* uuid(wsrep_xid_uuid(*xid));
115     char uuid_str[40] = {0, };
116     wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
117     WSREP_DEBUG("Read WSREPXid from InnoDB:  %s:%lld",
118                 uuid_str, (long long)wsrep_xid_seqno(*xid));
119   }
120 
121   return FALSE;
122 }
123 
wsrep_get_SE_checkpoint(XID & xid)124 void wsrep_get_SE_checkpoint(XID& xid)
125 {
126   plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN, &xid);
127 }
128 
wsrep_get_SE_checkpoint(wsrep_uuid_t & uuid,wsrep_seqno_t & seqno)129 void wsrep_get_SE_checkpoint(wsrep_uuid_t& uuid, wsrep_seqno_t& seqno)
130 {
131   uuid= WSREP_UUID_UNDEFINED;
132   seqno= WSREP_SEQNO_UNDEFINED;
133 
134   XID xid;
135   memset(&xid, 0, sizeof(xid));
136   xid.formatID= -1;
137 
138   wsrep_get_SE_checkpoint(xid);
139 
140   if (xid.formatID == -1) return; // nil XID
141 
142   if (!wsrep_is_wsrep_xid(&xid))
143   {
144     WSREP_WARN("Read non-wsrep XID from storage engines.");
145     return;
146   }
147 
148   uuid= *wsrep_xid_uuid(xid);
149   seqno= wsrep_xid_seqno(xid);
150 }
151 
152 /*
153   Sort order for XIDs. Wsrep XIDs are sorted according to
154   seqno in ascending order. Non-wsrep XIDs are considered
155   equal among themselves and greater than with respect
156   to wsrep XIDs.
157  */
158 struct Wsrep_xid_cmp
159 {
operator ()Wsrep_xid_cmp160   bool operator()(const XID& left, const XID& right) const
161   {
162     const bool left_is_wsrep= wsrep_is_wsrep_xid(&left);
163     const bool right_is_wsrep= wsrep_is_wsrep_xid(&right);
164     if (left_is_wsrep && right_is_wsrep)
165     {
166       return (wsrep_xid_seqno(left) < wsrep_xid_seqno(right));
167     }
168     else if (left_is_wsrep)
169     {
170       return true;
171     }
172     else
173     {
174       return false;
175     }
176   }
177 };
178 
wsrep_sort_xid_array(XID * array,int len)179 void wsrep_sort_xid_array(XID *array, int len)
180 {
181   std::sort(array, array + len, Wsrep_xid_cmp());
182 }
183