1
/* Copyright (C) 2007 Google Inc.
2
Copyright (c) 2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
3
Use is subject to license terms.
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; version 2 of the License.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
19
#include "semisync_master.h"
20
#include "sql_class.h" // THD
22
ReplSemiSyncMaster repl_semisync;
26
int repl_semi_report_binlog_update(Binlog_storage_param *param,
32
if (repl_semisync.getMasterEnabled())
35
Let us store the binlog file name and the position, so that
36
we know how long to wait for the binlog to the replicated to
37
the slave in synchronous replication.
39
error= repl_semisync.writeTranxInBinlog(log_file,
46
int repl_semi_request_commit(Trans_param *param)
51
int repl_semi_report_commit(Trans_param *param)
54
bool is_real_trans= param->flags & TRANS_IS_REAL_TRANS;
56
if (is_real_trans && param->log_pos)
58
const char *binlog_name= param->log_file;
59
return repl_semisync.commitTrx(binlog_name, param->log_pos);
64
int repl_semi_report_rollback(Trans_param *param)
66
return repl_semi_report_commit(param);
69
int repl_semi_binlog_dump_start(Binlog_transmit_param *param,
73
bool semi_sync_slave= repl_semisync.is_semi_sync_slave();
77
/* One more semi-sync slave */
78
repl_semisync.add_slave();
81
Let's assume this semi-sync slave has already received all
82
binlog events before the filename and position it requests.
84
repl_semisync.reportReplyBinlog(param->server_id, log_file, log_pos);
86
sql_print_information("Start %s binlog_dump to slave (server_id: %d), pos(%s, %lu)",
87
semi_sync_slave ? "semi-sync" : "asynchronous",
88
param->server_id, log_file, (unsigned long)log_pos);
93
int repl_semi_binlog_dump_end(Binlog_transmit_param *param)
95
bool semi_sync_slave= repl_semisync.is_semi_sync_slave();
97
sql_print_information("Stop %s binlog_dump to slave (server_id: %d)",
98
semi_sync_slave ? "semi-sync" : "asynchronous",
102
/* One less semi-sync slave */
103
repl_semisync.remove_slave();
108
int repl_semi_reserve_header(Binlog_transmit_param *param,
109
unsigned char *header,
110
unsigned long size, unsigned long *len)
112
*len += repl_semisync.reserveSyncHeader(header, size);
116
int repl_semi_before_send_event(Binlog_transmit_param *param,
117
unsigned char *packet, unsigned long len,
118
const char *log_file, my_off_t log_pos)
120
return repl_semisync.updateSyncHeader(packet,
126
int repl_semi_after_send_event(Binlog_transmit_param *param,
127
const char *event_buf, unsigned long len,
128
const char * skipped_log_file,
129
my_off_t skipped_log_pos)
131
if (repl_semisync.is_semi_sync_slave())
133
if(skipped_log_pos>0)
134
repl_semisync.skipSlaveReply(event_buf, param->server_id,
135
skipped_log_file, skipped_log_pos);
138
THD *thd= current_thd;
140
Possible errors in reading slave reply are ignored deliberately
141
because we do not want dump thread to quit on this. Error
142
messages are already reported.
144
(void) repl_semisync.readSlaveReply(&thd->net,
145
param->server_id, event_buf);
152
int repl_semi_reset_master(Binlog_transmit_param *param)
154
if (repl_semisync.resetMaster())
162
semisync system variables
164
static void fix_rpl_semi_sync_master_timeout(MYSQL_THD thd,
169
static void fix_rpl_semi_sync_master_trace_level(MYSQL_THD thd,
174
static void fix_rpl_semi_sync_master_enabled(MYSQL_THD thd,
179
static MYSQL_SYSVAR_BOOL(enabled, rpl_semi_sync_master_enabled,
181
"Enable semi-synchronous replication master (disabled by default). ",
183
&fix_rpl_semi_sync_master_enabled, // update
186
static MYSQL_SYSVAR_ULONG(timeout, rpl_semi_sync_master_timeout,
188
"The timeout value (in ms) for semi-synchronous replication in the master",
190
fix_rpl_semi_sync_master_timeout, // update
193
static MYSQL_SYSVAR_BOOL(wait_no_slave, rpl_semi_sync_master_wait_no_slave,
195
"Wait until timeout when no semi-synchronous replication slave available (enabled by default). ",
200
static MYSQL_SYSVAR_ULONG(trace_level, rpl_semi_sync_master_trace_level,
202
"The tracing level for semi-sync replication.",
204
&fix_rpl_semi_sync_master_trace_level, // update
207
static SYS_VAR* semi_sync_master_system_vars[]= {
208
MYSQL_SYSVAR(enabled),
209
MYSQL_SYSVAR(timeout),
210
MYSQL_SYSVAR(wait_no_slave),
211
MYSQL_SYSVAR(trace_level),
216
static void fix_rpl_semi_sync_master_timeout(MYSQL_THD thd,
221
*(unsigned long *)ptr= *(unsigned long *)val;
222
repl_semisync.setWaitTimeout(rpl_semi_sync_master_timeout);
226
static void fix_rpl_semi_sync_master_trace_level(MYSQL_THD thd,
231
*(unsigned long *)ptr= *(unsigned long *)val;
232
repl_semisync.setTraceLevel(rpl_semi_sync_master_trace_level);
236
static void fix_rpl_semi_sync_master_enabled(MYSQL_THD thd,
241
*(char *)ptr= *(char *)val;
242
if (rpl_semi_sync_master_enabled)
244
if (repl_semisync.enableMaster() != 0)
245
rpl_semi_sync_master_enabled = false;
249
if (repl_semisync.disableMaster() != 0)
250
rpl_semi_sync_master_enabled = true;
256
Trans_observer trans_observer = {
257
sizeof(Trans_observer), // len
259
repl_semi_report_commit, // after_commit
260
repl_semi_report_rollback, // after_rollback
263
Binlog_storage_observer storage_observer = {
264
sizeof(Binlog_storage_observer), // len
266
repl_semi_report_binlog_update, // report_update
269
Binlog_transmit_observer transmit_observer = {
270
sizeof(Binlog_transmit_observer), // len
272
repl_semi_binlog_dump_start, // start
273
repl_semi_binlog_dump_end, // stop
274
repl_semi_reserve_header, // reserve_header
275
repl_semi_before_send_event, // before_send_event
276
repl_semi_after_send_event, // after_send_event
277
repl_semi_reset_master, // reset
281
#define SHOW_FNAME(name) \
282
rpl_semi_sync_master_show_##name
284
#define DEF_SHOW_FUNC(name, show_type) \
285
static int SHOW_FNAME(name)(MYSQL_THD thd, SHOW_VAR *var, char *buff) \
287
repl_semisync.setExportStats(); \
288
var->type= show_type; \
289
var->value= (char *)&rpl_semi_sync_master_##name; \
293
DEF_SHOW_FUNC(status, SHOW_BOOL)
294
DEF_SHOW_FUNC(clients, SHOW_LONG)
295
DEF_SHOW_FUNC(wait_sessions, SHOW_LONG)
296
DEF_SHOW_FUNC(trx_wait_time, SHOW_LONGLONG)
297
DEF_SHOW_FUNC(trx_wait_num, SHOW_LONGLONG)
298
DEF_SHOW_FUNC(net_wait_time, SHOW_LONGLONG)
299
DEF_SHOW_FUNC(net_wait_num, SHOW_LONGLONG)
300
DEF_SHOW_FUNC(avg_net_wait_time, SHOW_LONG)
301
DEF_SHOW_FUNC(avg_trx_wait_time, SHOW_LONG)
304
/* plugin status variables */
305
static SHOW_VAR semi_sync_master_status_vars[]= {
306
{"Rpl_semi_sync_master_status",
307
(char*) &SHOW_FNAME(status),
309
{"Rpl_semi_sync_master_clients",
310
(char*) &SHOW_FNAME(clients),
312
{"Rpl_semi_sync_master_yes_tx",
313
(char*) &rpl_semi_sync_master_yes_transactions,
315
{"Rpl_semi_sync_master_no_tx",
316
(char*) &rpl_semi_sync_master_no_transactions,
318
{"Rpl_semi_sync_master_wait_sessions",
319
(char*) &SHOW_FNAME(wait_sessions),
321
{"Rpl_semi_sync_master_no_times",
322
(char*) &rpl_semi_sync_master_off_times,
324
{"Rpl_semi_sync_master_timefunc_failures",
325
(char*) &rpl_semi_sync_master_timefunc_fails,
327
{"Rpl_semi_sync_master_wait_pos_backtraverse",
328
(char*) &rpl_semi_sync_master_wait_pos_backtraverse,
330
{"Rpl_semi_sync_master_tx_wait_time",
331
(char*) &SHOW_FNAME(trx_wait_time),
333
{"Rpl_semi_sync_master_tx_waits",
334
(char*) &SHOW_FNAME(trx_wait_num),
336
{"Rpl_semi_sync_master_tx_avg_wait_time",
337
(char*) &SHOW_FNAME(avg_trx_wait_time),
339
{"Rpl_semi_sync_master_net_wait_time",
340
(char*) &SHOW_FNAME(net_wait_time),
342
{"Rpl_semi_sync_master_net_waits",
343
(char*) &SHOW_FNAME(net_wait_num),
345
{"Rpl_semi_sync_master_net_avg_wait_time",
346
(char*) &SHOW_FNAME(avg_net_wait_time),
348
{NULL, NULL, SHOW_LONG},
351
#ifdef HAVE_PSI_INTERFACE
352
PSI_mutex_key key_ss_mutex_LOCK_binlog_;
354
static PSI_mutex_info all_semisync_mutexes[]=
356
{ &key_ss_mutex_LOCK_binlog_, "LOCK_binlog_", 0}
359
PSI_cond_key key_ss_cond_COND_binlog_send_;
361
static PSI_cond_info all_semisync_conds[]=
363
{ &key_ss_cond_COND_binlog_send_, "COND_binlog_send_", 0}
365
#endif /* HAVE_PSI_INTERFACE */
367
PSI_stage_info stage_waiting_for_semi_sync_ack_from_slave=
368
{ 0, "Waiting for semi-sync ACK from slave", 0};
370
#ifdef HAVE_PSI_INTERFACE
371
PSI_stage_info *all_semisync_stages[]=
373
& stage_waiting_for_semi_sync_ack_from_slave
376
static void init_semisync_psi_keys(void)
378
const char* category= "semisync";
381
count= array_elements(all_semisync_mutexes);
382
mysql_mutex_register(category, all_semisync_mutexes, count);
384
count= array_elements(all_semisync_conds);
385
mysql_cond_register(category, all_semisync_conds, count);
387
count= array_elements(all_semisync_stages);
388
mysql_stage_register(category, all_semisync_stages, count);
390
#endif /* HAVE_PSI_INTERFACE */
392
static int semi_sync_master_plugin_init(void *p)
394
#ifdef HAVE_PSI_INTERFACE
395
init_semisync_psi_keys();
398
if (repl_semisync.initObject())
400
if (register_trans_observer(&trans_observer, p))
402
if (register_binlog_storage_observer(&storage_observer, p))
404
if (register_binlog_transmit_observer(&transmit_observer, p))
409
static int semi_sync_master_plugin_deinit(void *p)
411
if (unregister_trans_observer(&trans_observer, p))
413
sql_print_error("unregister_trans_observer failed");
416
if (unregister_binlog_storage_observer(&storage_observer, p))
418
sql_print_error("unregister_binlog_storage_observer failed");
421
if (unregister_binlog_transmit_observer(&transmit_observer, p))
423
sql_print_error("unregister_binlog_transmit_observer failed");
426
sql_print_information("unregister_replicator OK");
430
struct Mysql_replication semi_sync_master_plugin= {
431
MYSQL_REPLICATION_INTERFACE_VERSION
435
Plugin library descriptor
437
mysql_declare_plugin(semi_sync_master)
439
MYSQL_REPLICATION_PLUGIN,
440
&semi_sync_master_plugin,
441
"rpl_semi_sync_master",
443
"Semi-synchronous replication master",
445
semi_sync_master_plugin_init, /* Plugin Init */
446
semi_sync_master_plugin_deinit, /* Plugin Deinit */
448
semi_sync_master_status_vars, /* status variables */
449
semi_sync_master_system_vars, /* system variables */
450
NULL, /* config options */
453
mysql_declare_plugin_end;