| 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.
