Commit db1f9468 authored by unknown's avatar unknown

Bug#30919

  "Rows not deleted from innodb partitioned tables if --innodb_autoinc_lock_mode=0"

  Due to a previous bugfix which initializes a previously uninitialized
  variable, ha_partition::get_auto_increment() may fail to operate
  correctly when the storage engine reports that it is only reserving
  one value and one or more partitions have a different 'next-value'.
  Currently, only affects Innodb's new-style auto-increment code which
  reserves larger blocks of values and has less inter-thread contention.


mysql-test/suite/rpl/r/rpl_innodb_bug28430.result:
  Fix results - previous results shows symptoms of Bug30919
sql/ha_partition.cc:
  Bug30919
  
  ha_partition::write_row()
    Do not insert a row if a failure occurred while generating
    auto-increment value.
  
  ha_partition::get_auto_increment()
    If there is an empty 'intersection' of auto-increment values, perform
    a second pass before failing because partitions may have different
    auto-increment 'next-value' attributes.
storage/innobase/handler/ha_innodb.cc:
  Bug30919
    Only set *first_value if it is less than autoinc value. This allows
    a higher value to be hinted when operating as a partitioned table.
mysql-test/suite/rpl/r/rpl_innodb_bug30919.result:
  New BitKeeper file ``mysql-test/suite/rpl/r/rpl_innodb_bug30919.result''
mysql-test/suite/rpl/t/rpl_innodb_bug30919-master.opt:
  New BitKeeper file ``mysql-test/suite/rpl/t/rpl_innodb_bug30919-master.opt''
mysql-test/suite/rpl/t/rpl_innodb_bug30919.test:
  New BitKeeper file ``mysql-test/suite/rpl/t/rpl_innodb_bug30919.test''
