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