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