1/*
2 Copyright (c) 2001, 2011, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
17/**
18 @file
19
20 All of the functions defined in this file which are not used (the ones to
21 handle failsafe) are not used; their code has not been updated for more
22 than one year now so should be considered as BADLY BROKEN. Do not enable
23 it. The used functions (to handle LOAD DATA FROM MASTER, plus some small
24 functions like register_slave()) are working.
25*/
26
27#include "mariadb.h"
28#include "sql_priv.h"
29#include "sql_parse.h" // check_access
30#ifdef HAVE_REPLICATION
31
32#include "repl_failsafe.h"
33#include "sql_acl.h" // REPL_SLAVE_ACL
34#include "sql_repl.h"
35#include "slave.h"
36#include "rpl_mi.h"
37#include "rpl_filter.h"
38#include "log_event.h"
39#include <mysql.h>
40
41#define SLAVE_LIST_CHUNK 128
42#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
43
44
45ulong rpl_status=RPL_NULL;
46mysql_mutex_t LOCK_rpl_status;
47HASH slave_list;
48
49const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
50TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
51 rpl_role_type, NULL};
52
53const char* rpl_status_type[]=
54{
55 "AUTH_MASTER","IDLE_SLAVE","ACTIVE_SLAVE","LOST_SOLDIER","TROOP_SOLDIER",
56 "RECOVERY_CAPTAIN","NULL",NullS
57};
58
59/*
60 All of the functions defined in this file which are not used (the ones to
61 handle failsafe) are not used; their code has not been updated for more than
62 one year now so should be considered as BADLY BROKEN. Do not enable it.
63 The used functions (to handle LOAD DATA FROM MASTER, plus some small
64 functions like register_slave()) are working.
65*/
66
67void change_rpl_status(ulong from_status, ulong to_status)
68{
69 mysql_mutex_lock(&LOCK_rpl_status);
70 if (rpl_status == from_status || rpl_status == RPL_ANY)
71 rpl_status = to_status;
72 mysql_mutex_unlock(&LOCK_rpl_status);
73}
74
75
76#define get_object(p, obj, msg) \
77{\
78 uint len = (uint)*p++; \
79 if (p + len > p_end || len >= sizeof(obj)) \
80 {\
81 errmsg= msg;\
82 goto err; \
83 }\
84 strmake(obj,(char*) p,len); \
85 p+= len; \
86}\
87
88
89void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
90{
91 uint32 thd_server_id= thd->variables.server_id;
92 if (thd_server_id)
93 {
94 if (need_mutex)
95 mysql_mutex_lock(&LOCK_slave_list);
96
97 SLAVE_INFO* old_si;
98 if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
99 (uchar*)&thd_server_id, 4)) &&
100 (!only_mine || old_si->thd == thd))
101 my_hash_delete(&slave_list, (uchar*)old_si);
102
103 if (need_mutex)
104 mysql_mutex_unlock(&LOCK_slave_list);
105 }
106}
107
108
109/**
110 Register slave in 'slave_list' hash table.
111
112 @return
113 0 ok
114 @return
115 1 Error. Error message sent to client
116*/
117
118int register_slave(THD* thd, uchar* packet, size_t packet_length)
119{
120 int res;
121 SLAVE_INFO *si;
122 uchar *p= packet, *p_end= packet + packet_length;
123 const char *errmsg= "Wrong parameters to function register_slave";
124
125 if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
126 return 1;
127 if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
128 goto err2;
129
130 thd->variables.server_id= si->server_id= uint4korr(p);
131 p+= 4;
132 get_object(p,si->host, "Failed to register slave: too long 'report-host'");
133 get_object(p,si->user, "Failed to register slave: too long 'report-user'");
134 get_object(p,si->password, "Failed to register slave; too long 'report-password'");
135 if (p+10 > p_end)
136 goto err;
137 si->port= uint2korr(p);
138 p += 2;
139 /*
140 We need to by pass the bytes used in the fake rpl_recovery_rank
141 variable. It was removed in patch for BUG#13963. But this would
142 make a server with that patch unable to connect to an old master.
143 See: BUG#49259
144 */
145 // si->rpl_recovery_rank= uint4korr(p);
146 p += 4;
147 if (!(si->master_id= uint4korr(p)))
148 si->master_id= global_system_variables.server_id;
149 si->thd= thd;
150
151 mysql_mutex_lock(&LOCK_slave_list);
152 unregister_slave(thd,0,0);
153 res= my_hash_insert(&slave_list, (uchar*) si);
154 mysql_mutex_unlock(&LOCK_slave_list);
155 return res;
156
157err:
158 my_free(si);
159 my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
160err2:
161 return 1;
162}
163
164extern "C" uint32
165*slave_list_key(SLAVE_INFO* si, size_t *len,
166 my_bool not_used __attribute__((unused)))
167{
168 *len = 4;
169 return &si->server_id;
170}
171
172extern "C" void slave_info_free(void *s)
173{
174 my_free(s);
175}
176
177#ifdef HAVE_PSI_INTERFACE
178static PSI_mutex_key key_LOCK_slave_list;
179
180static PSI_mutex_info all_slave_list_mutexes[]=
181{
182 { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
183};
184
185static void init_all_slave_list_mutexes(void)
186{
187 const char* category= "sql";
188 int count;
189
190 if (PSI_server == NULL)
191 return;
192
193 count= array_elements(all_slave_list_mutexes);
194 PSI_server->register_mutex(category, all_slave_list_mutexes, count);
195}
196#endif /* HAVE_PSI_INTERFACE */
197
198void init_slave_list()
199{
200#ifdef HAVE_PSI_INTERFACE
201 init_all_slave_list_mutexes();
202#endif
203
204 my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
205 (my_hash_get_key) slave_list_key,
206 (my_hash_free_key) slave_info_free, 0);
207 mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
208}
209
210void end_slave_list()
211{
212 /* No protection by a mutex needed as we are only called at shutdown */
213 if (my_hash_inited(&slave_list))
214 {
215 my_hash_free(&slave_list);
216 mysql_mutex_destroy(&LOCK_slave_list);
217 }
218}
219
220/**
221 Execute a SHOW SLAVE HOSTS statement.
222
223 @param thd Pointer to THD object for the client thread executing the
224 statement.
225
226 @retval FALSE success
227 @retval TRUE failure
228*/
229bool show_slave_hosts(THD* thd)
230{
231 List<Item> field_list;
232 Protocol *protocol= thd->protocol;
233 MEM_ROOT *mem_root= thd->mem_root;
234 DBUG_ENTER("show_slave_hosts");
235
236 field_list.push_back(new (mem_root)
237 Item_return_int(thd, "Server_id", 10,
238 MYSQL_TYPE_LONG),
239 thd->mem_root);
240 field_list.push_back(new (mem_root)
241 Item_empty_string(thd, "Host", 20),
242 thd->mem_root);
243 if (opt_show_slave_auth_info)
244 {
245 field_list.push_back(new (mem_root) Item_empty_string(thd, "User", 20),
246 thd->mem_root);
247 field_list.push_back(new (mem_root) Item_empty_string(thd, "Password", 20),
248 thd->mem_root);
249 }
250 field_list.push_back(new (mem_root)
251 Item_return_int(thd, "Port", 7, MYSQL_TYPE_LONG),
252 thd->mem_root);
253 field_list.push_back(new (mem_root)
254 Item_return_int(thd, "Master_id", 10, MYSQL_TYPE_LONG),
255 thd->mem_root);
256
257 if (protocol->send_result_set_metadata(&field_list,
258 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
259 DBUG_RETURN(TRUE);
260
261 mysql_mutex_lock(&LOCK_slave_list);
262
263 for (uint i = 0; i < slave_list.records; ++i)
264 {
265 SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
266 protocol->prepare_for_resend();
267 protocol->store((uint32) si->server_id);
268 protocol->store(si->host, &my_charset_bin);
269 if (opt_show_slave_auth_info)
270 {
271 protocol->store(si->user, &my_charset_bin);
272 protocol->store(si->password, &my_charset_bin);
273 }
274 protocol->store((uint32) si->port);
275 protocol->store((uint32) si->master_id);
276 if (protocol->write())
277 {
278 mysql_mutex_unlock(&LOCK_slave_list);
279 DBUG_RETURN(TRUE);
280 }
281 }
282 mysql_mutex_unlock(&LOCK_slave_list);
283 my_eof(thd);
284 DBUG_RETURN(FALSE);
285}
286
287#endif /* HAVE_REPLICATION */
288
289