diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-07-02 15:17:09 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-07-02 15:18:12 +0300 |
commit | 6bb922e58ea92a30ff70a22ec41003b1a6468028 (patch) | |
tree | 88cb45935d634920f8af3b81cccfdd9fb3213626 | |
parent | 41f6e68878df46dd7abc8a98234f58a1fa030592 (diff) | |
download | mariadb-git-6bb922e58ea92a30ff70a22ec41003b1a6468028.tar.gz |
MDEV-13626: Import and adjust innodb.blob-crash
-rw-r--r-- | mysql-test/suite/innodb/r/blob-crash.result | 149 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/blob-crash.test | 208 | ||||
-rw-r--r-- | storage/innobase/btr/btr0cur.cc | 2 |
3 files changed, 358 insertions, 1 deletions
diff --git a/mysql-test/suite/innodb/r/blob-crash.result b/mysql-test/suite/innodb/r/blob-crash.result new file mode 100644 index 00000000000..85d12ff49b5 --- /dev/null +++ b/mysql-test/suite/innodb/r/blob-crash.result @@ -0,0 +1,149 @@ +# +# Bug #16963396 INNODB: USE OF LARGE EXTERNALLY-STORED FIELDS MAKES +# CRASH RECOVERY LOSE DATA +# +# +# Uncompressed Table - Insert Operation - Crash Test +# Fresh insert with blobs +# +CREATE TABLE t1 (a BIGINT PRIMARY KEY, b LONGBLOB) ENGINE=InnoDB; +INSERT INTO t1 (a, b) VALUES (1, repeat('^', 40000)); +INSERT INTO t1 (a, b) VALUES (2, '2'); +INSERT INTO t1 (a, b) VALUES (3, '3'); +INSERT INTO t1 (a, b) VALUES (4, '4'); +INSERT INTO t1 (a, b) VALUES (5, '5'); +begin; +INSERT INTO t1 (a, b) VALUES (6, REPEAT('a', 4*1024*1024)); +SELECT a, right(b, 50) FROM t1; +a right(b, 50) +1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 2 +3 3 +4 4 +5 5 +# +# Uncompressed Table - UPDATE Operation - Crash Test +# Update of non-blob column so that blob is needed. +# +begin; +UPDATE t1 set b = REPEAT('a', 4*1024*1024) where a = 5 ; +SELECT a, right(b, 50) FROM t1; +a right(b, 50) +1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 2 +3 3 +4 4 +5 5 +# +# Uncompressed Table - UPDATE Operation - Crash Test +# Update of blob column to blob. +# +connect con1,localhost,root,,; +begin; +UPDATE t1 set b = REPEAT('$', 50000) where a = 1; +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +UPDATE t1 SET b='five' WHERE a=5; +disconnect con1; +SELECT a, right(b, 50) FROM t1; +a right(b, 50) +1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +2 2 +3 3 +4 4 +5 five +# +# Uncompressed Table - Rollback of UPDATE operation +# Update moves offpage data to inline data. +# +create table t2 (f1 bigint primary key, f2 longblob, f3 longblob, +index(f2(10), f3(10))) engine=innodb; +insert into t2 values (10, repeat('.', 40000), repeat('?', 40000)); +connect con1,localhost,root,,; +begin; +update t2 set f2 = '='; +select f1, right(f2, 20), right(f3, 20) from t2; +f1 right(f2, 20) right(f3, 20) +10 = ???????????????????? +update t2 set f3 = '&'; +select f1, right(f2, 20), right(f3, 20) from t2; +f1 right(f2, 20) right(f3, 20) +10 = & +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=1; +disconnect con1; +select f1, right(f2, 20), right(f3, 20) from t2; +f1 right(f2, 20) right(f3, 20) +10 .................... ???????????????????? +check table t2; +Table Op Msg_type Msg_text +test.t2 check status OK +drop table t2; +# +# Compressed Table - Insert Operation - Crash Test +# fresh insert with BLOBs +# +set global innodb_compression_level = 0; +create table t3 (f1 bigint primary key, f2 longblob, f3 longblob, +index(f2(10), f3(10))) engine=innodb row_format=compressed; +connect con1,localhost,root,,; +begin; +INSERT INTO t3 (f1, f2, f3) VALUES (6, repeat('/', 40000), repeat('<', 40000)); +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=2; +disconnect con1; +select f1, length(f2), length(f3) from t3; +f1 length(f2) length(f3) +select f1, right(f2, 30), right(f3, 20) from t3; +f1 right(f2, 30) right(f3, 20) +check table t3; +Table Op Msg_type Msg_text +test.t3 check status OK +# +# Compressed Table - Update Operation - Crash Test +# update of a non-BLOB column so that BLOB is needed +# +set global innodb_compression_level = 0; +insert into t3 values (2, repeat('!', 30), repeat('+', 30)); +connect con1,localhost,root,,; +begin; +UPDATE t3 set f2 = repeat('>', 40000) where f1 = 2; +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=3; +disconnect con1; +select f1, length(f2), length(f3) from t3; +f1 length(f2) length(f3) +2 30 30 +select f1, right(f2, 30), right(f3, 20) from t3; +f1 right(f2, 30) right(f3, 20) +2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++++++++++++++++++++ +check table t3; +Table Op Msg_type Msg_text +test.t3 check status OK +# +# Compressed Table - Update Operation - Crash Test +# update blob to blob +# +set global innodb_compression_level = 0; +insert into t3 values (3, repeat('%', 40000), repeat('~', 40000)); +connect con1,localhost,root,,; +begin; +UPDATE t3 set f2 = concat(f2, repeat(',', 10)) where f1 = 3; +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=4; +select f1, length(f2), length(f3) from t3; +f1 length(f2) length(f3) +2 30 30 +3 40000 40000 +select f1, right(f2, 30), right(f3, 20) from t3; +f1 right(f2, 30) right(f3, 20) +2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++++++++++++++++++++ +3 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ~~~~~~~~~~~~~~~~~~~~ +check table t3; +Table Op Msg_type Msg_text +test.t3 check status OK +DROP TABLE t1,t3; diff --git a/mysql-test/suite/innodb/t/blob-crash.test b/mysql-test/suite/innodb/t/blob-crash.test new file mode 100644 index 00000000000..b36c9318e27 --- /dev/null +++ b/mysql-test/suite/innodb/t/blob-crash.test @@ -0,0 +1,208 @@ +--source include/maybe_debug.inc +--source include/innodb_page_size_small.inc + +--echo # +--echo # Bug #16963396 INNODB: USE OF LARGE EXTERNALLY-STORED FIELDS MAKES +--echo # CRASH RECOVERY LOSE DATA +--echo # + +# .......................................................................... + +--echo # +--echo # Uncompressed Table - Insert Operation - Crash Test +--echo # Fresh insert with blobs +--echo # + +CREATE TABLE t1 (a BIGINT PRIMARY KEY, b LONGBLOB) ENGINE=InnoDB; + +# Insert a few rows (it doesn't really matter how many). These transactions +# are committed once they are acked, so they should not be lost. +INSERT INTO t1 (a, b) VALUES (1, repeat('^', 40000)); +INSERT INTO t1 (a, b) VALUES (2, '2'); +INSERT INTO t1 (a, b) VALUES (3, '3'); +INSERT INTO t1 (a, b) VALUES (4, '4'); +INSERT INTO t1 (a, b) VALUES (5, '5'); + +# The BLOB insert will fail, and should disappear. However no data committed +# up to this point should be lost. +begin; +INSERT INTO t1 (a, b) VALUES (6, REPEAT('a', 4*1024*1024)); + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +SELECT a, right(b, 50) FROM t1; + +# .......................................................................... + +--echo # +--echo # Uncompressed Table - UPDATE Operation - Crash Test +--echo # Update of non-blob column so that blob is needed. +--echo # + +# The BLOB update will fail, and should disappear. However no data committed +# up to this point should be lost. +begin; +UPDATE t1 set b = REPEAT('a', 4*1024*1024) where a = 5 ; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +SELECT a, right(b, 50) FROM t1; + +# .......................................................................... + +--echo # +--echo # Uncompressed Table - UPDATE Operation - Crash Test +--echo # Update of blob column to blob. +--echo # + +# The BLOB update will fail, and should disappear. However no data committed +# up to this point should be lost. +connect (con1,localhost,root,,); +begin; +UPDATE t1 set b = REPEAT('$', 50000) where a = 1; + +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +UPDATE t1 SET b='five' WHERE a=5; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +disconnect con1; + +SELECT a, right(b, 50) FROM t1; + +# .......................................................................... + +--echo # +--echo # Uncompressed Table - Rollback of UPDATE operation +--echo # Update moves offpage data to inline data. +--echo # + +create table t2 (f1 bigint primary key, f2 longblob, f3 longblob, + index(f2(10), f3(10))) engine=innodb; + +insert into t2 values (10, repeat('.', 40000), repeat('?', 40000)); + +connect (con1,localhost,root,,); +begin; +update t2 set f2 = '='; +select f1, right(f2, 20), right(f3, 20) from t2; +update t2 set f3 = '&'; +select f1, right(f2, 20), right(f3, 20) from t2; + +if ($have_debug) { +--disable_query_log +set DEBUG_SYNC='blob_rollback_middle SIGNAL stuck WAIT_FOR ever'; +send ROLLBACK; +--enable_query_log +} + +connection default; +if ($have_debug) { +--disable_query_log +SET DEBUG_SYNC = 'now WAIT_FOR stuck'; +--enable_query_log +} +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=1; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +disconnect con1; + +select f1, right(f2, 20), right(f3, 20) from t2; +check table t2; +drop table t2; + +# .......................................................................... + +--echo # +--echo # Compressed Table - Insert Operation - Crash Test +--echo # fresh insert with BLOBs +--echo # + +set global innodb_compression_level = 0; + +create table t3 (f1 bigint primary key, f2 longblob, f3 longblob, + index(f2(10), f3(10))) engine=innodb row_format=compressed; + +# The BLOB insert will fail, and should disappear. However no data committed +# up to this point should be lost. +connect (con1,localhost,root,,); +begin; +INSERT INTO t3 (f1, f2, f3) VALUES (6, repeat('/', 40000), repeat('<', 40000)); + +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=2; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +disconnect con1; + +select f1, length(f2), length(f3) from t3; +select f1, right(f2, 30), right(f3, 20) from t3; +check table t3; + +# .......................................................................... + +--echo # +--echo # Compressed Table - Update Operation - Crash Test +--echo # update of a non-BLOB column so that BLOB is needed +--echo # + +set global innodb_compression_level = 0; +insert into t3 values (2, repeat('!', 30), repeat('+', 30)); + +# The BLOB update will fail, and should disappear. However no data committed +# up to this point should be lost. +connect (con1,localhost,root,,); +begin; +UPDATE t3 set f2 = repeat('>', 40000) where f1 = 2; + +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=3; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +disconnect con1; + +select f1, length(f2), length(f3) from t3; +select f1, right(f2, 30), right(f3, 20) from t3; +check table t3; + +# .......................................................................... + +--echo # +--echo # Compressed Table - Update Operation - Crash Test +--echo # update blob to blob +--echo # + +set global innodb_compression_level = 0; +insert into t3 values (3, repeat('%', 40000), repeat('~', 40000)); + +# The BLOB update will fail, and should disappear. However no data committed +# up to this point should be lost. +connect (con1,localhost,root,,); +begin; +UPDATE t3 set f2 = concat(f2, repeat(',', 10)) where f1 = 3; + +connection default; +SET GLOBAL innodb_flush_log_at_trx_commit=1; +DELETE FROM t1 WHERE a=4; + +let $shutdown_timeout=0; +--source include/restart_mysqld.inc + +select f1, length(f2), length(f3) from t3; +select f1, right(f2, 30), right(f3, 20) from t3; +check table t3; + +DROP TABLE t1,t3; diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 906785ee107..349ae990edb 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -4379,7 +4379,7 @@ btr_cur_pessimistic_update( ut_ad(dict_index_is_clust(index)); ut_ad(thr_get_trx(thr)->in_rollback); - DBUG_EXECUTE_IF("ib_blob_update_rollback", DBUG_SUICIDE();); + DEBUG_SYNC_C("blob_rollback_middle"); btr_rec_free_updated_extern_fields( index, rec, page_zip, *offsets, update, true, mtr); |