diff options
author | unknown <knielsen@knielsen-hq.org> | 2014-06-03 10:31:11 +0200 |
---|---|---|
committer | Kristian Nielsen <knielsen@knielsen-hq.org> | 2014-06-03 10:31:11 +0200 |
commit | 629b822913348cec56ec7a80a236f0ba2e613585 (patch) | |
tree | 8c713a0ad975deb8b6764af03b1cca8e8cd195db /sql/rpl_rli.h | |
parent | 787c470cef54574e744eb5dfd9153d837fe67e45 (diff) | |
download | mariadb-git-629b822913348cec56ec7a80a236f0ba2e613585.tar.gz |
MDEV-5262, MDEV-5914, MDEV-5941, MDEV-6020: Deadlocks during parallel
replication causing replication to fail.
In parallel replication, we run transactions from the master in parallel, but
force them to commit in the same order they did on the master. If we force T1
to commit before T2, but T2 holds eg. a row lock that is needed by T1, we get
a deadlock when T2 waits until T1 has committed.
Usually, we do not run T1 and T2 in parallel if there is a chance that they
can have conflicting locks like this, but there are certain edge cases where
it can occasionally happen (eg. MDEV-5914, MDEV-5941, MDEV-6020). The bug was
that this would cause replication to hang, eventually getting a lock timeout
and causing the slave to stop with error.
With this patch, InnoDB will report back to the upper layer whenever a
transactions T1 is about to do a lock wait on T2. If T1 and T2 are parallel
replication transactions, and T2 needs to commit later than T1, we can thus
detect the deadlock; we then kill T2, setting a flag that causes it to catch
the kill and convert it to a deadlock error; this error will then cause T2 to
roll back and release its locks (so that T1 can commit), and later T2 will be
re-tried and eventually also committed.
The kill happens asynchroneously in a slave background thread; this is
necessary, as the reporting from InnoDB about lock waits happen deep inside
the locking code, at a point where it is not possible to directly call
THD::awake() due to mutexes held.
Deadlock is assumed to be (very) rarely occuring, so this patch tries to
minimise the performance impact on the normal case where no deadlocks occur,
rather than optimise the handling of the occasional deadlock.
Also fix transaction retry due to deadlock when it happens after a transaction
already signalled to later transactions that it started to commit. In this
case we need to undo this signalling (and later redo it when we commit again
during retry), so following transactions will not start too early.
Also add a missing thd->send_kill_message() that got triggered during testing
(this corrects an incorrect fix for MySQL Bug#58933).
Diffstat (limited to 'sql/rpl_rli.h')
-rw-r--r-- | sql/rpl_rli.h | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 932db0a0b7d..b44e794a795 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -646,6 +646,7 @@ struct rpl_group_info inuse_relaylog *relay_log; uint64 retry_start_offset; uint64 retry_event_count; + bool killed_for_retry; rpl_group_info(Relay_log_info *rli_); ~rpl_group_info(); @@ -735,6 +736,7 @@ struct rpl_group_info void mark_start_commit_no_lock(); void mark_start_commit(); char *gtid_info(); + void unmark_start_commit(); time_t get_row_stmt_start_timestamp() { |