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