1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Bug #40116: Uncommited changes are replicated and stay on slave

after rollback on master

When starting a transaction with a statement containing changes
to both transactional tables and non-transactional tables, the
statement is considered as non-transactional and is therefore
written directly to the binary log. This behaviour was present
in 5.0, and has propagated to 5.1.

If a trigger containing a change of a non-transactional table is
added to a transactional table, any changes to the transactional
table is "tainted" as non-transactional.

This patch solves the problem by removing the existing "hack" that
allows non-transactional statements appearing first in a transaction
to be written directly to the binary log. Instead, anything inside
a transaction is treaded as part of the transaction and not written
to the binary log until the transaction is committed.
This commit is contained in:
Mats Kindahl
2008-12-03 20:55:49 +01:00
parent 5a897c8b4e
commit 82757fdfc0
8 changed files with 152 additions and 126 deletions

View File

@ -1478,60 +1478,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
}
/*
Decision table for committing a transaction. The top part, the
*conditions* represent different cases that can occur, and hte
bottom part, the *actions*, represent what should be done in that
particular case.
We commit the transaction if:
Real transaction 'all' was true
- We are not in a transaction and committing a statement, or
Statement in cache There were at least one statement in the
transaction cache
In transaction We are inside a transaction
Stmt modified non-trans The statement being committed modified a
non-transactional table
All modified non-trans Some statement before this one in the
transaction modified a non-transactional
table
============================= = = = = = = = = = = = = = = = =
Real transaction N N N N N N N N N N N N N N N N
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
Action: (C)ommit/(A)ccumulate C C - C A C - C - - - - A A - A
============================= = = = = = = = = = = = = = = = =
============================= = = = = = = = = = = = = = = = =
Real transaction Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
Statement in cache N N N N N N N N Y Y Y Y Y Y Y Y
In transaction N N N N Y Y Y Y N N N N Y Y Y Y
Stmt modified non-trans N N Y Y N N Y Y N N Y Y N N Y Y
All modified non-trans N Y N Y N Y N Y N Y N Y N Y N Y
(C)ommit/(A)ccumulate/(-) - - - - C C - C - - - - C C - C
============================= = = = = = = = = = = = = = = = =
In other words, we commit the transaction if and only if both of
the following are true:
- We are not in a transaction and committing a statement
- We are in a transaction and one (or more) of the following are
true:
- A full transaction is committed
OR
- A non-transactional statement is committed and there is
no statement cached
- We are in a transaction and a full transaction is committed
Otherwise, we accumulate the statement
*/
@ -1544,11 +1495,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
YESNO(in_transaction),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
if (in_transaction &&
(all ||
(!trx_data->at_least_one_stmt &&
thd->transaction.stmt.modified_non_trans_table)) ||
!in_transaction && !all)
if (!in_transaction || all)
{
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)