1 | /* Copyright 2008-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 | #include "wsrep_var.h" |
17 | |
18 | #include <mysqld.h> |
19 | #include <sql_class.h> |
20 | #include <set_var.h> |
21 | #include <sql_acl.h> |
22 | #include "wsrep_priv.h" |
23 | #include "wsrep_thd.h" |
24 | #include "wsrep_xid.h" |
25 | #include <my_dir.h> |
26 | #include <cstdio> |
27 | #include <cstdlib> |
28 | |
29 | ulong wsrep_reject_queries; |
30 | |
31 | static long wsrep_prev_slave_threads = wsrep_slave_threads; |
32 | |
33 | int wsrep_init_vars() |
34 | { |
35 | wsrep_provider = my_strdup(WSREP_NONE, MYF(MY_WME)); |
36 | wsrep_provider_options= my_strdup("" , MYF(MY_WME)); |
37 | wsrep_cluster_address = my_strdup("" , MYF(MY_WME)); |
38 | wsrep_cluster_name = my_strdup(WSREP_CLUSTER_NAME, MYF(MY_WME)); |
39 | wsrep_node_name = my_strdup("" , MYF(MY_WME)); |
40 | wsrep_node_address = my_strdup("" , MYF(MY_WME)); |
41 | wsrep_node_incoming_address= my_strdup(WSREP_NODE_INCOMING_AUTO, MYF(MY_WME)); |
42 | wsrep_start_position = my_strdup(WSREP_START_POSITION_ZERO, MYF(MY_WME)); |
43 | return 0; |
44 | } |
45 | |
46 | /* This is intentionally declared as a weak global symbol, so that |
47 | linking will succeed even if the server is built with a dynamically |
48 | linked InnoDB. */ |
49 | ulong innodb_lock_schedule_algorithm __attribute__((weak)); |
50 | |
51 | bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) |
52 | { |
53 | if (var_type == OPT_GLOBAL) { |
54 | // FIXME: this variable probably should be changed only per session |
55 | thd->variables.wsrep_on = global_system_variables.wsrep_on; |
56 | } |
57 | |
58 | return false; |
59 | } |
60 | |
61 | bool wsrep_on_check(sys_var *self, THD* thd, set_var* var) |
62 | { |
63 | bool new_wsrep_on= (bool)var->save_result.ulonglong_value; |
64 | |
65 | if (new_wsrep_on && innodb_lock_schedule_algorithm != 0) { |
66 | my_message(ER_WRONG_ARGUMENTS, " WSREP (galera) can't be enabled " |
67 | "if innodb_lock_schedule_algorithm=VATS. Please configure" |
68 | " innodb_lock_schedule_algorithm=FCFS and restart." , MYF(0)); |
69 | return true; |
70 | } |
71 | return false; |
72 | } |
73 | |
74 | bool wsrep_causal_reads_update (sys_var *self, THD* thd, enum_var_type var_type) |
75 | { |
76 | // global setting should not affect session setting. |
77 | // if (var_type == OPT_GLOBAL) { |
78 | // thd->variables.wsrep_causal_reads = global_system_variables.wsrep_causal_reads; |
79 | // } |
80 | if (thd->variables.wsrep_causal_reads) { |
81 | thd->variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; |
82 | } else { |
83 | thd->variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; |
84 | } |
85 | |
86 | // update global settings too. |
87 | if (global_system_variables.wsrep_causal_reads) { |
88 | global_system_variables.wsrep_sync_wait |= WSREP_SYNC_WAIT_BEFORE_READ; |
89 | } else { |
90 | global_system_variables.wsrep_sync_wait &= ~WSREP_SYNC_WAIT_BEFORE_READ; |
91 | } |
92 | |
93 | return false; |
94 | } |
95 | |
96 | bool wsrep_sync_wait_update (sys_var* self, THD* thd, enum_var_type var_type) |
97 | { |
98 | // global setting should not affect session setting. |
99 | // if (var_type == OPT_GLOBAL) { |
100 | // thd->variables.wsrep_sync_wait = global_system_variables.wsrep_sync_wait; |
101 | // } |
102 | thd->variables.wsrep_causal_reads = thd->variables.wsrep_sync_wait & |
103 | WSREP_SYNC_WAIT_BEFORE_READ; |
104 | |
105 | // update global settings too |
106 | global_system_variables.wsrep_causal_reads = global_system_variables.wsrep_sync_wait & |
107 | WSREP_SYNC_WAIT_BEFORE_READ; |
108 | |
109 | return false; |
110 | } |
111 | |
112 | |
113 | /* |
114 | Verify the format of the given UUID:seqno. |
115 | |
116 | @return |
117 | true Fail |
118 | false Pass |
119 | */ |
120 | static |
121 | bool wsrep_start_position_verify (const char* start_str) |
122 | { |
123 | size_t start_len; |
124 | wsrep_uuid_t uuid; |
125 | ssize_t uuid_len; |
126 | |
127 | // Check whether it has minimum acceptable length. |
128 | start_len = strlen (start_str); |
129 | if (start_len < 34) |
130 | return true; |
131 | |
132 | /* |
133 | Parse the input to check whether UUID length is acceptable |
134 | and seqno has been provided. |
135 | */ |
136 | uuid_len = wsrep_uuid_scan (start_str, start_len, &uuid); |
137 | if (uuid_len < 0 || (start_len - uuid_len) < 2) |
138 | return true; |
139 | |
140 | // Separator must follow the UUID. |
141 | if (start_str[uuid_len] != ':') |
142 | return true; |
143 | |
144 | char* endptr; |
145 | wsrep_seqno_t const seqno __attribute__((unused)) // to avoid GCC warnings |
146 | (strtoll(&start_str[uuid_len + 1], &endptr, 10)); |
147 | |
148 | // Remaining string was seqno. |
149 | if (*endptr == '\0') return false; |
150 | |
151 | return true; |
152 | } |
153 | |
154 | |
155 | static |
156 | bool wsrep_set_local_position(const char* const value, size_t length, |
157 | bool const sst) |
158 | { |
159 | wsrep_uuid_t uuid; |
160 | size_t const uuid_len = wsrep_uuid_scan(value, length, &uuid); |
161 | wsrep_seqno_t const seqno = strtoll(value + uuid_len + 1, NULL, 10); |
162 | |
163 | if (sst) { |
164 | return wsrep_sst_received (wsrep, uuid, seqno, NULL, 0, false); |
165 | } else { |
166 | // initialization |
167 | local_uuid = uuid; |
168 | local_seqno = seqno; |
169 | } |
170 | return false; |
171 | } |
172 | |
173 | |
174 | bool wsrep_start_position_check (sys_var *self, THD* thd, set_var* var) |
175 | { |
176 | char start_pos_buf[FN_REFLEN]; |
177 | |
178 | if ((! var->save_result.string_value.str) || |
179 | (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety |
180 | goto err; |
181 | |
182 | memcpy(start_pos_buf, var->save_result.string_value.str, |
183 | var->save_result.string_value.length); |
184 | start_pos_buf[var->save_result.string_value.length]= 0; |
185 | |
186 | // Verify the format. |
187 | if (wsrep_start_position_verify(start_pos_buf)) return true; |
188 | |
189 | /* |
190 | As part of further verification, we try to update the value and catch |
191 | errors (if any). |
192 | */ |
193 | if (wsrep_set_local_position(var->save_result.string_value.str, |
194 | var->save_result.string_value.length, |
195 | true)) |
196 | { |
197 | goto err; |
198 | } |
199 | |
200 | return false; |
201 | |
202 | err: |
203 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
204 | var->save_result.string_value.str ? |
205 | var->save_result.string_value.str : "NULL" ); |
206 | return true; |
207 | } |
208 | |
209 | bool wsrep_start_position_update (sys_var *self, THD* thd, enum_var_type type) |
210 | { |
211 | // Print a confirmation that wsrep_start_position has been updated. |
212 | WSREP_INFO ("wsrep_start_position set to '%s'" , wsrep_start_position); |
213 | return false; |
214 | } |
215 | |
216 | bool wsrep_start_position_init (const char* val) |
217 | { |
218 | if (NULL == val || wsrep_start_position_verify (val)) |
219 | { |
220 | WSREP_ERROR("Bad initial value for wsrep_start_position: %s" , |
221 | (val ? val : "" )); |
222 | return true; |
223 | } |
224 | |
225 | if (wsrep_set_local_position (val, strlen(val), false)) |
226 | { |
227 | WSREP_ERROR("Failed to set initial wsep_start_position: %s" , val); |
228 | return true; |
229 | } |
230 | |
231 | return false; |
232 | } |
233 | |
234 | static int get_provider_option_value(const char* opts, |
235 | const char* opt_name, |
236 | ulong* opt_value) |
237 | { |
238 | int ret= 1; |
239 | ulong opt_value_tmp; |
240 | char *opt_value_str, *s, *opts_copy= my_strdup(opts, MYF(MY_WME)); |
241 | |
242 | if ((opt_value_str= strstr(opts_copy, opt_name)) == NULL) |
243 | goto end; |
244 | opt_value_str= strtok_r(opt_value_str, "=" , &s); |
245 | if (opt_value_str == NULL) goto end; |
246 | opt_value_str= strtok_r(NULL, ";" , &s); |
247 | if (opt_value_str == NULL) goto end; |
248 | |
249 | opt_value_tmp= strtoul(opt_value_str, NULL, 10); |
250 | if (errno == ERANGE) goto end; |
251 | |
252 | *opt_value= opt_value_tmp; |
253 | ret= 0; |
254 | |
255 | end: |
256 | my_free(opts_copy); |
257 | return ret; |
258 | } |
259 | |
260 | static bool refresh_provider_options() |
261 | { |
262 | DBUG_ASSERT(wsrep); |
263 | |
264 | WSREP_DEBUG("refresh_provider_options: %s" , |
265 | (wsrep_provider_options) ? wsrep_provider_options : "null" ); |
266 | char* opts= wsrep->options_get(wsrep); |
267 | if (opts) |
268 | { |
269 | wsrep_provider_options_init(opts); |
270 | get_provider_option_value(wsrep_provider_options, |
271 | (char*)"repl.max_ws_size" , |
272 | &wsrep_max_ws_size); |
273 | free(opts); |
274 | } |
275 | else |
276 | { |
277 | WSREP_ERROR("Failed to get provider options" ); |
278 | return true; |
279 | } |
280 | return false; |
281 | } |
282 | |
283 | static int wsrep_provider_verify (const char* provider_str) |
284 | { |
285 | MY_STAT f_stat; |
286 | char path[FN_REFLEN]; |
287 | |
288 | if (!provider_str || strlen(provider_str)== 0) |
289 | return 1; |
290 | |
291 | if (!strcmp(provider_str, WSREP_NONE)) |
292 | return 0; |
293 | |
294 | if (!unpack_filename(path, provider_str)) |
295 | return 1; |
296 | |
297 | /* check that provider file exists */ |
298 | memset(&f_stat, 0, sizeof(MY_STAT)); |
299 | if (!my_stat(path, &f_stat, MYF(0))) |
300 | { |
301 | return 1; |
302 | } |
303 | return 0; |
304 | } |
305 | |
306 | bool wsrep_provider_check (sys_var *self, THD* thd, set_var* var) |
307 | { |
308 | char wsrep_provider_buf[FN_REFLEN]; |
309 | |
310 | if ((! var->save_result.string_value.str) || |
311 | (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety |
312 | goto err; |
313 | |
314 | memcpy(wsrep_provider_buf, var->save_result.string_value.str, |
315 | var->save_result.string_value.length); |
316 | wsrep_provider_buf[var->save_result.string_value.length]= 0; |
317 | |
318 | if (!wsrep_provider_verify(wsrep_provider_buf)) return 0; |
319 | |
320 | err: |
321 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
322 | var->save_result.string_value.str ? |
323 | var->save_result.string_value.str : "NULL" ); |
324 | return 1; |
325 | } |
326 | |
327 | bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type) |
328 | { |
329 | bool rcode= false; |
330 | |
331 | bool wsrep_on_saved= thd->variables.wsrep_on; |
332 | thd->variables.wsrep_on= false; |
333 | |
334 | WSREP_DEBUG("wsrep_provider_update: %s" , wsrep_provider); |
335 | |
336 | /* stop replication is heavy operation, and includes closing all client |
337 | connections. Closing clients may need to get LOCK_global_system_variables |
338 | at least in MariaDB. |
339 | |
340 | Note: releasing LOCK_global_system_variables may cause race condition, if |
341 | there can be several concurrent clients changing wsrep_provider |
342 | */ |
343 | mysql_mutex_unlock(&LOCK_global_system_variables); |
344 | wsrep_stop_replication(thd); |
345 | mysql_mutex_lock(&LOCK_global_system_variables); |
346 | |
347 | if (wsrep_inited == 1) |
348 | wsrep_deinit(false); |
349 | |
350 | char* tmp= strdup(wsrep_provider); // wsrep_init() rewrites provider |
351 | //when fails |
352 | |
353 | if (wsrep_init()) |
354 | { |
355 | my_error(ER_CANT_OPEN_LIBRARY, MYF(0), tmp, my_error, "wsrep_init failed" ); |
356 | rcode = true; |
357 | } |
358 | free(tmp); |
359 | |
360 | // we sure don't want to use old address with new provider |
361 | wsrep_cluster_address_init(NULL); |
362 | wsrep_provider_options_init(NULL); |
363 | |
364 | thd->variables.wsrep_on= wsrep_on_saved; |
365 | |
366 | refresh_provider_options(); |
367 | |
368 | return rcode; |
369 | } |
370 | |
371 | void wsrep_provider_init (const char* value) |
372 | { |
373 | WSREP_DEBUG("wsrep_provider_init: %s -> %s" , |
374 | (wsrep_provider) ? wsrep_provider : "null" , |
375 | (value) ? value : "null" ); |
376 | if (NULL == value || wsrep_provider_verify (value)) |
377 | { |
378 | WSREP_ERROR("Bad initial value for wsrep_provider: %s" , |
379 | (value ? value : "" )); |
380 | return; |
381 | } |
382 | |
383 | if (wsrep_provider) my_free((void *)wsrep_provider); |
384 | wsrep_provider = my_strdup(value, MYF(0)); |
385 | } |
386 | |
387 | bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) |
388 | { |
389 | if (wsrep == NULL) |
390 | { |
391 | my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started" , MYF(0)); |
392 | return true; |
393 | } |
394 | return false; |
395 | } |
396 | |
397 | bool wsrep_provider_options_update(sys_var *self, THD* thd, enum_var_type type) |
398 | { |
399 | DBUG_ASSERT(wsrep); |
400 | wsrep_status_t ret= wsrep->options_set(wsrep, wsrep_provider_options); |
401 | if (ret != WSREP_OK) |
402 | { |
403 | WSREP_ERROR("Set options returned %d" , ret); |
404 | refresh_provider_options(); |
405 | return true; |
406 | } |
407 | return refresh_provider_options(); |
408 | } |
409 | |
410 | void wsrep_provider_options_init(const char* value) |
411 | { |
412 | if (wsrep_provider_options && wsrep_provider_options != value) |
413 | my_free((void *)wsrep_provider_options); |
414 | wsrep_provider_options = (value) ? my_strdup(value, MYF(0)) : NULL; |
415 | } |
416 | |
417 | bool wsrep_reject_queries_update(sys_var *self, THD* thd, enum_var_type type) |
418 | { |
419 | switch (wsrep_reject_queries) { |
420 | case WSREP_REJECT_NONE: |
421 | WSREP_INFO("Allowing client queries due to manual setting" ); |
422 | break; |
423 | case WSREP_REJECT_ALL: |
424 | WSREP_INFO("Rejecting client queries due to manual setting" ); |
425 | break; |
426 | case WSREP_REJECT_ALL_KILL: |
427 | wsrep_close_client_connections(FALSE); |
428 | WSREP_INFO("Rejecting client queries and killing connections due to manual setting" ); |
429 | break; |
430 | default: |
431 | WSREP_INFO("Unknown value for wsrep_reject_queries: %lu" , |
432 | wsrep_reject_queries); |
433 | return true; |
434 | } |
435 | return false; |
436 | } |
437 | |
438 | static int wsrep_cluster_address_verify (const char* cluster_address_str) |
439 | { |
440 | /* There is no predefined address format, it depends on provider. */ |
441 | return 0; |
442 | } |
443 | |
444 | bool wsrep_cluster_address_check (sys_var *self, THD* thd, set_var* var) |
445 | { |
446 | char addr_buf[FN_REFLEN]; |
447 | |
448 | if ((! var->save_result.string_value.str) || |
449 | (var->save_result.string_value.length >= sizeof(addr_buf))) // safety |
450 | goto err; |
451 | |
452 | strmake(addr_buf, var->save_result.string_value.str, |
453 | MY_MIN(sizeof(addr_buf)-1, var->save_result.string_value.length)); |
454 | |
455 | if (!wsrep_cluster_address_verify(addr_buf)) |
456 | return 0; |
457 | |
458 | err: |
459 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
460 | var->save_result.string_value.str ? |
461 | var->save_result.string_value.str : "NULL" ); |
462 | return 1; |
463 | } |
464 | |
465 | bool wsrep_cluster_address_update (sys_var *self, THD* thd, enum_var_type type) |
466 | { |
467 | bool wsrep_on_saved; |
468 | |
469 | /* Do not proceed if wsrep provider is not loaded. */ |
470 | if (!wsrep) |
471 | { |
472 | WSREP_INFO("wsrep provider is not loaded, can't re(start) replication." ); |
473 | return false; |
474 | } |
475 | |
476 | wsrep_on_saved= thd->variables.wsrep_on; |
477 | thd->variables.wsrep_on= false; |
478 | |
479 | /* stop replication is heavy operation, and includes closing all client |
480 | connections. Closing clients may need to get LOCK_global_system_variables |
481 | at least in MariaDB. |
482 | |
483 | Note: releasing LOCK_global_system_variables may cause race condition, if |
484 | there can be several concurrent clients changing wsrep_provider |
485 | */ |
486 | mysql_mutex_unlock(&LOCK_global_system_variables); |
487 | wsrep_stop_replication(thd); |
488 | |
489 | /* |
490 | Unlock and lock LOCK_wsrep_slave_threads to maintain lock order & avoid |
491 | any potential deadlock. |
492 | */ |
493 | mysql_mutex_unlock(&LOCK_wsrep_slave_threads); |
494 | mysql_mutex_lock(&LOCK_global_system_variables); |
495 | mysql_mutex_lock(&LOCK_wsrep_slave_threads); |
496 | |
497 | if (wsrep_start_replication()) |
498 | { |
499 | wsrep_create_rollbacker(); |
500 | wsrep_create_appliers(wsrep_slave_threads); |
501 | } |
502 | |
503 | thd->variables.wsrep_on= wsrep_on_saved; |
504 | |
505 | return false; |
506 | } |
507 | |
508 | void wsrep_cluster_address_init (const char* value) |
509 | { |
510 | WSREP_DEBUG("wsrep_cluster_address_init: %s -> %s" , |
511 | (wsrep_cluster_address) ? wsrep_cluster_address : "null" , |
512 | (value) ? value : "null" ); |
513 | |
514 | my_free((void*) wsrep_cluster_address); |
515 | wsrep_cluster_address= my_strdup(value ? value : "" , MYF(0)); |
516 | } |
517 | |
518 | /* wsrep_cluster_name cannot be NULL or an empty string. */ |
519 | bool wsrep_cluster_name_check (sys_var *self, THD* thd, set_var* var) |
520 | { |
521 | if (!var->save_result.string_value.str || |
522 | (var->save_result.string_value.length == 0)) |
523 | { |
524 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
525 | (var->save_result.string_value.str ? |
526 | var->save_result.string_value.str : "NULL" )); |
527 | return 1; |
528 | } |
529 | return 0; |
530 | } |
531 | |
532 | bool wsrep_cluster_name_update (sys_var *self, THD* thd, enum_var_type type) |
533 | { |
534 | return 0; |
535 | } |
536 | |
537 | bool wsrep_node_name_check (sys_var *self, THD* thd, set_var* var) |
538 | { |
539 | // TODO: for now 'allow' 0-length string to be valid (default) |
540 | if (!var->save_result.string_value.str) |
541 | { |
542 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
543 | (var->save_result.string_value.str ? |
544 | var->save_result.string_value.str : "NULL" )); |
545 | return 1; |
546 | } |
547 | return 0; |
548 | } |
549 | |
550 | bool wsrep_node_name_update (sys_var *self, THD* thd, enum_var_type type) |
551 | { |
552 | return 0; |
553 | } |
554 | |
555 | // TODO: do something more elaborate, like checking connectivity |
556 | bool wsrep_node_address_check (sys_var *self, THD* thd, set_var* var) |
557 | { |
558 | char addr_buf[FN_REFLEN]; |
559 | |
560 | if ((! var->save_result.string_value.str) || |
561 | (var->save_result.string_value.length > (FN_REFLEN - 1))) // safety |
562 | goto err; |
563 | |
564 | memcpy(addr_buf, var->save_result.string_value.str, |
565 | var->save_result.string_value.length); |
566 | addr_buf[var->save_result.string_value.length]= 0; |
567 | |
568 | // TODO: for now 'allow' 0-length string to be valid (default) |
569 | return 0; |
570 | |
571 | err: |
572 | my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name.str, |
573 | var->save_result.string_value.str ? |
574 | var->save_result.string_value.str : "NULL" ); |
575 | return 1; |
576 | } |
577 | |
578 | bool wsrep_node_address_update (sys_var *self, THD* thd, enum_var_type type) |
579 | { |
580 | return 0; |
581 | } |
582 | |
583 | void wsrep_node_address_init (const char* value) |
584 | { |
585 | if (wsrep_node_address && strcmp(wsrep_node_address, value)) |
586 | my_free ((void*)wsrep_node_address); |
587 | |
588 | wsrep_node_address = (value) ? my_strdup(value, MYF(0)) : NULL; |
589 | } |
590 | |
591 | static void wsrep_slave_count_change_update () |
592 | { |
593 | wsrep_slave_count_change += (wsrep_slave_threads - wsrep_prev_slave_threads); |
594 | wsrep_prev_slave_threads = wsrep_slave_threads; |
595 | } |
596 | |
597 | bool wsrep_slave_threads_update (sys_var *self, THD* thd, enum_var_type type) |
598 | { |
599 | wsrep_slave_count_change_update(); |
600 | if (wsrep_slave_count_change > 0) |
601 | { |
602 | wsrep_create_appliers(wsrep_slave_count_change); |
603 | wsrep_slave_count_change = 0; |
604 | } |
605 | return false; |
606 | } |
607 | |
608 | bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) |
609 | { |
610 | if (wsrep == NULL) |
611 | { |
612 | my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started" , MYF(0)); |
613 | return true; |
614 | } |
615 | |
616 | bool new_wsrep_desync= (bool) var->save_result.ulonglong_value; |
617 | if (wsrep_desync == new_wsrep_desync) { |
618 | if (new_wsrep_desync) { |
619 | push_warning (thd, Sql_condition::WARN_LEVEL_WARN, |
620 | ER_WRONG_VALUE_FOR_VAR, |
621 | "'wsrep_desync' is already ON." ); |
622 | } else { |
623 | push_warning (thd, Sql_condition::WARN_LEVEL_WARN, |
624 | ER_WRONG_VALUE_FOR_VAR, |
625 | "'wsrep_desync' is already OFF." ); |
626 | } |
627 | return false; |
628 | } |
629 | wsrep_status_t ret(WSREP_WARNING); |
630 | if (new_wsrep_desync) { |
631 | ret = wsrep->desync (wsrep); |
632 | if (ret != WSREP_OK) { |
633 | WSREP_WARN ("SET desync failed %d for schema: %s, query: %s" , |
634 | ret, thd->get_db(), thd->query()); |
635 | my_error (ER_CANNOT_USER, MYF(0), "'desync'" , thd->query()); |
636 | return true; |
637 | } |
638 | } else { |
639 | ret = wsrep->resync (wsrep); |
640 | if (ret != WSREP_OK) { |
641 | WSREP_WARN ("SET resync failed %d for schema: %s, query: %s" , ret, |
642 | thd->get_db(), thd->query()); |
643 | my_error (ER_CANNOT_USER, MYF(0), "'resync'" , thd->query()); |
644 | return true; |
645 | } |
646 | } |
647 | return false; |
648 | } |
649 | |
650 | bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type) |
651 | { |
652 | DBUG_ASSERT(wsrep); |
653 | return false; |
654 | } |
655 | |
656 | bool wsrep_max_ws_size_check(sys_var *self, THD* thd, set_var* var) |
657 | { |
658 | if (wsrep == NULL) |
659 | { |
660 | my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started" , MYF(0)); |
661 | return true; |
662 | } |
663 | return false; |
664 | } |
665 | |
666 | bool wsrep_max_ws_size_update (sys_var *self, THD *thd, enum_var_type) |
667 | { |
668 | DBUG_ASSERT(wsrep); |
669 | |
670 | char max_ws_size_opt[128]; |
671 | my_snprintf(max_ws_size_opt, sizeof(max_ws_size_opt), |
672 | "repl.max_ws_size=%lu" , wsrep_max_ws_size); |
673 | wsrep_status_t ret= wsrep->options_set(wsrep, max_ws_size_opt); |
674 | if (ret != WSREP_OK) |
675 | { |
676 | WSREP_ERROR("Set options returned %d" , ret); |
677 | refresh_provider_options(); |
678 | return true; |
679 | } |
680 | return refresh_provider_options(); |
681 | } |
682 | |
683 | static SHOW_VAR wsrep_status_vars[]= |
684 | { |
685 | {"connected" , (char*) &wsrep_connected, SHOW_BOOL}, |
686 | {"ready" , (char*) &wsrep_ready, SHOW_BOOL}, |
687 | {"cluster_state_uuid" ,(char*) &wsrep_cluster_state_uuid,SHOW_CHAR_PTR}, |
688 | {"cluster_conf_id" , (char*) &wsrep_cluster_conf_id, SHOW_LONGLONG}, |
689 | {"cluster_status" , (char*) &wsrep_cluster_status, SHOW_CHAR_PTR}, |
690 | {"cluster_size" , (char*) &wsrep_cluster_size, SHOW_LONG_NOFLUSH}, |
691 | {"local_index" , (char*) &wsrep_local_index, SHOW_LONG_NOFLUSH}, |
692 | {"local_bf_aborts" , (char*) &wsrep_show_bf_aborts, SHOW_SIMPLE_FUNC}, |
693 | {"provider_name" , (char*) &wsrep_provider_name, SHOW_CHAR_PTR}, |
694 | {"provider_version" , (char*) &wsrep_provider_version, SHOW_CHAR_PTR}, |
695 | {"provider_vendor" , (char*) &wsrep_provider_vendor, SHOW_CHAR_PTR}, |
696 | {"thread_count" , (char*) &wsrep_running_threads, SHOW_LONG_NOFLUSH} |
697 | }; |
698 | |
699 | static int show_var_cmp(const void *var1, const void *var2) |
700 | { |
701 | return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); |
702 | } |
703 | |
704 | int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff, |
705 | enum enum_var_type scope) |
706 | { |
707 | uint i, maxi= SHOW_VAR_FUNC_BUFF_SIZE / sizeof(*var) - 1; |
708 | SHOW_VAR *v= (SHOW_VAR *)buff; |
709 | |
710 | var->type= SHOW_ARRAY; |
711 | var->value= buff; |
712 | |
713 | for (i=0; i < array_elements(wsrep_status_vars); i++) |
714 | *v++= wsrep_status_vars[i]; |
715 | |
716 | DBUG_ASSERT(i < maxi); |
717 | |
718 | if (wsrep != NULL) |
719 | { |
720 | wsrep_stats_var* stats= wsrep->stats_get(wsrep); |
721 | for (wsrep_stats_var *sv= stats; |
722 | i < maxi && sv && sv->name; i++, |
723 | sv++, v++) |
724 | { |
725 | v->name = thd->strdup(sv->name); |
726 | switch (sv->type) { |
727 | case WSREP_VAR_INT64: |
728 | v->value = (char*)thd->memdup(&sv->value._integer64, sizeof(longlong)); |
729 | v->type = SHOW_LONGLONG; |
730 | break; |
731 | case WSREP_VAR_STRING: |
732 | v->value = thd->strdup(sv->value._string); |
733 | v->type = SHOW_CHAR; |
734 | break; |
735 | case WSREP_VAR_DOUBLE: |
736 | v->value = (char*)thd->memdup(&sv->value._double, sizeof(double)); |
737 | v->type = SHOW_DOUBLE; |
738 | break; |
739 | } |
740 | } |
741 | wsrep->stats_free(wsrep, stats); |
742 | } |
743 | |
744 | my_qsort(buff, i, sizeof(*v), show_var_cmp); |
745 | |
746 | v->name= 0; // terminator |
747 | return 0; |
748 | } |
749 | |
750 | |