commit be5c4113e2f62c134dde9db9f4df0221c0fd93ca Author: nizamordulu Date: 4 days ago Test against random compression failures Summary: This diff provides a method to test against random compression failures. Test Plan: OK Reviewers: mcallaghan Reviewed By: mcallaghan CC: db-eng@lists, mcallaghan, nizamordulu Differential Revision: https://phabricator.fb.com/D382101 Revert Plan: ok Task ID: 855216 diff --git a/mysql-test/suite/innodb_plugin/r/simulate_comp_failures.result b/mysql-test/suite/innodb_plugin/r/simulate_comp_failures.result new file mode 100644 index 0000000..fcc8037 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/r/simulate_comp_failures.result @@ -0,0 +1,23 @@ +# +# Testing robustness against random compression failures +# +DROP TABLE IF EXISTS t1; +SET GLOBAL INNODB_FILE_FORMAT='Barracuda'; +call mtr.add_suppression(".*"); +CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(255), KEY msg_i(msg)) +ENGINE=INNODB +ROW_FORMAT=COMPRESSED +KEY_BLOCK_SIZE=8; +SET GLOBAL innodb_comp_fail_samples = 0; +SET GLOBAL innodb_simulate_comp_failures = 25; +SELECT COUNT(*) FROM t1; +COUNT(*) +100000 +SELECT FLOOR(100*compress_ops_ok/compress_ops) from information_schema.innodb_cmp where page_size=8192; +FLOOR(100*compress_ops_ok/compress_ops) +75 +DROP TABLE t1; +SET GLOBAL innodb_file_format = "Antelope"; +SET GLOBAL innodb_file_format_check = "Antelope"; +SET GLOBAL innodb_comp_fail_samples = 200; +SET GLOBAL innodb_simulate_comp_failures = 0; diff --git a/mysql-test/suite/innodb_plugin/t/simulate_comp_failures-master.opt b/mysql-test/suite/innodb_plugin/t/simulate_comp_failures-master.opt new file mode 100644 index 0000000..7a82ebc --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/simulate_comp_failures-master.opt @@ -0,0 +1 @@ +--innodb-file-per-table \ No newline at end of file diff --git a/mysql-test/suite/innodb_plugin/t/simulate_comp_failures.test b/mysql-test/suite/innodb_plugin/t/simulate_comp_failures.test new file mode 100644 index 0000000..ac6a2e4 --- /dev/null +++ b/mysql-test/suite/innodb_plugin/t/simulate_comp_failures.test @@ -0,0 +1,132 @@ +--echo # +--echo # Testing robustness against random compression failures +--echo # +--source include/not_embedded.inc +--source include/have_innodb.inc + +# record the file format in order to restore in the end. +--let $file_format_save = `SELECT @@innodb_file_format` +--let $file_format_check_save = `SELECT @@innodb_file_format_check` +--let $comp_fail_samples_save = `SELECT @@innodb_comp_fail_samples` +--let $simulate_comp_failures_save = `SELECT @@innodb_simulate_comp_failures` + +--disable_warnings +DROP TABLE IF EXISTS t1; +SET GLOBAL INNODB_FILE_FORMAT='Barracuda'; +--enable_warnings + +# since this test generates lot of errors in log, suppress checking errors +call mtr.add_suppression(".*"); + +# create the table with compressed pages of size 8K. +CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY, msg VARCHAR(255), KEY msg_i(msg)) +ENGINE=INNODB +ROW_FORMAT=COMPRESSED +KEY_BLOCK_SIZE=8; + +# turn off adaptive padding so that it's not confused +# by random compression failures +SET GLOBAL innodb_comp_fail_samples = 0; +# percentage of compressions that will be forced to fail +SET GLOBAL innodb_simulate_comp_failures = 25; +--disable_query_log +--disable_result_log +let $num_inserts = 100000; +while ($num_inserts) +{ + let $repeat = `select floor(rand() * 10)`; + eval +INSERT INTO t1(id, msg) +VALUES ($num_inserts, REPEAT('abcdefghijklmnopqrstuvwxyz', $repeat)); + dec $num_inserts; +} + +--enable_query_log +--enable_result_log +SELECT COUNT(*) FROM t1; +--disable_query_log +--disable_result_log + +# do random ops, making sure that some pages will get fragmented and reorganized. +let $num_ops = 30000; +while($num_ops) +{ + let $idx = `select floor(rand()*100000)`; + let $insert_or_update = `select floor(rand()*3)`; + let $repeat = `select floor(rand() * 9) + 1`; + let $msg = query_get_value(`select repeat('abcdefghijklmnopqrstuvwxyz', $repeat) as x`, x, 1); + let $single_or_multi = `select floor(rand()*10)`; + if ($insert_or_update) + { + let $cnt = query_get_value(SELECT COUNT(*) cnt FROM t1 WHERE id=$idx, cnt, 1); + if ($cnt) + { + let $update = `select floor(rand()*2)`; + if ($update) + { + if ($single_or_multi) + { + eval UPDATE t1 SET msg=\"$msg\" WHERE id=$idx; + } + if (!$single_or_multi) + { + eval UPDATE t1 SET msg=\"$msg\" WHERE id >= $idx - 100 AND id <= $idx + 100; + } + } + if (!$update) + { + if ($single_or_multi) + { + eval INSERT INTO t1(msg, id) VALUES (\"$msg\", $idx) ON DUPLICATE KEY UPDATE msg=VALUES(msg), id = VALUES(id); + } + if (!$single_or_multi) + { + let $diff = 200; + while ($diff) + { + eval INSERT INTO t1(msg, id) VALUES (\"$msg\", $idx + 100 - $diff) ON DUPLICATE KEY UPDATE msg=VALUES(msg), id=VALUES(id); + dec $diff; + } + } + } + } + if (!$cnt) + { + let $null_msg = `select floor(rand()*2)`; + if ($null_msg) + { + eval INSERT INTO t1(id,msg) VALUES ($idx, NULL); + } + if (!$null_msg) + { + eval INSERT INTO t1(id, msg) VALUES ($idx, \"$msg\"); + } + } + } + if (!$insert_or_update) + { + if ($single_or_multi) + { + eval DELETE from t1 WHERE id=$idx; + } + if (!$single_or_multi) + { + eval DELETE from t1 WHERE id >= $idx - 100 AND id <= $idx + 100; + } + } + dec $num_ops; +} + +--enable_query_log +--enable_result_log +SELECT FLOOR(100*compress_ops_ok/compress_ops) from information_schema.innodb_cmp where page_size=8192; +# final cleanup +DROP TABLE t1; + +# restore innodb_file_format and innodb_file_format_check +eval SET GLOBAL innodb_file_format = \"$file_format_save\"; +eval SET GLOBAL innodb_file_format_check = \"$file_format_check_save\"; +eval SET GLOBAL innodb_comp_fail_samples = $comp_fail_samples_save; +eval SET GLOBAL innodb_simulate_comp_failures = $simulate_comp_failures_save; +# clean exit +--exit diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 7ee75dc..0d8417c 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -12015,6 +12015,11 @@ static MYSQL_SYSVAR_DOUBLE(comp_fail_threshold, " then the table will not be padded.", NULL, NULL, 0.10, 0.01, 0.99, 0); +static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures, + PLUGIN_VAR_NOCMDARG, + "Simulate compression failures.", + NULL, NULL, 0, 0, 99, 0); + static MYSQL_SYSVAR_STR(log_group_home_dir, innobase_log_group_home_dir, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "Path to InnoDB log files.", NULL, NULL, NULL); @@ -12407,6 +12412,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(comp_fail_samples), MYSQL_SYSVAR(comp_fail_tree_size), MYSQL_SYSVAR(comp_fail_threshold), + MYSQL_SYSVAR(simulate_comp_failures), MYSQL_SYSVAR(log_file_size), MYSQL_SYSVAR(log_files_in_group), MYSQL_SYSVAR(log_group_home_dir), diff --git a/storage/innodb_plugin/include/srv0srv.h b/storage/innodb_plugin/include/srv0srv.h index 355b0c5..d2efc4e 100644 --- a/storage/innodb_plugin/include/srv0srv.h +++ b/storage/innodb_plugin/include/srv0srv.h @@ -104,6 +104,7 @@ extern my_bool srv_background_drop_table; /** If true, always log the images of compressed pages when the page is recompressed */ extern my_bool srv_log_compressed_pages; +extern uint srv_simulate_comp_failures; /** Number of page size samples collected from pages that fail to compress to determine the ideal page size that won't fail to compress. */ diff --git a/storage/innodb_plugin/page/page0zip.c b/storage/innodb_plugin/page/page0zip.c index 6a14bbc..35c1a3b 100644 --- a/storage/innodb_plugin/page/page0zip.c +++ b/storage/innodb_plugin/page/page0zip.c @@ -37,6 +37,7 @@ Created June 2005 by Marko Makela #include "btr0cur.h" #include "page0types.h" #include "log0recv.h" +#include "srv0srv.h" #include "zlib.h" #ifndef UNIV_HOTBACKUP # include "buf0lru.h" @@ -1246,6 +1247,25 @@ page_zip_compress( goto err_exit; } + /* Simulate a compression failure with a probability determined by + innodb_simulate_comp_failures, only if the page has 2 or more records and + the padding computation is finished. */ + if (srv_simulate_comp_failures + && (index->comp_fail_max_page_size_final || srv_comp_fail_samples == 0) + && page_get_n_recs(page) >= 2 + && ((rand() % 100) < srv_simulate_comp_failures)) { +#ifdef UNIV_DEBUG + fprintf(stderr, + "InnoDB: Simulating a compression failure" + " for table %s, index %s, page %lu (%s)\n", + index->table_name, + index->name, + page_get_page_no(page), + page_is_leaf(page) ? "leaf" : "non-leaf"); +#endif + goto err_exit; + } + heap = mem_heap_create(page_zip_get_size(page_zip) + n_fields * (2 + sizeof *offsets) + n_dense * ((sizeof *recs) diff --git a/storage/innodb_plugin/srv/srv0srv.c b/storage/innodb_plugin/srv/srv0srv.c index 6a27d61..36b7ec6 100644 --- a/storage/innodb_plugin/srv/srv0srv.c +++ b/storage/innodb_plugin/srv/srv0srv.c @@ -136,6 +136,7 @@ UNIV_INTERN my_bool srv_log_compressed_pages = TRUE; UNIV_INTERN uint srv_comp_fail_tree_size = 0; UNIV_INTERN uint srv_comp_fail_samples = 0; UNIV_INTERN double srv_comp_fail_threshold = 0; +UNIV_INTERN uint srv_simulate_comp_failures = 0; /** Whether to check file format during startup. A value of DICT_TF_FORMAT_MAX + 1 means no checking ie. FALSE. The default is to