mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 19:37:16 +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;
|
SET AUTOCOMMIT = 0;
|
||||||
UPDATE t_permanent_innodb SET col1 = 9;
|
UPDATE t_permanent_innodb SET col1 = 9;
|
||||||
UPDATE t_permanent_aria 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;
|
UPDATE t_permanent_myisam SET col1 = 9;
|
||||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||||
UPDATE t_permanent_aria2 SET col1 = 9;
|
UPDATE t_permanent_aria2 SET col1 = 9;
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,7 @@ select * from t_permanent_aria2;
|
||||||
|
|
||||||
SET AUTOCOMMIT = 0;
|
SET AUTOCOMMIT = 0;
|
||||||
UPDATE t_permanent_innodb SET col1 = 9;
|
UPDATE t_permanent_innodb SET col1 = 9;
|
||||||
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
UPDATE t_permanent_aria SET col1 = 9;
|
UPDATE t_permanent_aria SET col1 = 9;
|
||||||
--error ER_LOCK_WAIT_TIMEOUT
|
--error ER_LOCK_WAIT_TIMEOUT
|
||||||
UPDATE t_permanent_myisam SET col1 = 9;
|
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.
|
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.
|
A helper function to evaluate if two-phase commit is mandatory.
|
||||||
As a side effect, propagates the read-only/read-write flags
|
As a side effect, propagates the read-only/read-write flags
|
||||||
of the statement transaction to its enclosing normal transaction.
|
of the statement transaction to its enclosing normal transaction.
|
||||||
|
|
@ -1604,16 +1610,21 @@ uint ha_count_rw_2pc(THD *thd, bool all)
|
||||||
|
|
||||||
uint
|
uint
|
||||||
ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
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. */
|
/* The number of storage engines that have actual changes. */
|
||||||
unsigned rw_ha_count= 0;
|
unsigned rw_ha_count= 0;
|
||||||
Ha_trx_info *ha_info;
|
Ha_trx_info *ha_info;
|
||||||
|
|
||||||
|
*no_rollback= false;
|
||||||
for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
|
for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
|
||||||
{
|
{
|
||||||
if (ha_info->is_trx_read_write())
|
if (ha_info->is_trx_read_write())
|
||||||
|
{
|
||||||
++rw_ha_count;
|
++rw_ha_count;
|
||||||
|
if (ha_info->is_trx_no_rollback())
|
||||||
|
*no_rollback= true;
|
||||||
|
}
|
||||||
|
|
||||||
if (! all)
|
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
|
information up, and the need for two-phase commit has been
|
||||||
already established. Break the loop prematurely.
|
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;
|
return rw_ha_count;
|
||||||
|
|
@ -1771,7 +1793,9 @@ int ha_commit_trans(THD *thd, bool all)
|
||||||
if (is_real_trans) /* not a statement commit */
|
if (is_real_trans) /* not a statement commit */
|
||||||
thd->stmt_map.close_transient_cursors();
|
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 */
|
/* rw_trans is TRUE when we in a transaction changing data */
|
||||||
bool rw_trans= is_real_trans && rw_ha_count > 0;
|
bool rw_trans= is_real_trans && rw_ha_count > 0;
|
||||||
MDL_request mdl_backup;
|
MDL_request mdl_backup;
|
||||||
|
|
@ -1784,7 +1808,7 @@ int ha_commit_trans(THD *thd, bool all)
|
||||||
calling ha_commit_trans() from spader_commit().
|
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
|
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,
|
static bool is_ro_1pc_trans(THD *thd, Ha_trx_info *ha_info, bool all,
|
||||||
bool is_real_trans)
|
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 &&
|
bool rw_trans= is_real_trans &&
|
||||||
(rw_ha_count > (thd->is_current_stmt_binlog_disabled()?0U:1U));
|
(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)
|
if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE)
|
||||||
ha_info->set_trx_read_write();
|
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());
|
DBUG_ASSERT(is_started());
|
||||||
return m_flags & (int) TRX_READ_WRITE;
|
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; }
|
bool is_started() const { return m_ht != NULL; }
|
||||||
/** Mark this transaction read-write if the argument is read-write. */
|
/** Mark this transaction read-write if the argument is read-write. */
|
||||||
void coalesce_trx_with(const Ha_trx_info *stmt_trx)
|
void coalesce_trx_with(const Ha_trx_info *stmt_trx)
|
||||||
|
|
@ -2038,7 +2048,7 @@ public:
|
||||||
return m_ht;
|
return m_ht;
|
||||||
}
|
}
|
||||||
private:
|
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 */
|
/** Auxiliary, used for ha_list management */
|
||||||
Ha_trx_info *m_next;
|
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);
|
bool non_existing_table_error(int error);
|
||||||
uint ha_count_rw_2pc(THD *thd, bool all);
|
uint ha_count_rw_2pc(THD *thd, bool all);
|
||||||
uint ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
|
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,
|
int get_select_field_pos(Alter_info *alter_info, int select_field_count,
|
||||||
bool versioned);
|
bool versioned);
|
||||||
|
|
|
||||||
|
|
@ -1446,7 +1446,8 @@ bool wsrep_check_mode_after_open_table (THD *thd,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check are we inside a transaction
|
// 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);
|
bool changes= wsrep_has_changes(thd);
|
||||||
|
|
||||||
// Roll back current stmt if exists
|
// Roll back current stmt if exists
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue