summaryrefslogtreecommitdiff
path: root/sql/log_event_server.cc
diff options
context:
space:
mode:
authorSujatha <sujatha.sivakumar@mariadb.com>2020-04-09 20:45:45 +0530
committerAndrei Elkin <andrei.elkin@mariadb.com>2021-06-11 19:49:39 +0300
commit6c39eaeb126328e7813b146ecf652d51e4508981 (patch)
tree0a5226675f3564235b02a99f29a0b6272af8efe0 /sql/log_event_server.cc
parent82c07b178abfa9395f1d67747148a431d6eb6ae7 (diff)
downloadmariadb-git-6c39eaeb126328e7813b146ecf652d51e4508981.tar.gz
MDEV-21117: refine the server binlog-based recovery for semisync
Problem: ======= When the semisync master is crashed and restarted as slave it could recover transactions that former slaves may never have seen. A known method existed to clear out all prepared transactions with --tc-heuristic-recover=rollback does not care to adjust binlog accordingly. Fix: === The binlog-based recovery is made to concern of the slave semisync role of post-crash restarted server. No changes in behavior is done to the "normal" binloggging server and the semisync master. When the restarted server is configured with --rpl-semi-sync-slave-enabled=1 the refined recovery attempts to roll back prepared transactions and truncate binlog accordingly. In case of a partially committed (that is committed at least in one of the engine participants) such transaction gets committed. It's guaranteed no (partially as well) committed transactions exist beyond the truncate position. In case there exists a non-transactional replication event (being in a way a committed transaction) past the computed truncate position the recovery ends with an error. As after master crash and failover to slave, the demoted-to-slave ex-master must be ready to face and accept its own (generated by) events, without generally necessary --replicate-same-server-id. So the acceptance conditions are relaxed for the semisync slave to accept own events without that option. While gtid_strict_mode ON ensures no duplicate transaction can be (re-)executed the master_use_gtid=none slave has to be configured with --replicate-same-server-id. *NOTE* for reviewers. This patch does not handle the user XA which is done in next git commit.
Diffstat (limited to 'sql/log_event_server.cc')
-rw-r--r--sql/log_event_server.cc68
1 files changed, 53 insertions, 15 deletions
diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc
index e216724ca7a..d97e87fc4e9 100644
--- a/sql/log_event_server.cc
+++ b/sql/log_event_server.cc
@@ -644,7 +644,7 @@ Log_event::do_shall_skip(rpl_group_info *rgi)
rli->replicate_same_server_id,
rli->slave_skip_counter));
if ((server_id == global_system_variables.server_id &&
- !rli->replicate_same_server_id) ||
+ !(rli->replicate_same_server_id || (flags & LOG_EVENT_ACCEPT_OWN_F))) ||
(rli->slave_skip_counter == 1 && rli->is_in_group()) ||
(flags & LOG_EVENT_SKIP_REPLICATION_F &&
opt_replicate_events_marked_for_skip != RPL_SKIP_REPLICATE))
@@ -3261,10 +3261,13 @@ bool Binlog_checkpoint_log_event::write()
Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
uint32 domain_id_arg, bool standalone,
uint16 flags_arg, bool is_transactional,
- uint64 commit_id_arg)
+ uint64 commit_id_arg, bool has_xid,
+ bool ro_1pc)
: Log_event(thd_arg, flags_arg, is_transactional),
seq_no(seq_no_arg), commit_id(commit_id_arg), domain_id(domain_id_arg),
- flags2((standalone ? FL_STANDALONE : 0) | (commit_id_arg ? FL_GROUP_COMMIT_ID : 0))
+ flags2((standalone ? FL_STANDALONE : 0) |
+ (commit_id_arg ? FL_GROUP_COMMIT_ID : 0)),
+ flags_extra(0), extra_engines(0)
{
cache_type= Log_event::EVENT_NO_CACHE;
bool is_tmp_table= thd_arg->lex->stmt_accessed_temp_table();
@@ -3287,15 +3290,40 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
flags2|= (thd_arg->rgi_slave->gtid_ev_flags2 & (FL_DDL|FL_WAITED));
XID_STATE &xid_state= thd->transaction->xid_state;
- if (is_transactional && xid_state.is_explicit_XA() &&
- (thd->lex->sql_command == SQLCOM_XA_PREPARE ||
- xid_state.get_state_code() == XA_PREPARED))
+ if (is_transactional)
{
- DBUG_ASSERT(thd->lex->xa_opt != XA_ONE_PHASE);
+ if (xid_state.is_explicit_XA() &&
+ (thd->lex->sql_command == SQLCOM_XA_PREPARE ||
+ xid_state.get_state_code() == XA_PREPARED))
+ {
+ DBUG_ASSERT(thd->lex->xa_opt != XA_ONE_PHASE);
+
+ flags2|= thd->lex->sql_command == SQLCOM_XA_PREPARE ?
+ FL_PREPARED_XA : FL_COMPLETED_XA;
+ xid.set(xid_state.get_xid());
+ }
+ /* count non-zero extra recoverable engines; total = extra + 1 */
+ if (has_xid)
+ {
+ DBUG_ASSERT(ha_count_rw_2pc(thd_arg,
+ thd_arg->in_multi_stmt_transaction_mode()));
+
+ extra_engines=
+ ha_count_rw_2pc(thd_arg, thd_arg->in_multi_stmt_transaction_mode()) - 1;
+ }
+ else if (ro_1pc)
+ {
+ extra_engines= UCHAR_MAX;
+ }
+ else if (thd->lex->sql_command == SQLCOM_XA_PREPARE)
+ {
+ DBUG_ASSERT(thd_arg->in_multi_stmt_transaction_mode());
- flags2|= thd->lex->sql_command == SQLCOM_XA_PREPARE ?
- FL_PREPARED_XA : FL_COMPLETED_XA;
- xid.set(xid_state.get_xid());
+ uint8 count= ha_count_rw_2pc(thd_arg, true);
+ extra_engines= count > 1 ? 0 : UCHAR_MAX;
+ }
+ if (extra_engines > 0)
+ flags_extra|= FL_EXTRA_MULTI_ENGINE;
}
}
@@ -3339,19 +3367,19 @@ Gtid_log_event::peek(const uchar *event_start, size_t event_len,
bool
Gtid_log_event::write()
{
- uchar buf[GTID_HEADER_LEN+2+sizeof(XID)];
- size_t write_len;
+ uchar buf[GTID_HEADER_LEN+2+sizeof(XID) + /* flags_extra: */ 1+4];
+ size_t write_len= 13;
int8store(buf, seq_no);
int4store(buf+8, domain_id);
buf[12]= flags2;
if (flags2 & FL_GROUP_COMMIT_ID)
{
- int8store(buf+13, commit_id);
+ DBUG_ASSERT(write_len + 8 == GTID_HEADER_LEN + 2);
+
+ int8store(buf+write_len, commit_id);
write_len= GTID_HEADER_LEN + 2;
}
- else
- write_len= 13;
if (flags2 & (FL_PREPARED_XA | FL_COMPLETED_XA))
{
@@ -3363,6 +3391,16 @@ Gtid_log_event::write()
memcpy(buf+write_len, xid.data, data_length);
write_len+= data_length;
}
+ if (flags_extra > 0)
+ {
+ buf[write_len]= flags_extra;
+ write_len++;
+ }
+ if (flags_extra & FL_EXTRA_MULTI_ENGINE)
+ {
+ buf[write_len]= extra_engines;
+ write_len++;
+ }
if (write_len < GTID_HEADER_LEN)
{