Commit 9755f072 authored by Mats Kindahl's avatar Mats Kindahl

Bug #32709: Assertion failed: trx_data->empty(), file log.cc

The assertion indicates that some data was left in the transaction
cache when the server was shut down, which means that a previous
statement did not commit or rollback correctly.

What happened was that a bug in the rollback of a transactional
table caused the transaction cache to be emptied, but not reset.
The error can be triggered by having a failing UPDATE or INSERT,
on a transactional table, causing an implicit rollback.

Fixed by always flushing the pending event to reset the state
properly.
parent 83ce448c
......@@ -451,3 +451,23 @@ connection master;
drop table t1, t2, t3, t4, t5, t6, t7;
sync_slave_with_master;
#
# BUG#32709: Assertion failed: trx_data->empty(), file .\log.cc, line 1293
#
connection master;
eval CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=$type;
INSERT INTO t1 VALUES (1), (2), (3);
--error ER_DUP_ENTRY
UPDATE t1 SET a = 10;
INSERT INTO t1 VALUES (4);
sync_slave_with_master;
let $diff_table_1=master:test.t1;
let $diff_table_2=slave:test.t1;
source include/diff_tables.inc;
connection master;
drop table t1;
sync_slave_with_master;
......@@ -520,3 +520,10 @@ INSERT INTO t7 VALUES (1, "", 1);
INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
Comparing tables master:test.t7 and slave:test.t7
drop table t1, t2, t3, t4, t5, t6, t7;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE='MYISAM' ;
INSERT INTO t1 VALUES (1), (2), (3);
UPDATE t1 SET a = 10;
ERROR 23000: Duplicate entry '10' for key 'PRIMARY'
INSERT INTO t1 VALUES (4);
Comparing tables master:test.t1 and slave:test.t1
drop table t1;
......@@ -520,3 +520,10 @@ INSERT INTO t7 VALUES (1, "", 1);
INSERT INTO t7 VALUES (2, repeat(_utf8'a', 255), 2);
Comparing tables master:test.t7 and slave:test.t7
drop table t1, t2, t3, t4, t5, t6, t7;
CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE='INNODB' ;
INSERT INTO t1 VALUES (1), (2), (3);
UPDATE t1 SET a = 10;
ERROR 23000: Duplicate entry '10' for key 'PRIMARY'
INSERT INTO t1 VALUES (4);
Comparing tables master:test.t1 and slave:test.t1
drop table t1;
......@@ -1421,6 +1421,7 @@ binlog_end_trans(THD *thd, binlog_trx_data *trx_data,
If rolling back a statement in a transaction, we truncate the
transaction cache to remove the statement.
*/
thd->binlog_remove_pending_rows_event(TRUE);
if (all || !(thd->options & (OPTION_BEGIN | OPTION_NOT_AUTOCOMMIT)))
trx_data->reset();
else // ...statement
......@@ -3769,6 +3770,31 @@ THD::binlog_set_pending_rows_event(Rows_log_event* ev)
}
/**
Remove the pending rows event, discarding any outstanding rows.
If there is no pending rows event available, this is effectively a
no-op.
*/
int
MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd)
{
DBUG_ENTER(__FUNCTION__);
binlog_trx_data *const trx_data=
(binlog_trx_data*) thd_get_ha_data(thd, binlog_hton);
DBUG_ASSERT(trx_data);
if (Rows_log_event* pending= trx_data->pending())
{
delete pending;
trx_data->set_pending(NULL);
}
DBUG_RETURN(0);
}
/*
Moves the last bunch of rows from the pending Rows event to the binlog
(either cached binlog if transaction, or disk binlog). Sets a new pending
......
......@@ -307,6 +307,7 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
void update_table_map_version() { ++m_table_map_version; }
int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event);
int remove_pending_rows_event(THD *thd);
#endif /* !defined(MYSQL_CLIENT) */
void reset_bytes_written()
......
......@@ -3502,6 +3502,21 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
}
int THD::binlog_remove_pending_rows_event(bool clear_maps)
{
DBUG_ENTER(__FUNCTION__);
if (!mysql_bin_log.is_open())
DBUG_RETURN(0);
mysql_bin_log.remove_pending_rows_event(this);
if (clear_maps)
binlog_table_maps= 0;
DBUG_RETURN(0);
}
int THD::binlog_flush_pending_rows_event(bool stmt_end)
{
DBUG_ENTER("THD::binlog_flush_pending_rows_event");
......
......@@ -1360,6 +1360,7 @@ class THD :public Statement,
Rows_log_event* binlog_get_pending_rows_event() const;
void binlog_set_pending_rows_event(Rows_log_event* ev);
int binlog_flush_pending_rows_event(bool stmt_end);
int binlog_remove_pending_rows_event(bool clear_maps);
private:
uint binlog_table_maps; // Number of table maps currently in the binlog
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment