Bug 12963823 - Crash in Purge thread under unusual circumstances.

The problem occurred when indexes are added between the time that an
UNDO record is created and the time that the purge thread comes around
and deletes the old secondary index entries.  The purge thread would
hit an assert when trying to build a secondary index entry for
searching.  The problem was that the old value of those fields were not
in the UNDO record since they were not part of an index when the UPDATE
occured. 
A test case was added to innodb-index.test.
parent 9c454fa5
...@@ -39,6 +39,81 @@ DELETE FROM t1_purge; ...@@ -39,6 +39,81 @@ DELETE FROM t1_purge;
DELETE FROM t2_purge; DELETE FROM t2_purge;
DELETE FROM t3_purge; DELETE FROM t3_purge;
DELETE FROM t4_purge; DELETE FROM t4_purge;
SET @r=REPEAT('a',500);
CREATE TABLE t12637786(a INT,
v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500),
v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500),
v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500),
v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500),
v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500),
v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE INDEX idx1 ON t12637786(a,v1);
INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r);
UPDATE t12637786 SET a=1000;
DELETE FROM t12637786;
create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob,
i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob)
engine=innodb row_format=dynamic;
SET @r = repeat('a', 767);
insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r);
create index ndx_a on t12963823 (a(500));
create index ndx_b on t12963823 (b(500));
create index ndx_c on t12963823 (c(500));
create index ndx_d on t12963823 (d(500));
create index ndx_e on t12963823 (e(500));
create index ndx_f on t12963823 (f(500));
create index ndx_k on t12963823 (k(500));
create index ndx_l on t12963823 (l(500));
SET @r = repeat('b', 500);
update t12963823 set a=@r,b=@r,c=@r,d=@r;
update t12963823 set e=@r,f=@r,g=@r,h=@r;
update t12963823 set i=@r,j=@r,k=@r,l=@r;
update t12963823 set m=@r,n=@r,o=@r,p=@r;
alter table t12963823 drop index ndx_a;
alter table t12963823 drop index ndx_b;
create index ndx_g on t12963823 (g(500));
create index ndx_h on t12963823 (h(500));
create index ndx_i on t12963823 (i(500));
create index ndx_j on t12963823 (j(500));
create index ndx_m on t12963823 (m(500));
create index ndx_n on t12963823 (n(500));
create index ndx_o on t12963823 (o(500));
create index ndx_p on t12963823 (p(500));
show create table t12963823;
Table Create Table
t12963823 CREATE TABLE `t12963823` (
`a` blob,
`b` blob,
`c` blob,
`d` blob,
`e` blob,
`f` blob,
`g` blob,
`h` blob,
`i` blob,
`j` blob,
`k` blob,
`l` blob,
`m` blob,
`n` blob,
`o` blob,
`p` blob,
KEY `ndx_c` (`c`(500)),
KEY `ndx_d` (`d`(500)),
KEY `ndx_e` (`e`(500)),
KEY `ndx_f` (`f`(500)),
KEY `ndx_k` (`k`(500)),
KEY `ndx_l` (`l`(500)),
KEY `ndx_g` (`g`(500)),
KEY `ndx_h` (`h`(500)),
KEY `ndx_i` (`i`(500)),
KEY `ndx_j` (`j`(500)),
KEY `ndx_m` (`m`(500)),
KEY `ndx_n` (`n`(500)),
KEY `ndx_o` (`o`(500)),
KEY `ndx_p` (`p`(500))
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
set global innodb_file_per_table=0; set global innodb_file_per_table=0;
set global innodb_file_format=Antelope; set global innodb_file_format=Antelope;
create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb;
...@@ -1010,20 +1085,6 @@ ERROR HY000: Too big row ...@@ -1010,20 +1085,6 @@ ERROR HY000: Too big row
alter table t1 row_format=compact; alter table t1 row_format=compact;
create index t1u on t1 (u(1)); create index t1u on t1 (u(1));
drop table t1; drop table t1;
SET @r=REPEAT('a',500);
CREATE TABLE t1(a INT,
v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500),
v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500),
v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500),
v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500),
v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500),
v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE INDEX idx1 ON t1(a,v1);
INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r);
UPDATE t1 SET a=1000;
DELETE FROM t1;
DROP TABLE t1;
CREATE TABLE bug12547647( CREATE TABLE bug12547647(
a INT NOT NULL, b BLOB NOT NULL, c TEXT, a INT NOT NULL, b BLOB NOT NULL, c TEXT,
PRIMARY KEY (b(10), a), INDEX (c(10)) PRIMARY KEY (b(10), a), INDEX (c(10))
...@@ -1237,3 +1298,5 @@ a b ...@@ -1237,3 +1298,5 @@ a b
3 b 3 b
DROP TABLE t1; DROP TABLE t1;
DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge;
DROP TABLE t12637786;
DROP TABLE t12963823;
...@@ -9,7 +9,7 @@ let $format=`select @@innodb_file_format`; ...@@ -9,7 +9,7 @@ let $format=`select @@innodb_file_format`;
set global innodb_file_per_table=on; set global innodb_file_per_table=on;
set global innodb_file_format='Barracuda'; set global innodb_file_format='Barracuda';
# Test an assertion failure on purge. # Bug #12429576 - Test an assertion failure on purge.
CREATE TABLE t1_purge ( CREATE TABLE t1_purge (
A INT, A INT,
B BLOB, C BLOB, D BLOB, E BLOB, B BLOB, C BLOB, D BLOB, E BLOB,
...@@ -59,6 +59,68 @@ DELETE FROM t1_purge; ...@@ -59,6 +59,68 @@ DELETE FROM t1_purge;
DELETE FROM t2_purge; DELETE FROM t2_purge;
DELETE FROM t3_purge; DELETE FROM t3_purge;
DELETE FROM t4_purge; DELETE FROM t4_purge;
# Instead of doing a --sleep 10, wait until the rest of the tests in
# this file complete before dropping the tables. By then, the purge thread
# will have delt with the updates above.
# Bug#12637786 - Bad assert by purge thread for records with external data
# used in secondary indexes.
SET @r=REPEAT('a',500);
CREATE TABLE t12637786(a INT,
v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500),
v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500),
v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500),
v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500),
v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500),
v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE INDEX idx1 ON t12637786(a,v1);
INSERT INTO t12637786 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r);
UPDATE t12637786 SET a=1000;
DELETE FROM t12637786;
# We need to activate the purge thread at this point to make sure it does not
# assert and is able to clean up the old versions of secondary index entries.
# But instead of doing a --sleep 10, wait until the rest of the tests in
# this file complete before dropping the table. By then, the purge thread
# will have delt with the updates above.
# Bug#12963823 - Test that the purge thread does not crash when
# the number of indexes has changed since the UNDO record was logged.
create table t12963823(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob,
i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob)
engine=innodb row_format=dynamic;
SET @r = repeat('a', 767);
insert into t12963823 values (@r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r, @r,@r,@r,@r);
create index ndx_a on t12963823 (a(500));
create index ndx_b on t12963823 (b(500));
create index ndx_c on t12963823 (c(500));
create index ndx_d on t12963823 (d(500));
create index ndx_e on t12963823 (e(500));
create index ndx_f on t12963823 (f(500));
create index ndx_k on t12963823 (k(500));
create index ndx_l on t12963823 (l(500));
SET @r = repeat('b', 500);
update t12963823 set a=@r,b=@r,c=@r,d=@r;
update t12963823 set e=@r,f=@r,g=@r,h=@r;
update t12963823 set i=@r,j=@r,k=@r,l=@r;
update t12963823 set m=@r,n=@r,o=@r,p=@r;
alter table t12963823 drop index ndx_a;
alter table t12963823 drop index ndx_b;
create index ndx_g on t12963823 (g(500));
create index ndx_h on t12963823 (h(500));
create index ndx_i on t12963823 (i(500));
create index ndx_j on t12963823 (j(500));
create index ndx_m on t12963823 (m(500));
create index ndx_n on t12963823 (n(500));
create index ndx_o on t12963823 (o(500));
create index ndx_p on t12963823 (p(500));
show create table t12963823;
# We need to activate the purge thread at this point to see if it crashes
# but instead of doing a --sleep 10, wait until the rest of the tests in
# this file complete before dropping the table. By then, the purge thread
# will have delt with the updates above.
eval set global innodb_file_per_table=$per_table; eval set global innodb_file_per_table=$per_table;
eval set global innodb_file_format=$format; eval set global innodb_file_format=$format;
...@@ -462,24 +524,6 @@ create index t1u on t1 (u(1)); ...@@ -462,24 +524,6 @@ create index t1u on t1 (u(1));
drop table t1; drop table t1;
# Bug#12637786
SET @r=REPEAT('a',500);
CREATE TABLE t1(a INT,
v1 VARCHAR(500), v2 VARCHAR(500), v3 VARCHAR(500),
v4 VARCHAR(500), v5 VARCHAR(500), v6 VARCHAR(500),
v7 VARCHAR(500), v8 VARCHAR(500), v9 VARCHAR(500),
v10 VARCHAR(500), v11 VARCHAR(500), v12 VARCHAR(500),
v13 VARCHAR(500), v14 VARCHAR(500), v15 VARCHAR(500),
v16 VARCHAR(500), v17 VARCHAR(500), v18 VARCHAR(500)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE INDEX idx1 ON t1(a,v1);
INSERT INTO t1 VALUES(9,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r,@r);
UPDATE t1 SET a=1000;
DELETE FROM t1;
# Let the purge thread clean up this file.
-- sleep 10
DROP TABLE t1;
# Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE # Bug#12547647 UPDATE LOGGING COULD EXCEED LOG PAGE SIZE
CREATE TABLE bug12547647( CREATE TABLE bug12547647(
a INT NOT NULL, b BLOB NOT NULL, c TEXT, a INT NOT NULL, b BLOB NOT NULL, c TEXT,
...@@ -630,7 +674,12 @@ disconnect a; ...@@ -630,7 +674,12 @@ disconnect a;
disconnect b; disconnect b;
DROP TABLE t1; DROP TABLE t1;
# Drop these tables since the purge thread must have run by now
# and did not crash.
DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge; DROP TABLE t1_purge, t2_purge, t3_purge, t4_purge;
DROP TABLE t12637786;
DROP TABLE t12963823;
# #
# restore environment to the state it was before this test execution # restore environment to the state it was before this test execution
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ...@@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc.,
Place, Suite 330, Boston, MA 02111-1307 USA 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/ *****************************************************************************/
...@@ -530,13 +530,13 @@ row_purge_parse_undo_rec( ...@@ -530,13 +530,13 @@ row_purge_parse_undo_rec(
roll_ptr_t roll_ptr; roll_ptr_t roll_ptr;
ulint info_bits; ulint info_bits;
ulint type; ulint type;
ulint cmpl_info;
ut_ad(node && thr); ut_ad(node && thr);
trx = thr_get_trx(thr); trx = thr_get_trx(thr);
ptr = trx_undo_rec_get_pars(node->undo_rec, &type, &cmpl_info, ptr = trx_undo_rec_get_pars(
node->undo_rec, &type, &node->cmpl_info,
updated_extern, &undo_no, &table_id); updated_extern, &undo_no, &table_id);
node->rec_type = type; node->rec_type = type;
...@@ -550,7 +550,8 @@ row_purge_parse_undo_rec( ...@@ -550,7 +550,8 @@ row_purge_parse_undo_rec(
node->table = NULL; node->table = NULL;
if (type == TRX_UNDO_UPD_EXIST_REC if (type == TRX_UNDO_UPD_EXIST_REC
&& cmpl_info & UPD_NODE_NO_ORD_CHANGE && !(*updated_extern)) { && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE
&& !(*updated_extern)) {
/* Purge requires no changes to indexes: we may return */ /* Purge requires no changes to indexes: we may return */
...@@ -600,7 +601,7 @@ err_exit: ...@@ -600,7 +601,7 @@ err_exit:
/* Read to the partial row the fields that occur in indexes */ /* Read to the partial row the fields that occur in indexes */
if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { if (!(node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
ptr = trx_undo_rec_get_partial_row( ptr = trx_undo_rec_get_partial_row(
ptr, clust_index, &node->row, ptr, clust_index, &node->row,
type == TRX_UNDO_UPD_DEL_REC, type == TRX_UNDO_UPD_DEL_REC,
......
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