1 /* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
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 St, Fifth Floor, Boston, MA 02110-1301 USA */
15
16 /**
17 @file
18
19 All of the functions defined in this file which are not used (the ones to
20 handle failsafe) are not used; their code has not been updated for more
21 than one year now so should be considered as BADLY BROKEN. Do not enable
22 it. The used functions (to handle LOAD DATA FROM MASTER, plus some small
23 functions like register_slave()) are working.
24 */
25
26 #include "sql_priv.h"
27 #include "sql_parse.h" // check_access
28 #ifdef HAVE_REPLICATION
29
30 #include "repl_failsafe.h"
31 #include "sql_acl.h" // REPL_SLAVE_ACL
32 #include "sql_repl.h"
33 #include "slave.h"
34 #include "rpl_mi.h"
35 #include "rpl_filter.h"
36 #include "log_event.h"
37 #include "sql_db.h" // mysql_create_db
38 #include <mysql.h>
39
40 #define SLAVE_LIST_CHUNK 128
41 #define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
42
43
44 ulong rpl_status=RPL_NULL;
45 mysql_mutex_t LOCK_rpl_status;
46 mysql_cond_t COND_rpl_status;
47 HASH slave_list;
48
49 const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
50 TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
51 rpl_role_type, NULL};
52
53 const 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
change_rpl_status(ulong from_status,ulong to_status)67 void 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_cond_signal(&COND_rpl_status);
73 mysql_mutex_unlock(&LOCK_rpl_status);
74 }
75
76
77 #define get_object(p, obj, msg) \
78 {\
79 uint len = (uint)*p++; \
80 if (p + len > p_end || len >= sizeof(obj)) \
81 {\
82 errmsg= msg;\
83 goto err; \
84 }\
85 strmake(obj,(char*) p,len); \
86 p+= len; \
87 }\
88
89
unregister_slave(THD * thd,bool only_mine,bool need_mutex)90 void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
91 {
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
register_slave(THD * thd,uchar * packet,uint packet_length)118 int register_slave(THD* thd, uchar* packet, uint 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->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= 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
157 err:
158 my_free(si);
159 my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
160 err2:
161 return 1;
162 }
163
164 extern "C" uint32
slave_list_key(SLAVE_INFO * si,size_t * len,my_bool not_used)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
slave_info_free(void * s)172 extern "C" void slave_info_free(void *s)
173 {
174 my_free(s);
175 }
176
177 #ifdef HAVE_PSI_INTERFACE
178 static PSI_mutex_key key_LOCK_slave_list;
179
180 static PSI_mutex_info all_slave_list_mutexes[]=
181 {
182 { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
183 };
184
init_all_slave_list_mutexes(void)185 static 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
init_slave_list()198 void 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
end_slave_list()210 void 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 /**
222 Execute a SHOW SLAVE HOSTS statement.
223
224 @param thd Pointer to THD object for the client thread executing the
225 statement.
226
227 @retval FALSE success
228 @retval TRUE failure
229 */
show_slave_hosts(THD * thd)230 bool show_slave_hosts(THD* thd)
231 {
232 List<Item> field_list;
233 Protocol *protocol= thd->protocol;
234 DBUG_ENTER("show_slave_hosts");
235
236 field_list.push_back(new Item_return_int("Server_id", 10,
237 MYSQL_TYPE_LONG));
238 field_list.push_back(new Item_empty_string("Host", 20));
239 if (opt_show_slave_auth_info)
240 {
241 field_list.push_back(new Item_empty_string("User",20));
242 field_list.push_back(new Item_empty_string("Password",20));
243 }
244 field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
245 field_list.push_back(new Item_return_int("Master_id", 10,
246 MYSQL_TYPE_LONG));
247
248 if (protocol->send_result_set_metadata(&field_list,
249 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
250 DBUG_RETURN(TRUE);
251
252 mysql_mutex_lock(&LOCK_slave_list);
253
254 for (uint i = 0; i < slave_list.records; ++i)
255 {
256 SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
257 protocol->prepare_for_resend();
258 protocol->store((uint32) si->server_id);
259 protocol->store(si->host, &my_charset_bin);
260 if (opt_show_slave_auth_info)
261 {
262 protocol->store(si->user, &my_charset_bin);
263 protocol->store(si->password, &my_charset_bin);
264 }
265 protocol->store((uint32) si->port);
266 protocol->store((uint32) si->master_id);
267 if (protocol->write())
268 {
269 mysql_mutex_unlock(&LOCK_slave_list);
270 DBUG_RETURN(TRUE);
271 }
272 }
273 mysql_mutex_unlock(&LOCK_slave_list);
274 my_eof(thd);
275 DBUG_RETURN(FALSE);
276 }
277
278 #endif /* HAVE_REPLICATION */
279
280