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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
15  */
16 
17 //! @file some utility functions and classes not directly related to replication
18 
19 #include "mariadb.h"
20 #include "wsrep_xid.h"
21 #include "sql_class.h"
22 #include "wsrep_mysqld.h" // for logging macros
23 
24 #include <algorithm> /* std::sort() */
25 
26 /*
27  * WSREPXid
28  */
29 
30 #define WSREP_XID_PREFIX "WSREPXi"
31 #define WSREP_XID_PREFIX_LEN 7
32 #define WSREP_XID_VERSION_OFFSET WSREP_XID_PREFIX_LEN
33 #define WSREP_XID_VERSION_1 'd'
34 #define WSREP_XID_VERSION_2 'e'
35 #define WSREP_XID_UUID_OFFSET 8
36 #define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
37 #define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
38 
wsrep_xid_init(XID * xid,const wsrep_uuid_t & uuid,wsrep_seqno_t seqno)39 void wsrep_xid_init(XID* xid, const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
40 {
41   xid->formatID= 1;
42   xid->gtrid_length= WSREP_XID_GTRID_LEN;
43   xid->bqual_length= 0;
44   memset(xid->data, 0, sizeof(xid->data));
45   memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
46   xid->data[WSREP_XID_VERSION_OFFSET] = WSREP_XID_VERSION_2;
47   memcpy(xid->data + WSREP_XID_UUID_OFFSET,  &uuid,  sizeof(wsrep_uuid_t));
48   int8store(xid->data + WSREP_XID_SEQNO_OFFSET,seqno);
49 }
50 
wsrep_is_wsrep_xid(const XID * xid)51 int wsrep_is_wsrep_xid(const XID* xid)
52 {
53   return (xid->formatID      == 1                   &&
54           xid->gtrid_length  == WSREP_XID_GTRID_LEN &&
55           xid->bqual_length  == 0                   &&
56           !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN) &&
57           (xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_1 ||
58            xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_2));
59 }
60 
wsrep_xid_uuid(const XID & xid)61 const wsrep_uuid_t* wsrep_xid_uuid(const XID& xid)
62 {
63   if (wsrep_is_wsrep_xid(&xid))
64     return reinterpret_cast<const wsrep_uuid_t*>(xid.data
65                                                  + WSREP_XID_UUID_OFFSET);
66   else
67     return &WSREP_UUID_UNDEFINED;
68 }
69 
wsrep_xid_uuid(const xid_t * xid)70 const unsigned char* wsrep_xid_uuid(const xid_t* xid)
71 {
72   DBUG_ASSERT(xid);
73   return wsrep_xid_uuid(*xid)->data;
74 }
75 
wsrep_xid_seqno(const XID & xid)76 wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
77 {
78   wsrep_seqno_t ret= WSREP_SEQNO_UNDEFINED;
79   if (wsrep_is_wsrep_xid(&xid))
80   {
81     switch (xid.data[WSREP_XID_VERSION_OFFSET])
82     {
83     case WSREP_XID_VERSION_1:
84       memcpy(&ret, xid.data + WSREP_XID_SEQNO_OFFSET, sizeof ret);
85       break;
86     case WSREP_XID_VERSION_2:
87       ret= sint8korr(xid.data + WSREP_XID_SEQNO_OFFSET);
88       break;
89     default:
90       break;
91     }
92   }
93   return ret;
94 }
95 
wsrep_xid_seqno(const xid_t * xid)96 long long wsrep_xid_seqno(const xid_t* xid)
97 {
98   DBUG_ASSERT(xid);
99   return wsrep_xid_seqno(*xid);
100 }
101 
set_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)102 static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
103 {
104   XID* xid= static_cast<XID*>(arg);
105   handlerton* hton= plugin_data(plugin, handlerton *);
106 
107   if (hton->set_checkpoint)
108   {
109     const wsrep_uuid_t* uuid(wsrep_xid_uuid(*xid));
110     char uuid_str[40] = {0, };
111     wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
112     WSREP_DEBUG("Set WSREPXid for InnoDB:  %s:%lld",
113                 uuid_str, (long long)wsrep_xid_seqno(*xid));
114     hton->set_checkpoint(hton, xid);
115   }
116   return FALSE;
117 }
118 
wsrep_set_SE_checkpoint(XID & xid)119 bool wsrep_set_SE_checkpoint(XID& xid)
120 {
121   return plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN,
122                         &xid);
123 }
124 
wsrep_set_SE_checkpoint(const wsrep_uuid_t & uuid,wsrep_seqno_t seqno)125 bool wsrep_set_SE_checkpoint(const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
126 {
127   XID xid;
128   wsrep_xid_init(&xid, uuid, seqno);
129   return wsrep_set_SE_checkpoint(xid);
130 }
131 
get_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)132 static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
133 {
134   XID* xid= reinterpret_cast<XID*>(arg);
135   handlerton* hton= plugin_data(plugin, handlerton *);
136 
137   if (hton->get_checkpoint)
138   {
139     hton->get_checkpoint(hton, xid);
140     const wsrep_uuid_t* uuid(wsrep_xid_uuid(*xid));
141     char uuid_str[40] = {0, };
142     wsrep_uuid_print(uuid, uuid_str, sizeof(uuid_str));
143     WSREP_DEBUG("Read WSREPXid from InnoDB:  %s:%lld",
144                 uuid_str, (long long)wsrep_xid_seqno(*xid));
145   }
146   return FALSE;
147 }
148 
wsrep_get_SE_checkpoint(XID & xid)149 bool wsrep_get_SE_checkpoint(XID& xid)
150 {
151   return plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN,
152                         &xid);
153 }
154 
wsrep_get_SE_checkpoint(wsrep_uuid_t & uuid,wsrep_seqno_t & seqno)155 bool wsrep_get_SE_checkpoint(wsrep_uuid_t& uuid, wsrep_seqno_t& seqno)
156 {
157   uuid= WSREP_UUID_UNDEFINED;
158   seqno= WSREP_SEQNO_UNDEFINED;
159 
160   XID xid;
161   xid.null();
162 
163   if (wsrep_get_SE_checkpoint(xid))
164   {
165     return true;
166   }
167 
168   if (xid.is_null())
169   {
170     return false;
171   }
172 
173   if (!wsrep_is_wsrep_xid(&xid))
174   {
175     WSREP_WARN("Read non-wsrep XID from storage engines.");
176     return false;
177   }
178 
179   uuid= *wsrep_xid_uuid(xid);
180   seqno= wsrep_xid_seqno(xid);
181 
182   return false;
183 }
184 
185 /*
186   Sort order for XIDs. Wsrep XIDs are sorted according to
187   seqno in ascending order. Non-wsrep XIDs are considered
188   equal among themselves and greater than with respect
189   to wsrep XIDs.
190  */
191 struct Wsrep_xid_cmp
192 {
operator ()Wsrep_xid_cmp193   bool operator()(const XID& left, const XID& right) const
194   {
195     const bool left_is_wsrep= wsrep_is_wsrep_xid(&left);
196     const bool right_is_wsrep= wsrep_is_wsrep_xid(&right);
197     if (left_is_wsrep && right_is_wsrep)
198     {
199       return (wsrep_xid_seqno(left) < wsrep_xid_seqno(right));
200     }
201     else if (left_is_wsrep)
202     {
203       return true;
204     }
205     else
206     {
207       return false;
208     }
209   }
210 };
211 
wsrep_sort_xid_array(XID * array,int len)212 void wsrep_sort_xid_array(XID *array, int len)
213 {
214   std::sort(array, array + len, Wsrep_xid_cmp());
215 }
216