parent 67a8e6a0
...@@ -101,10 +101,10 @@ SELECT count(*) as "Master regular" FROM test.regular_tbl; ...@@ -101,10 +101,10 @@ SELECT count(*) as "Master regular" FROM test.regular_tbl;
Master regular 500 Master regular 500
CALL test.proc_bykey(); CALL test.proc_bykey();
SELECT count(*) as "Master bykey" FROM test.bykey_tbl; SELECT count(*) as "Master bykey" FROM test.bykey_tbl;
Master bykey 811 Master bykey 500
CALL test.proc_byrange(); CALL test.proc_byrange();
SELECT count(*) as "Master byrange" FROM test.byrange_tbl; SELECT count(*) as "Master byrange" FROM test.byrange_tbl;
Master byrange 996 Master byrange 500
show create table test.byrange_tbl; show create table test.byrange_tbl;
Table byrange_tbl Table byrange_tbl
Create Table CREATE TABLE `byrange_tbl` ( Create Table CREATE TABLE `byrange_tbl` (
...@@ -123,9 +123,9 @@ Master_User root ...@@ -123,9 +123,9 @@ Master_User root
Master_Port 12000 Master_Port 12000
Connect_Retry 1 Connect_Retry 1
Master_Log_File master-bin.000001 Master_Log_File master-bin.000001
Read_Master_Log_Pos 776796 Read_Master_Log_Pos 945644
Relay_Log_File slave-relay-bin.000003 Relay_Log_File slave-relay-bin.000003
Relay_Log_Pos 776942 Relay_Log_Pos 945790
Relay_Master_Log_File master-bin.000001 Relay_Master_Log_File master-bin.000001
Slave_IO_Running Yes Slave_IO_Running Yes
Slave_SQL_Running Yes Slave_SQL_Running Yes
...@@ -138,8 +138,8 @@ Replicate_Wild_Ignore_Table ...@@ -138,8 +138,8 @@ Replicate_Wild_Ignore_Table
Last_Errno 0 Last_Errno 0
Last_Error Last_Error
Skip_Counter 0 Skip_Counter 0
Exec_Master_Log_Pos 776796 Exec_Master_Log_Pos 945644
Relay_Log_Space 777097 Relay_Log_Space 945945
Until_Condition None Until_Condition None
Until_Log_File Until_Log_File
Until_Log_Pos 0 Until_Log_Pos 0
...@@ -158,9 +158,9 @@ Last_SQL_Error ...@@ -158,9 +158,9 @@ Last_SQL_Error
SELECT count(*) "Slave norm" FROM test.regular_tbl; SELECT count(*) "Slave norm" FROM test.regular_tbl;
Slave norm 500 Slave norm 500
SELECT count(*) "Slave bykey" FROM test.bykey_tbl; SELECT count(*) "Slave bykey" FROM test.bykey_tbl;
Slave bykey 811 Slave bykey 500
SELECT count(*) "Slave byrange" FROM test.byrange_tbl; SELECT count(*) "Slave byrange" FROM test.byrange_tbl;
Slave byrange 996 Slave byrange 500
DROP PROCEDURE test.proc_norm; DROP PROCEDURE test.proc_norm;
DROP PROCEDURE test.proc_bykey; DROP PROCEDURE test.proc_bykey;
DROP PROCEDURE test.proc_byrange; DROP PROCEDURE test.proc_byrange;
......
This diff is collapsed.
--innodb --innodb_autoinc_lock_mode=0
--source include/have_innodb.inc
--vertical_results
let $engine_type= 'innodb';
###### CLEAN UP SECTION ##############
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
######## Creat Table Section #########
use test;
eval CREATE TABLE test.part_tbl(id MEDIUMINT NOT NULL AUTO_INCREMENT,
dt TIMESTAMP, user CHAR(255), uuidf LONGBLOB,
fkid MEDIUMINT, filler VARCHAR(255),
PRIMARY KEY(id)) ENGINE=$engine_type
PARTITION BY RANGE(id)
SUBPARTITION BY hash(id) subpartitions 2
(PARTITION pa3 values less than (42),
PARTITION pa6 values less than (60),
PARTITION pa7 values less than (70),
PARTITION pa8 values less than (80),
PARTITION pa9 values less than (90),
PARTITION pa10 values less than (100),
PARTITION pa11 values less than MAXVALUE);
######## Create SPs, Functions, Views and Triggers Section ##############
delimiter |;
CREATE PROCEDURE test.proc_part()
BEGIN
DECLARE ins_count INT DEFAULT 1000;
DECLARE del_count INT;
DECLARE cur_user VARCHAR(255);
DECLARE local_uuid VARCHAR(255);
DECLARE local_time TIMESTAMP;
SET local_time= NOW();
SET cur_user= CURRENT_USER();
SET local_uuid= UUID();
WHILE ins_count > 0 DO
INSERT INTO test.part_tbl VALUES (NULL, NOW(), USER() , UUID(),
ins_count,'Going to test MBR for MySQL');
SET ins_count = ins_count - 1;
END WHILE;
SELECT MAX(id) FROM test.part_tbl INTO del_count;
WHILE del_count > 0 DO
DELETE FROM test.part_tbl WHERE id = del_count;
select count(*) as internal_count, del_count -- these two lines are for
FROM test.part_tbl; -- debug to show the problem
SET del_count = del_count - 2;
END WHILE;
END|
delimiter ;|
############ Finish Setup Section ###################
############ Test Section ###################
--horizontal_results
CALL test.proc_part();
select count(*) as Part from test.part_tbl;
DROP PROCEDURE test.proc_part;
DROP TABLE test.part_tbl;
...@@ -2693,7 +2693,17 @@ int ha_partition::write_row(uchar * buf) ...@@ -2693,7 +2693,17 @@ int ha_partition::write_row(uchar * buf)
or a new row, then update the auto_increment value in the record. or a new row, then update the auto_increment value in the record.
*/ */
if (table->next_number_field && buf == table->record[0]) if (table->next_number_field && buf == table->record[0])
update_auto_increment(); {
error= update_auto_increment();
/*
If we have failed to set the auto-increment value for this row,
it is highly likely that we will not be able to insert it into
the correct partition. We must check and fail if neccessary.
*/
if (error)
DBUG_RETURN(error);
}
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set);
#ifdef NOT_NEEDED #ifdef NOT_NEEDED
...@@ -5456,8 +5466,10 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, ...@@ -5456,8 +5466,10 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
ulonglong first_value_part, last_value_part, nb_reserved_values_part, ulonglong first_value_part, last_value_part, nb_reserved_values_part,
last_value= ~ (ulonglong) 0; last_value= ~ (ulonglong) 0;
handler **pos, **end; handler **pos, **end;
bool retry= TRUE;
DBUG_ENTER("ha_partition::get_auto_increment"); DBUG_ENTER("ha_partition::get_auto_increment");
again:
for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++) for (pos=m_file, end= m_file+ m_tot_parts; pos != end ; pos++)
{ {
first_value_part= *first_value; first_value_part= *first_value;
...@@ -5466,7 +5478,8 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, ...@@ -5466,7 +5478,8 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
if (first_value_part == ~(ulonglong)(0)) // error in one partition if (first_value_part == ~(ulonglong)(0)) // error in one partition
{ {
*first_value= first_value_part; *first_value= first_value_part;
break; sql_print_error("Partition failed to reserve auto_increment value");
DBUG_VOID_RETURN;
} }
/* /*
Partition has reserved an interval. Intersect it with the intervals Partition has reserved an interval. Intersect it with the intervals
...@@ -5479,6 +5492,25 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, ...@@ -5479,6 +5492,25 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment,
} }
if (last_value < *first_value) /* empty intersection, error */ if (last_value < *first_value) /* empty intersection, error */
{ {
/*
When we have an empty intersection, it means that one or more
partitions may have a significantly different autoinc next value.
We should not fail here - it just means that we should try to
find a new reservation making use of the current *first_value
wbich should now be compatible with all partitions.
*/
if (retry)
{
retry= FALSE;
last_value= ~ (ulonglong) 0;
release_auto_increment();
goto again;
}
/*
We should not get here.
*/
sql_print_error("Failed to calculate auto_increment value for partition");
*first_value= ~(ulonglong)(0); *first_value= ~(ulonglong)(0);
} }
if (increment) // If not check for values if (increment) // If not check for values
......
...@@ -7328,10 +7328,10 @@ ha_innobase::get_auto_increment( ...@@ -7328,10 +7328,10 @@ ha_innobase::get_auto_increment(
trx->n_autoinc_rows = 1; trx->n_autoinc_rows = 1;
} }
*first_value = autoinc; set_if_bigger(*first_value, autoinc);
/* Not in the middle of a mult-row INSERT. */ /* Not in the middle of a mult-row INSERT. */
} else if (prebuilt->last_value == 0) { } else if (prebuilt->last_value == 0) {
*first_value = autoinc; set_if_bigger(*first_value, autoinc);
} }
*nb_reserved_values = trx->n_autoinc_rows; *nb_reserved_values = trx->n_autoinc_rows;
......
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