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 <mysql/service_wsrep.h>
25
26 #include <algorithm> /* std::sort() */
27 /*
28 * WSREPXid
29 */
30
31 #define WSREP_XID_PREFIX "WSREPXi"
32 #define WSREP_XID_PREFIX_LEN 7
33 #define WSREP_XID_VERSION_OFFSET WSREP_XID_PREFIX_LEN
34 #define WSREP_XID_VERSION_1 'd'
35 #define WSREP_XID_VERSION_2 'e'
36 #define WSREP_XID_UUID_OFFSET 8
37 #define WSREP_XID_SEQNO_OFFSET (WSREP_XID_UUID_OFFSET + sizeof(wsrep_uuid_t))
38 #define WSREP_XID_GTRID_LEN (WSREP_XID_SEQNO_OFFSET + sizeof(wsrep_seqno_t))
39
wsrep_xid_init(XID * xid,const wsrep::gtid & wsgtid)40 void wsrep_xid_init(XID* xid, const wsrep::gtid& wsgtid)
41 {
42 xid->formatID= 1;
43 xid->gtrid_length= WSREP_XID_GTRID_LEN;
44 xid->bqual_length= 0;
45 memset(xid->data, 0, sizeof(xid->data));
46 memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
47 xid->data[WSREP_XID_VERSION_OFFSET]= WSREP_XID_VERSION_2;
48 memcpy(xid->data + WSREP_XID_UUID_OFFSET, wsgtid.id().data(),sizeof(wsrep::id));
49 int8store(xid->data + WSREP_XID_SEQNO_OFFSET, wsgtid.seqno().get());
50 }
51
52 extern "C"
wsrep_is_wsrep_xid(const void * xid_ptr)53 int wsrep_is_wsrep_xid(const void* xid_ptr)
54 {
55 const XID* xid= static_cast<const XID*>(xid_ptr);
56 return (xid->formatID == 1 &&
57 xid->gtrid_length == WSREP_XID_GTRID_LEN &&
58 xid->bqual_length == 0 &&
59 !memcmp(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN) &&
60 (xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_1 ||
61 xid->data[WSREP_XID_VERSION_OFFSET] == WSREP_XID_VERSION_2));
62 }
63
wsrep_xid_uuid(const xid_t * xid)64 const unsigned char* wsrep_xid_uuid(const xid_t* xid)
65 {
66 DBUG_ASSERT(xid);
67 static wsrep::id const undefined;
68 if (wsrep_is_wsrep_xid(xid))
69 return reinterpret_cast<const unsigned char*>
70 (xid->data + WSREP_XID_UUID_OFFSET);
71 else
72 return static_cast<const unsigned char*>(wsrep::id::undefined().data());
73 }
74
wsrep_xid_uuid(const XID & xid)75 const wsrep::id& wsrep_xid_uuid(const XID& xid)
76 {
77 compile_time_assert(sizeof(wsrep::id) == sizeof(wsrep_uuid_t));
78 return *reinterpret_cast<const wsrep::id*>(wsrep_xid_uuid(&xid));
79 }
80
wsrep_xid_seqno(const xid_t * xid)81 long long wsrep_xid_seqno(const xid_t* xid)
82 {
83 DBUG_ASSERT(xid);
84 long long ret= wsrep::seqno::undefined().get();
85 if (wsrep_is_wsrep_xid(xid))
86 {
87 switch (xid->data[WSREP_XID_VERSION_OFFSET])
88 {
89 case WSREP_XID_VERSION_1:
90 memcpy(&ret, xid->data + WSREP_XID_SEQNO_OFFSET, sizeof ret);
91 break;
92 case WSREP_XID_VERSION_2:
93 ret= sint8korr(xid->data + WSREP_XID_SEQNO_OFFSET);
94 break;
95 default:
96 break;
97 }
98 }
99 return ret;
100 }
101
wsrep_xid_seqno(const XID & xid)102 wsrep::seqno wsrep_xid_seqno(const XID& xid)
103 {
104 return wsrep::seqno(wsrep_xid_seqno(&xid));
105 }
106
set_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)107 static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
108 {
109 XID* xid= static_cast<XID*>(arg);
110 handlerton* hton= plugin_data(plugin, handlerton *);
111
112 if (hton->set_checkpoint)
113 {
114 const unsigned char* uuid= wsrep_xid_uuid(xid);
115 char uuid_str[40]= {0, };
116 wsrep_uuid_print((const wsrep_uuid_t*)uuid, uuid_str, sizeof(uuid_str));
117 WSREP_DEBUG("Set WSREPXid for InnoDB: %s:%lld",
118 uuid_str, (long long)wsrep_xid_seqno(xid));
119 hton->set_checkpoint(hton, xid);
120 }
121 return FALSE;
122 }
123
wsrep_set_SE_checkpoint(XID & xid)124 bool wsrep_set_SE_checkpoint(XID& xid)
125 {
126 return plugin_foreach(NULL, set_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN,
127 &xid);
128 }
129
wsrep_set_SE_checkpoint(const wsrep::gtid & wsgtid)130 bool wsrep_set_SE_checkpoint(const wsrep::gtid& wsgtid)
131 {
132 XID xid;
133 wsrep_xid_init(&xid, wsgtid);
134 return wsrep_set_SE_checkpoint(xid);
135 }
136
get_SE_checkpoint(THD * unused,plugin_ref plugin,void * arg)137 static my_bool get_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
138 {
139 XID* xid= reinterpret_cast<XID*>(arg);
140 handlerton* hton= plugin_data(plugin, handlerton *);
141
142 if (hton->get_checkpoint)
143 {
144 hton->get_checkpoint(hton, xid);
145 wsrep_uuid_t uuid;
146 memcpy(&uuid, wsrep_xid_uuid(xid), sizeof(uuid));
147 char uuid_str[40]= {0, };
148 wsrep_uuid_print(&uuid, uuid_str, sizeof(uuid_str));
149 WSREP_DEBUG("Read WSREPXid from InnoDB: %s:%lld",
150 uuid_str, (long long)wsrep_xid_seqno(xid));
151 }
152 return FALSE;
153 }
154
wsrep_get_SE_checkpoint(XID & xid)155 bool wsrep_get_SE_checkpoint(XID& xid)
156 {
157 return plugin_foreach(NULL, get_SE_checkpoint, MYSQL_STORAGE_ENGINE_PLUGIN,
158 &xid);
159 }
160
wsrep_get_SE_checkpoint()161 wsrep::gtid wsrep_get_SE_checkpoint()
162 {
163 XID xid;
164 xid.null();
165
166 if (wsrep_get_SE_checkpoint(xid))
167 {
168 return wsrep::gtid();
169 }
170
171 if (xid.is_null())
172 {
173 return wsrep::gtid();
174 }
175
176 if (!wsrep_is_wsrep_xid(&xid))
177 {
178 WSREP_WARN("Read non-wsrep XID from storage engines.");
179 return wsrep::gtid();
180 }
181
182 return wsrep::gtid(wsrep_xid_uuid(xid),wsrep_xid_seqno(xid));
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