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
29ulong wsrep_reject_queries;
30
31static long wsrep_prev_slave_threads = wsrep_slave_threads;
32
33int 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
47linking will succeed even if the server is built with a dynamically
48linked InnoDB. */
49ulong innodb_lock_schedule_algorithm __attribute__((weak));
50
51bool 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
61bool 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
74bool 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
96bool 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*/
120static
121bool 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
155static
156bool 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
174bool 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
202err:
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
209bool 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
216bool 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
234static 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
255end:
256 my_free(opts_copy);
257 return ret;
258}
259
260static 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
283static 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
306bool 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
320err:
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
327bool 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
371void 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
387bool 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
397bool 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
410void 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
417bool 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
438static 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
444bool 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
465bool 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
508void 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. */
519bool 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
532bool wsrep_cluster_name_update (sys_var *self, THD* thd, enum_var_type type)
533{
534 return 0;
535}
536
537bool 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
550bool 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
556bool 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
571err:
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
578bool wsrep_node_address_update (sys_var *self, THD* thd, enum_var_type type)
579{
580 return 0;
581}
582
583void 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
591static 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
597bool 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
608bool 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
650bool wsrep_desync_update (sys_var *self, THD* thd, enum_var_type type)
651{
652 DBUG_ASSERT(wsrep);
653 return false;
654}
655
656bool 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
666bool 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
683static 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
699static int show_var_cmp(const void *var1, const void *var2)
700{
701 return strcasecmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name);
702}
703
704int 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