Bug #44163 | On blackhole engine table autoincrement always returns `1` | ||
---|---|---|---|
Submitted: | 8 Apr 2009 18:09 | Modified: | 27 May 2010 9:23 |
Reporter: | Sorin Panca | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: Documentation | Severity: | S2 (Serious) |
Version: | 5.1.32, 5.0, 5.1.46, 5.6.99 | OS: | Any (FreeBSD, Linux) |
Assigned to: | Tony Bedford | CPU Architecture: | Any |
Tags: | autoincrement, blackhole |
[8 Apr 2009 18:09]
Sorin Panca
[9 Apr 2009 7:11]
Valeriy Kravchuk
Thank you for the problem report. What kind of replication do you use, statement-based or row-based?
[9 Apr 2009 11:06]
Sorin Panca
We're using mixed replication.
[4 May 2009 15:07]
Susanne Ebrecht
Many thanks for writing a bug report. Unfortunately this is not a bug because of storage engine blackhole. For getting other values then 1 please use statement based replication.
[5 May 2009 11:17]
Sorin Panca
I know you like facts, so here they are: sorin@ws39 ~ $ mysql -hbhdb1 # my blackhole master server Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 120365 Server version: 5.1.30-log FreeBSD port: mysql-server-5.1.30 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> set global binlog_format='STATEMENT'; Query OK, 0 rows affected (0.12 sec) mysql> SHOW GLOBAL VARIABLES LIKE 'binlog_format'; +---------------+-----------+ | Variable_name | Value | +---------------+-----------+ | binlog_format | STATEMENT | +---------------+-----------+ 1 row in set (0.12 sec) mysql> CREATE TABLE pr.sorin (a INT AUTO_INCREMENT, PRIMARY KEY (`a`)) ENGINE=BLACKHOLE; Query OK, 0 rows affected (0.14 sec) mysql> Bye sorin@ws39 ~ $ mysql -hdb1 # one of the slaves Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 338323 Server version: 5.1.30-log FreeBSD port: mysql-server-5.1.30 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> show create table pr.sorin; +-------+-----------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+-----------------------------------------------------------------------------------------------------------------------------+ | sorin | CREATE TABLE `sorin` ( `a` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`a`) ) ENGINE=BLACKHOLE DEFAULT CHARSET=latin1 | +-------+-----------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.14 sec) mysql> alter table pr.sorin ENGINE=MyISAM; Query OK, 0 rows affected (0.14 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> show create table pr.sorin; +-------+--------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +-------+--------------------------------------------------------------------------------------------------------------------------+ | sorin | CREATE TABLE `sorin` ( `a` int(11) NOT NULL AUTO_INCREMENT, PRIMARY KEY (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 | +-------+--------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.12 sec) mysql> Bye sorin@ws39 ~ $ mysql -hbhdb1 # on master again Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 120370 Server version: 5.1.30-log FreeBSD port: mysql-server-5.1.30 Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> use pr; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> alter table sorin add ( b int); Query OK, 0 rows affected (0.15 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> insert into sorin (b) values ( 1 ); Query OK, 1 row affected (0.12 sec) mysql> insert into sorin (b) values ( 1 ); Query OK, 1 row affected (0.12 sec) mysql> select * from sorin; Empty set (0.12 sec) mysql> Bye sorin@ws39 ~ $ mysql -db1 # now on the slave.... mysql> select * from pr.sorin; +---+------+ | a | b | +---+------+ | 1 | 1 | +---+------+ 1 row in set (0.11 sec) mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: bhdb1.psrk.com Master_User: website Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin.000186 Read_Master_Log_Pos: 665968451 Relay_Log_File: db1-relay-bin.000569 Relay_Log_Pos: 665946381 Relay_Master_Log_File: mysql-bin.000186 Slave_IO_Running: Yes Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 1062 Last_Error: Error 'Duplicate entry '1' for key 'PRIMARY'' on query. Default database: 'pr'. Query: 'insert into sorin (b) values ( 1 )' Skip_Counter: 0 Exec_Master_Log_Pos: 665946236 Relay_Log_Space: 665968792 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 2013 Last_IO_Error: error reconnecting to master 'replication@bhdb1.psrk.com:3306' - retry-time: 60 retries: 86400 Last_SQL_Errno: 1062 Last_SQL_Error: Error 'Duplicate entry '1' for key 'PRIMARY'' on query. Default database: 'pr'. Query: 'insert into sorin (b) values ( 1 )' 1 row in set (0.12 sec) ERROR: No query specified
[8 May 2009 17:45]
Sorin Panca
This is a feature request, not a bug...
[23 Feb 2010 12:29]
Sheeri Cabral
We have confirmed this on MysQL 5.1.37. It would be nice to be able to set an AUTOINCREMENT on a BLACKHOLE table and have it work properly. I believe this is a bug because BLACKHOLE shouldn't try to insert a value for AUTOINCREMENT -- it is BLACKHOLE, it should enter in NULL.
[23 Feb 2010 13:08]
Sheeri Cabral
We're using statement-based replication on MySQL 5.1.37 and it sets the INSERT_ID in the binary logs. This is a *bug*, as with statement-based replication the INSERT_ID should NOT be set by the master -- otherwise it is not BLACKHOLE, it is BLACKHOLE + [pointless] AUTOINCREMENT On Master: master [localhost] {msandbox} ((none)) > CREATE TABLE test_blackhole (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, field1 varchar(10), PRIMARY KEY (`id`)) ENGINE=BLACKHOLE; Query OK, 0 rows affected (0.03 sec) Altered to MyISAM on slave: slave1 [localhost] {msandbox} (test) > ALTER TABLE test_blackhole ENGINE=MyISAM; Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 master [localhost] {msandbox} (test) > SHOW VARIABLES LIKE '%format%'; +---------------------+-------------------+ | Variable_name | Value | +---------------------+-------------------+ | binlog_format | STATEMENT | master [localhost] {msandbox} (test) > INSERT INTO test_blackhole (field1) VALUES ('statement1'); Query OK, 1 row affected (0.00 sec) master [localhost] {msandbox} (test) > INSERT INTO test_blackhole (field1) VALUES ('statement2'); Query OK, 1 row affected (0.00 sec) master [localhost] {msandbox} (test) > INSERT INTO test_blackhole (field1) VALUES ('statement3'); Query OK, 1 row affected (0.00 sec) Checking binary log: BEGIN /*!*/; # at 3148 #100223 14:41:08 server id 1 end_log_pos 3176 Intvar SET INSERT_ID=1/*!*/; # at 3176 #100223 14:41:08 server id 1 end_log_pos 3296 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928868/*!*/; INSERT INTO test_blackhole (field1) VALUES ('statement1') /*!*/; # at 3296 #100223 14:41:08 server id 1 end_log_pos 3365 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928868/*!*/; COMMIT /*!*/; # at 3365 #100223 14:41:10 server id 1 end_log_pos 3433 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928870/*!*/; BEGIN /*!*/; # at 3433 #100223 14:41:10 server id 1 end_log_pos 3461 Intvar SET INSERT_ID=1/*!*/; # at 3461 #100223 14:41:10 server id 1 end_log_pos 3581 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928870/*!*/; INSERT INTO test_blackhole (field1) VALUES ('statement2') /*!*/; # at 3581 #100223 14:41:10 server id 1 end_log_pos 3650 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928870/*!*/; COMMIT /*!*/; # at 3650 #100223 14:41:13 server id 1 end_log_pos 3718 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928873/*!*/; BEGIN /*!*/; # at 3718 #100223 14:41:13 server id 1 end_log_pos 3746 Intvar SET INSERT_ID=1/*!*/; # at 3746 #100223 14:41:13 server id 1 end_log_pos 3866 Query thread_id=16 exec_time=0 error_code=0 SET TIMESTAMP=1266928873/*!*/; INSERT INTO test_blackhole (field1) VALUES ('statement3') All the INSERT_ID=1, which causes error on slave.
[4 Apr 2010 16:51]
Wes Biggs
I agree with the previous comment. This is definitely a bug that we see with binlog mode statement.
[4 Apr 2010 18:05]
MySQL Verification Team
maybe fix for bug #35178 wasn't implemented ideally?
[6 Apr 2010 6:16]
Sveta Smirnova
Thank you for the feedback. Verified as described. Problem is repeatable only if create table with single column, then issue alter table sorin add ( b int); If create table with 2 columns at first time everything works fine. Row-based replication does not help. Test case for MTR: --source include/master-slave.inc set global binlog_format='STATEMENT'; CREATE TABLE sorin (a INT AUTO_INCREMENT, PRIMARY KEY (`a`)) ENGINE=BLACKHOLE; sleep 1; connection slave; alter table sorin engine=myisam; connection master; alter table sorin add ( b int); insert into sorin(b) values(1); insert into sorin(b) values(2); insert into sorin(b) values(3); sleep 1; connection slave; select * from sorin; --vertical_results show slave status;
[9 Apr 2010 11:34]
Luis Soares
Hi! Blackhole engine is basically a no-op engine. So whatever you throw at it it will basically do nothing, and this is valid for auto increment fields as well. Therefore, if one does inserts without explicit auto increment values, the engine will not increment the field value for us, as well as it will not keep auto increment field state. This means that if setting up replication and: 1. on the master there is a blackhole table with an auto increment field (PK); 2. on the slave there's the same table in a MyISAM engine; 3. inserts are performed into the master's table, omitting the auto increment field (either by not setting the value explicitly or using SET INSERT_ID); replication will break. The reason it will break is somewhat different depending on the binary log formats. Assuming that the user does not set the value explicitly as mentioned in #3 above, this is how it will behave: - SBR - the INSERT_ID in the context event that precedes each insert will always be set to the same value . As a consequence, replication will break; - RBR - the value in the row that the engine returns for the auto increment field will always be the same for each insert, thence replication will break. Expanding analysis a bit, lets take the following test case: -- source include/master-slave.inc CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY, c2 int) ENGINE=BLACKHOLE; -- sync_slave_with_master ALTER TABLE t1 ENGINE=MyISAM; -- connection master SET INSERT_ID= 10; INSERT INTO t1(c2) VALUES (1); INSERT INTO t1(c2) VALUES (2); INSERT INTO t1(c2) VALUES (3); -- sync_slave_with_master SELECT * FROM t1; -- exit Now lets look at what happens in both binary log formats: SBR and RBR. SBR === Lets start by running the aforementioned test case: $ perl mysql-test-run.pl --mysqld=--binlog-format=statement rpl.bug44163 (...) INSERT INTO t1(c2) VALUES (2); INSERT INTO t1(c2) VALUES (3); rpl.rpl_x [ fail ] (...) Last_SQL_Errno 1062 Last_SQL_Error Error 'Duplicate entry '1' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'INSERT INTO t1(c2) VALUES (3)' (...) As we can see here the offending statement is the third insert. Looking a the output from the master's binary log, we can see that all three insert statements (as expected) are preceded by 'SET INSERT_ID': # at 314 #100409 11:53:32 server id 1 end_log_pos 342 Intvar SET INSERT_ID=10/*!*/; # at 342 #100409 11:53:32 server id 1 end_log_pos 434 Query thread_id=3 exec_time=0 error_code=0 SET TIMESTAMP=1270810412/*!*/; INSERT INTO t1(c2) VALUES (1) /*!*/; (...) # at 571 #100409 11:53:32 server id 1 end_log_pos 599 Intvar SET INSERT_ID=1/*!*/; # at 599 #100409 11:53:32 server id 1 end_log_pos 691 Query thread_id=3 exec_time=0 error_code=0 SET TIMESTAMP=1270810412/*!*/; INSERT INTO t1(c2) VALUES (2) /*!*/; (...) # at 828 #100409 11:53:32 server id 1 end_log_pos 856 Intvar SET INSERT_ID=1/*!*/; # at 856 #100409 11:53:32 server id 1 end_log_pos 948 Query thread_id=3 exec_time=0 error_code=0 SET TIMESTAMP=1270810412/*!*/; INSERT INTO t1(c2) VALUES (3) /*!*/; So we now see that the INSERT_ID is the same for the two last insert statements. And this is because blackhole does nothing, even wrt keeping auto increment state. RBR === Running the same test case but using row binary log format we get: $ perl mysql-test-run.pl --mysqld=--binlog-format=row rpl.bug44163 (...) INSERT INTO t1(c2) VALUES (2); INSERT INTO t1(c2) VALUES (3); rpl.rpl_x [ fail ] (...) Last_Errno 1062 Last_Error Could not execute Write_rows event on table test.t1; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log master-bin.000001, end_log_pos 828 (...) We cannot tell for sure what's the offending insert based on this output. So lets take a look at the binary log contents in the master: (...) ### INSERT INTO test.t1 ### SET ### @1=10 /* INT meta=0 nullable=0 is_null=0 */ ### @2=1 /* INT meta=0 nullable=1 is_null=0 */ (...) ### INSERT INTO test.t1 ### SET ### @1=1 /* INT meta=0 nullable=0 is_null=0 */ ### @2=2 /* INT meta=0 nullable=1 is_null=0 */ (...) ### INSERT INTO test.t1 ### SET ### @1=1 /* INT meta=0 nullable=0 is_null=0 */ ### @2=3 /* INT meta=0 nullable=1 is_null=0 */ (...) As we can see here, the third insert is the offending insert (as was the case in statement mode). What's happening here, however, is that the blackhole engine returns the same value for the inserted row when the auto increment field is omitted from the query. Consequently, the slave will replay the two Write_rows_log_event with the same value for the primary key field and thence it will stop. Conclusion ========== Given this analysis, the blackhole engine is intended to be mostly used in a relay slave scenario. It's usage as master's tables engines must take into account the pitfalls described. I would say this is not a bug. However, existing documentation on how blackhole engine and auto increments play together seems a bit short.
[27 May 2010 9:23]
Tony Bedford
The 5.0, 5.1, 5.4, 5.5, and 6.0 reference manuals have been updated. Section added on how Blackhole engine handles auto-increment columns, and implications for replication.