mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-8302: Duplicate key with parallel replication
This bug is essentially another variant of MDEV-7458. If a transaction conflict caused a deadlock kill of T2 in record_gtid() during commit, the code would do a rollback _before_ running rgi->unmark_start_commit(). This creates a race where following transactions could start too early (before T2 has completed its transaction retry). This in turn could lead to replication failure, if there was a conflict that caused eg. duplicate key error or similar. The fix is to remove these rollbacks (in Query_log_event::do_apply_event() and Xid_log_event::do_apply_event(). They seem out-of-place; code in log_event.cc generally does not roll back on error, this is handled higher up. In addition, because of the extreme difficulty of reproducing bugs like MDEV-7458 and MDEV-8302, this patch adds some extra precations to try to detect (in debug builds) or prevent (in release builds) similar bugs. ha_rollback_trans() will now call unmark_start_commit() if needed (and assert in debug build when a caller does rollback without unmark first). We also add an extra check for thd->killed() so that we avoid doing mark_start_commit() if we already have a pending deadlock kill. And we add a missing unmark_start_commit() call in the error case, found by the above assertion.
This commit is contained in:
@ -1582,6 +1582,24 @@ int ha_rollback_trans(THD *thd, bool all)
|
||||
DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL ||
|
||||
trans == &thd->transaction.stmt);
|
||||
|
||||
if (is_real_trans)
|
||||
{
|
||||
/*
|
||||
In parallel replication, if we need to rollback during commit, we must
|
||||
first inform following transactions that we are going to abort our commit
|
||||
attempt. Otherwise those following transactions can run too early, and
|
||||
possibly cause replication to fail. See comments in retry_event_group().
|
||||
|
||||
There were several bugs with this in the past that were very hard to
|
||||
track down (MDEV-7458, MDEV-8302). So we add here an assertion for
|
||||
rollback without signalling following transactions. And in release
|
||||
builds, we explicitly do the signalling before rolling back.
|
||||
*/
|
||||
DBUG_ASSERT(!(thd->rgi_slave && thd->rgi_slave->did_mark_start_commit));
|
||||
if (thd->rgi_slave && thd->rgi_slave->did_mark_start_commit)
|
||||
thd->rgi_slave->unmark_start_commit();
|
||||
}
|
||||
|
||||
if (thd->in_sub_stmt)
|
||||
{
|
||||
DBUG_ASSERT(0);
|
||||
|
Reference in New Issue
Block a user