mirror of
https://github.com/MariaDB/server.git
synced 2026-05-09 08:34:28 +02:00
MDEV-36143 Row event replication with Aria does not honour BLOCK_COMMIT
This commit fixes a bug where Aria tables are used in (master->slave1->slave2) and a backup is taken on slave2. In this case it is possible that the replication position in the backup, stored in mysql.gtid_slave_pos, will be wrong. This will lead to replication errors if one is trying to use the backup as a new slave. Analyze: Replicated row events are committed with trans_commit_stmt() and thd->transaction->all.ha_list != 0. This means that backup_commit_lock is not taken for Aria tables, which means the rows are committed and binary logged on the slave under BLOCK_COMMIT which should not happen. This issue does not occur on the master as thd->transaction->all.ha_list is == 0 under AUTO_COMMIT, which sets 'is_real_trans' and 'rw_trans' which in turn causes backup_commit_lock to be taken. Fixed by checking in ha_check_and_coalesce_trx_read_only() if all handlers supports rollback and if not, then wait for BLOCK_COMMIT also for statement commit.
This commit is contained in:
parent
f533333f82
commit
22024da64e
5 changed files with 50 additions and 8 deletions
|
|
@ -266,6 +266,7 @@ col1
|
|||
SET AUTOCOMMIT = 0;
|
||||
UPDATE t_permanent_innodb SET col1 = 9;
|
||||
UPDATE t_permanent_aria SET col1 = 9;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
UPDATE t_permanent_myisam SET col1 = 9;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
UPDATE t_permanent_aria2 SET col1 = 9;
|
||||
|
|
|
|||
|
|
@ -328,6 +328,7 @@ select * from t_permanent_aria2;
|
|||
|
||||
SET AUTOCOMMIT = 0;
|
||||
UPDATE t_permanent_innodb SET col1 = 9;
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
UPDATE t_permanent_aria SET col1 = 9;
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
UPDATE t_permanent_myisam SET col1 = 9;
|
||||
|
|
|
|||
|
|
@ -1586,6 +1586,12 @@ uint ha_count_rw_2pc(THD *thd, bool all)
|
|||
/**
|
||||
Check if we can skip the two-phase commit.
|
||||
|
||||
@param thd Thread handler
|
||||
@param ha_list List of all engines participating on the commit
|
||||
@param all True if this is final commit (not statement commit)
|
||||
@param no_rollback Set to 1 if one of the engines doing writes does
|
||||
not support rollback
|
||||
|
||||
A helper function to evaluate if two-phase commit is mandatory.
|
||||
As a side effect, propagates the read-only/read-write flags
|
||||
of the statement transaction to its enclosing normal transaction.
|
||||
|
|
@ -1604,16 +1610,21 @@ uint ha_count_rw_2pc(THD *thd, bool all)
|
|||
|
||||
uint
|
||||
ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
||||
bool all)
|
||||
bool all, bool *no_rollback)
|
||||
{
|
||||
/* The number of storage engines that have actual changes. */
|
||||
unsigned rw_ha_count= 0;
|
||||
Ha_trx_info *ha_info;
|
||||
|
||||
*no_rollback= false;
|
||||
for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
|
||||
{
|
||||
if (ha_info->is_trx_read_write())
|
||||
{
|
||||
++rw_ha_count;
|
||||
if (ha_info->is_trx_no_rollback())
|
||||
*no_rollback= true;
|
||||
}
|
||||
|
||||
if (! all)
|
||||
{
|
||||
|
|
@ -1636,7 +1647,18 @@ ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
|||
information up, and the need for two-phase commit has been
|
||||
already established. Break the loop prematurely.
|
||||
*/
|
||||
break;
|
||||
if (*no_rollback == 0)
|
||||
{
|
||||
while ((ha_info= ha_info->next()))
|
||||
{
|
||||
if (ha_info->is_trx_read_write() && ha_info->is_trx_no_rollback())
|
||||
{
|
||||
*no_rollback= 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rw_ha_count;
|
||||
|
|
@ -1771,7 +1793,9 @@ int ha_commit_trans(THD *thd, bool all)
|
|||
if (is_real_trans) /* not a statement commit */
|
||||
thd->stmt_map.close_transient_cursors();
|
||||
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
|
||||
bool no_rollback;
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all,
|
||||
&no_rollback);
|
||||
/* rw_trans is TRUE when we in a transaction changing data */
|
||||
bool rw_trans= is_real_trans && rw_ha_count > 0;
|
||||
MDL_request mdl_backup;
|
||||
|
|
@ -1784,7 +1808,7 @@ int ha_commit_trans(THD *thd, bool all)
|
|||
calling ha_commit_trans() from spader_commit().
|
||||
*/
|
||||
|
||||
if (rw_trans && !thd->backup_commit_lock)
|
||||
if ((rw_trans || no_rollback) && !thd->backup_commit_lock)
|
||||
{
|
||||
/*
|
||||
Acquire a metadata lock which will ensure that COMMIT is blocked
|
||||
|
|
@ -2114,7 +2138,9 @@ int ha_commit_one_phase(THD *thd, bool all)
|
|||
static bool is_ro_1pc_trans(THD *thd, Ha_trx_info *ha_info, bool all,
|
||||
bool is_real_trans)
|
||||
{
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
|
||||
bool no_rollback;
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, ha_info, all,
|
||||
&no_rollback);
|
||||
bool rw_trans= is_real_trans &&
|
||||
(rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
|
||||
|
||||
|
|
@ -5145,6 +5171,9 @@ void handler::mark_trx_read_write_internal()
|
|||
*/
|
||||
if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE)
|
||||
ha_info->set_trx_read_write();
|
||||
/* Mark if we are using a table that cannot do rollback */
|
||||
if (ht->flags & HTON_NO_ROLLBACK)
|
||||
ha_info->set_trx_no_rollback();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2014,6 +2014,16 @@ public:
|
|||
DBUG_ASSERT(is_started());
|
||||
return m_flags & (int) TRX_READ_WRITE;
|
||||
}
|
||||
void set_trx_no_rollback()
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
m_flags|= (int) TRX_NO_ROLLBACK;
|
||||
}
|
||||
bool is_trx_no_rollback() const
|
||||
{
|
||||
DBUG_ASSERT(is_started());
|
||||
return m_flags & (int) TRX_NO_ROLLBACK;
|
||||
}
|
||||
bool is_started() const { return m_ht != NULL; }
|
||||
/** Mark this transaction read-write if the argument is read-write. */
|
||||
void coalesce_trx_with(const Ha_trx_info *stmt_trx)
|
||||
|
|
@ -2038,7 +2048,7 @@ public:
|
|||
return m_ht;
|
||||
}
|
||||
private:
|
||||
enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 };
|
||||
enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1, TRX_NO_ROLLBACK= 2 };
|
||||
/** Auxiliary, used for ha_list management */
|
||||
Ha_trx_info *m_next;
|
||||
/**
|
||||
|
|
@ -5531,7 +5541,7 @@ uint ha_count_rw_all(THD *thd, Ha_trx_info **ptr_ha_info);
|
|||
bool non_existing_table_error(int error);
|
||||
uint ha_count_rw_2pc(THD *thd, bool all);
|
||||
uint ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
||||
bool all);
|
||||
bool all, bool *no_rollback);
|
||||
|
||||
int get_select_field_pos(Alter_info *alter_info, int select_field_count,
|
||||
bool versioned);
|
||||
|
|
|
|||
|
|
@ -1446,7 +1446,8 @@ bool wsrep_check_mode_after_open_table (THD *thd,
|
|||
}
|
||||
|
||||
// Check are we inside a transaction
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, thd->transaction->all.ha_list, true);
|
||||
bool not_used;
|
||||
uint rw_ha_count= ha_check_and_coalesce_trx_read_only(thd, thd->transaction->all.ha_list, true, ¬_used);
|
||||
bool changes= wsrep_has_changes(thd);
|
||||
|
||||
// Roll back current stmt if exists
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue