Bug #333 3 binlogging bugs when doing INSERT with mixed InnoDB / MyISAM

Submitted: 26 Apr 2003 13:49 Modified: 22 Aug 2003 7:08
Reporter: Guilhem Bichot Email Updates:
Status: Won't fix Impact on me:
None 
Category:MySQL Server: Replication Severity:S2 (Serious)
Version:4.0 OS:Any (all)
Assigned to: Guilhem Bichot CPU Architecture:Any

[26 Apr 2003 13:49] Guilhem Bichot
Description:
Hi,

Heikki recently (April 3rd) reported some of these bugs, here are the results of tests I have
run in 4.1. They are worrying and we probably have to fix this.

M is a MyISAM table, I an InnoDB table.

1) First bug

MASTER> reset master;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table M;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table I;
Query OK, 0 rows affected (0.00 sec)

MASTER> begin;
Query OK, 0 rows affected (0.00 sec)

MASTER> insert into I values(10);
Query OK, 1 row affected (0.00 sec)

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M

MASTER> insert into M select * from I;
Query OK, 1 row affected (0.02 sec)
Records: 1  Duplicates: 0  Warnings: 0

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M
| gbichot-bin.000001 | 130 | Query      |         1 |          130 | use `test`; insert into M select * from I        |

MASTER> select * from I;
+------+
| a    |
+------+
|   10 |
+------+
1 row in set (0.00 sec)

MASTER> rollback;
Query OK, 0 rows affected (0.00 sec)

MASTER> select * from I;
+------+
| a    |
+------+
|   10 |
+------+
1 row in set (0.00 sec)

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M

As you see, updating a MyISAM table inside a transaction silently commits the
transaction, which is very good. But the cached binlog lines are never written to the file binlog (because of ROLLBACK), so insert into I values(10);
is lost, while it affected M, and the slave is different from the master =>bug.

2) Another one (the same but with COMMIT instead of ROLLBACK) :

MASTER> reset master;
Query OK, 0 rows affected (0.00 sec)

MASTER> begin;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table M;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table I;
Query OK, 1 row affected (0.00 sec)

MASTER> insert into I values(10);
Query OK, 1 row affected (0.00 sec)

MASTER> insert into M select * from I;
Query OK, 1 row affected (0.01 sec)
Records: 1  Duplicates: 0  Warnings: 0

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M

MASTER> commit;
Query OK, 0 rows affected (0.00 sec)

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M
| gbichot-bin.000001 | 130 | Query      |         1 |          130 | use `test`; insert into M select * from I        |
| gbichot-bin.000001 | 194 | Query      |         1 |          194 | use `test`; BEGIN
| gbichot-bin.000001 | 234 | Query      |         1 |          130 | use `test`; truncate table I
| gbichot-bin.000001 | 285 | Query      |         1 |          130 | use `test`; insert into I values(10)
| gbichot-bin.000001 | 344 | Query      |         1 |          344 | use `test`; COMMIT

As you see order is wrong and this breaks replication as well.

3) Another one :

MASTER> reset master;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table M;
Query OK, 0 rows affected (0.00 sec)

MASTER> truncate table I;
Query OK, 1 row affected (0.01 sec)

MASTER> begin;
Query OK, 0 rows affected (0.00 sec)

MASTER> insert into I select * from M;
Query OK, 0 rows affected (0.00 sec)
Records: 0  Duplicates: 0  Warnings: 0

MASTER> commit;
Query OK, 0 rows affected (0.00 sec)

MASTER> select * from I;
Empty set (0.00 sec)

MASTER> show binlog events;
| gbichot-bin.000001 |  79 | Query      |         1 |           79 | use `test`; truncate table M
| gbichot-bin.000001 | 130 | Query      |         1 |          130 | use `test`; truncate table I
| gbichot-bin.000001 | 181 | Query      |         1 |          181 | use `test`; insert into M values(1000)
| gbichot-bin.000001 | 242 | Query      |         1 |          242 | use `test`; BEGIN
| gbichot-bin.000001 | 282 | Query      |         1 |          181 | use `test`; insert into I select * from M        |
| gbichot-bin.000001 | 346 | Query      |         1 |          346 | use `test`; COMMIT

Between the' insert into I select * from M;' and the 'commit;',
I opened another connection and did 'insert into M values(1000);'.
And this last INSERT was immediately written to the binlog, hence the bad order. The last INSERT could have been blocked by read-locking M when the INSERT SELECT was issued.
As you see the order in the binlog is wrong again.

How to repeat:

Suggested fix:
Proposed solutions :

To fix 1) and 2) : as there is a silent commit, do all what a real COMMIT does,
i.e. flush the cached binlog entry to the file binlog. Probably very easy to do.

To fix 3) : as we do when the SELECTed table is InnoDB : lock the SELECTed data
until the INSERT SELECT is commited. As the read table is MyISAM, this means
taking a READ lock on the MyISAM table.
[26 Apr 2003 13:50] Guilhem Bichot
I already sent an email to Monty for comments he may have.
[26 Apr 2003 13:51] Guilhem Bichot
Comment by Heikki:

Guilhem,

I recently changed the code in 4.0 so that an insert to a MyISAM table no
longer silently commits the InnoDB transaction:
ha_report_binlog_offset_and_commit() is no longer called if (1) we are
writing directly to the binlog and (2) there is data in the binlog cache of
the trx. That was because a user complained about that 'feature'.
[27 Apr 2003 12:01] Michael Widenius
This is one of the non fixable things when mixing transactional and non transactional tables.

I have update the manual to reflect this.
[19 Aug 2003 1:09] Guilhem Bichot
First and second bug could be fixed like this:
when, in a transaction, a non-transactional table is updated, write the statement to the binlog cache (don't immediately write the statement to binlog, like it is now, which is a serious bug); if rollback occurs, write the binlog cache to the binlog, but with a ending ROLLBACK.
[22 Aug 2003 7:08] Guilhem Bichot
sub-bugs 1 & 2 (i.e. the cases which are in a single connection) are fixed in
ChangeSet@1.1576.4.1, 2003-08-22 15:39:24+02:00, guilhem@mysql.com in MySQL 4.0.15.
sub-bug 3 (where 2 concurrent connections are involved) will not be fixed until we have row-level logging.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.054 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.