diff --git a/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations b/mysql-test/suite/innodb/include/have_undo_tablespaces.combinations similarity index 100% rename from mysql-test/suite/innodb_undo/include/have_undo_tablespaces.combinations rename to mysql-test/suite/innodb/include/have_undo_tablespaces.combinations diff --git a/mysql-test/suite/innodb_undo/include/have_undo_tablespaces.inc b/mysql-test/suite/innodb/include/have_undo_tablespaces.inc similarity index 100% rename from mysql-test/suite/innodb_undo/include/have_undo_tablespaces.inc rename to mysql-test/suite/innodb/include/have_undo_tablespaces.inc diff --git a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result b/mysql-test/suite/innodb/r/undo_truncate.result similarity index 60% rename from mysql-test/suite/innodb_undo/r/truncate_multi_client.result rename to mysql-test/suite/innodb/r/undo_truncate.result index 0333a70d771..89171d36d0f 100644 --- a/mysql-test/suite/innodb_undo/r/truncate_multi_client.result +++ b/mysql-test/suite/innodb/r/undo_truncate.result @@ -1,5 +1,13 @@ call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; +SET @save_undo_logs = @@GLOBAL.innodb_undo_logs; +SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; +SET GLOBAL innodb_undo_log_truncate = 0; +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; +SET @trunc_start= +(SELECT variable_value FROM information_schema.global_status +WHERE variable_name = 'innodb_undo_truncations'); create table t1(keyc int primary key, c char(100)) engine = innodb; create table t2(keyc int primary key, c char(100)) engine = innodb; CREATE PROCEDURE populate_t1() @@ -37,6 +45,7 @@ delete from t1; connection con2; delete from t2; connection con1; +SET GLOBAL innodb_undo_log_truncate = 1; commit; disconnect con1; connection con2; @@ -46,7 +55,7 @@ connection default; drop table t1, t2; drop PROCEDURE populate_t1; drop PROCEDURE populate_t2; -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; -FOUND 1 /Truncating UNDO tablespace 1/ in mysqld.1.err +InnoDB 0 transactions not purged +SET GLOBAL innodb_undo_logs = @save_undo_logs; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; +SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/mysql-test/suite/innodb_undo/r/truncate_recover.result b/mysql-test/suite/innodb/r/undo_truncate_recover.result similarity index 100% rename from mysql-test/suite/innodb_undo/r/truncate_recover.result rename to mysql-test/suite/innodb/r/undo_truncate_recover.result diff --git a/mysql-test/suite/innodb/t/undo_truncate.test b/mysql-test/suite/innodb/t/undo_truncate.test new file mode 100644 index 00000000000..4f350e380ee --- /dev/null +++ b/mysql-test/suite/innodb/t/undo_truncate.test @@ -0,0 +1,128 @@ +--source include/have_innodb.inc +# With 32k, truncation could happen on shutdown after the test, +# and the mtr.add_suppression() would not filter out the warning. +# With 64k, no truncation seems to happen. +# --source include/innodb_page_size.inc +--source include/innodb_page_size_small.inc +--source include/have_undo_tablespaces.inc + +call mtr.add_suppression("InnoDB: The transaction log size is too large"); + +SET @save_undo_logs = @@GLOBAL.innodb_undo_logs; +SET @save_frequency = @@GLOBAL.innodb_purge_rseg_truncate_frequency; +SET @save_truncate = @@GLOBAL.innodb_undo_log_truncate; +SET GLOBAL innodb_undo_log_truncate = 0; +SET GLOBAL innodb_undo_logs = 4; +SET GLOBAL innodb_purge_rseg_truncate_frequency = 1; + +SET @trunc_start= +(SELECT variable_value FROM information_schema.global_status +WHERE variable_name = 'innodb_undo_truncations'); + +#----------------------------------------------------------------------------- +# +# Perform DML action using multiple clients and multiple undo tablespace. +# +# +create table t1(keyc int primary key, c char(100)) engine = innodb; +create table t2(keyc int primary key, c char(100)) engine = innodb; +# +delimiter |; +CREATE PROCEDURE populate_t1() +BEGIN + DECLARE i INT DEFAULT 1; + while (i <= 20000) DO + insert into t1 values (i, 'a'); + SET i = i + 1; + END WHILE; +END | +delimiter ;| +# +delimiter |; +CREATE PROCEDURE populate_t2() +BEGIN + DECLARE i INT DEFAULT 1; + while (i <= 20000) DO + insert into t2 values (i, 'a'); + SET i = i + 1; + END WHILE; +END | +delimiter ;| +# +# +let DATADIR = `select @@datadir`; +connect (con1,localhost,root,,); +begin; +send call populate_t1(); + +connect (con2,localhost,root,,); +begin; +send call populate_t2(); + +connection con1; reap; send update t1 set c = 'mysql'; +connection con2; reap; send update t2 set c = 'mysql'; +connection con1; reap; send update t1 set c = 'oracle'; +connection con2; reap; send update t2 set c = 'oracle'; +connection con1; reap; send delete from t1; +connection con2; reap; delete from t2; +connection con1; reap; + +let CHECKFILE = $MYSQL_TMP_DIR/check.txt; +perl; +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) + = stat("$ENV{DATADIR}/undo001"); +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) + = stat("$ENV{DATADIR}/undo002"); +open(OUT, ">$ENV{CHECKFILE}") || die; +print OUT "let \$size1='$size1,$size2';\n"; +close(OUT); +EOF + +SET GLOBAL innodb_undo_log_truncate = 1; +commit; disconnect con1; +connection con2; commit; disconnect con2; + +connection default; +drop table t1, t2; +drop PROCEDURE populate_t1; +drop PROCEDURE populate_t2; + +--source include/wait_all_purged.inc + +# Truncation will normally not occur with innodb_page_size=64k, +# and occasionally not with innodb_page_size=32k, +# because the undo log will not grow enough. +if (`select @@innodb_page_size IN (4096,8192,16384)`) +{ + let $wait_condition = (SELECT variable_value!=@trunc_start + FROM information_schema.global_status + WHERE variable_name = 'innodb_undo_truncations'); + source include/wait_condition.inc; +} + +--source $CHECKFILE +perl; +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) + = stat("$ENV{DATADIR}/undo001"); +($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) + = stat("$ENV{DATADIR}/undo002"); +open(OUT, ">$ENV{CHECKFILE}") || die; +print OUT "let \$size2='$size1,$size2';\n"; +close(OUT); +EOF + +--source $CHECKFILE +--remove_file $CHECKFILE + +if ($size1 == $size2) +{ + # This fails for innodb_page_size=64k, occasionally also for 32k. + if (`select @@innodb_page_size IN (4096,8192,16384)`) + { + echo Truncation did not happen: $size1; + } +} + +SET GLOBAL innodb_undo_logs = @save_undo_logs; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; +SET GLOBAL innodb_undo_log_truncate = @save_truncate; diff --git a/mysql-test/suite/innodb_undo/t/truncate_recover.test b/mysql-test/suite/innodb/t/undo_truncate_recover.test similarity index 100% rename from mysql-test/suite/innodb_undo/t/truncate_recover.test rename to mysql-test/suite/innodb/t/undo_truncate_recover.test diff --git a/mysql-test/suite/innodb_undo/r/truncate.result b/mysql-test/suite/innodb_undo/r/truncate.result deleted file mode 100644 index 2194eed3e7b..00000000000 --- a/mysql-test/suite/innodb_undo/r/truncate.result +++ /dev/null @@ -1,12 +0,0 @@ -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; -create table t1(keyc int primary key, c1 char(100)) engine = innodb; -begin; -update t1 set c1 = 'mysql'; -update t1 set c1 = 'oracle'; -delete from t1; -commit; -drop table t1; -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; diff --git a/mysql-test/suite/innodb_undo/t/truncate.test b/mysql-test/suite/innodb_undo/t/truncate.test deleted file mode 100644 index cc18434ae13..00000000000 --- a/mysql-test/suite/innodb_undo/t/truncate.test +++ /dev/null @@ -1,73 +0,0 @@ -# -# WL#6965: Truncate UNDO logs. -# - ---source include/have_innodb.inc ---source include/have_innodb_max_16k.inc ---source include/have_undo_tablespaces.inc - -# The test is restarting the server to force undo truncation. ---source include/not_embedded.inc - -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; ---let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 ---source include/restart_mysqld.inc - -let MYSQLD_DATADIR = `select @@datadir`; - -#----------------------------------------------------------------------------- -# -# 1. Perform enough DML action so that undo tablespace size grows beyond -# set threshold and then wait and see if it is being truncated. -# -create table t1(keyc int primary key, c1 char(100)) engine = innodb; -begin; ---disable_query_log -let $i=30000; -while ($i) { - eval insert into t1 values(30000-$i, ''); - dec $i; -} ---enable_query_log -update t1 set c1 = 'mysql'; -update t1 set c1 = 'oracle'; -delete from t1; -commit; -drop table t1; - -let CHECKFILE = $MYSQL_TMP_DIR/check.txt; -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{MYSQLD_DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{MYSQLD_DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size1='$size1,$size2';\n"; -close(OUT); -EOF -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; ---source include/shutdown_mysqld.inc ---source $CHECKFILE -perl; -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size1) - = stat("$ENV{MYSQLD_DATADIR}/undo001"); -($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size2) - = stat("$ENV{MYSQLD_DATADIR}/undo002"); -open(OUT, ">$ENV{CHECKFILE}") || die; -print OUT "let \$size2='$size1,$size2';\n"; -close(OUT); -EOF - ---source $CHECKFILE ---remove_file $CHECKFILE - -if ($size1 == $size2) -{ - echo Truncation did not happen: $size1 == $size2; -} - ---let $restart_parameters= ---source include/start_mysqld.inc diff --git a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test b/mysql-test/suite/innodb_undo/t/truncate_multi_client.test deleted file mode 100644 index 6a3d702d0d5..00000000000 --- a/mysql-test/suite/innodb_undo/t/truncate_multi_client.test +++ /dev/null @@ -1,78 +0,0 @@ -# -# WL#6965: Truncate UNDO logs. -# - ---source include/have_innodb.inc -# This test is restarting the server. ---source include/not_embedded.inc -# With larger innodb_page_size, the undo log tablespaces do not grow enough. ---source include/have_innodb_max_16k.inc ---source include/have_undo_tablespaces.inc - -call mtr.add_suppression("InnoDB: The transaction log size is too large"); -SET GLOBAL innodb_fast_shutdown=0; ---let $restart_parameters=--innodb_undo_tablespaces=2 --innodb_undo_logs=4 ---source include/restart_mysqld.inc - -#----------------------------------------------------------------------------- -# -# Perform DML action using multiple clients and multiple undo tablespace. -# -# -create table t1(keyc int primary key, c char(100)) engine = innodb; -create table t2(keyc int primary key, c char(100)) engine = innodb; -# -delimiter |; -CREATE PROCEDURE populate_t1() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t1 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -delimiter |; -CREATE PROCEDURE populate_t2() -BEGIN - DECLARE i INT DEFAULT 1; - while (i <= 20000) DO - insert into t2 values (i, 'a'); - SET i = i + 1; - END WHILE; -END | -delimiter ;| -# -# -connect (con1,localhost,root,,); -begin; -send call populate_t1(); - -connect (con2,localhost,root,,); -begin; -send call populate_t2(); - -connection con1; reap; send update t1 set c = 'mysql'; -connection con2; reap; send update t2 set c = 'mysql'; -connection con1; reap; send update t1 set c = 'oracle'; -connection con2; reap; send update t2 set c = 'oracle'; -connection con1; reap; send delete from t1; -connection con2; reap; send delete from t2; -connection con1; reap; commit; disconnect con1; -connection con2; reap; commit; disconnect con2; - -connection default; -drop table t1, t2; -drop PROCEDURE populate_t1; -drop PROCEDURE populate_t2; - -SET GLOBAL innodb_fast_shutdown=0; -SET GLOBAL innodb_undo_log_truncate=1; -SET GLOBAL innodb_purge_rseg_truncate_frequency=1; - ---source include/restart_mysqld.inc - -let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.1.err; -let SEARCH_PATTERN = Truncating UNDO tablespace 1; ---source include/search_pattern_in_file.inc diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5d79c22edcf..6bbb4c3f81b 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1100,6 +1100,8 @@ static SHOW_VAR innodb_status_variables[]= { (char*) &export_vars.innodb_truncated_status_writes, SHOW_LONG}, {"available_undo_logs", (char*) &export_vars.innodb_available_undo_logs, SHOW_LONG}, + {"undo_truncations", + (char*) &export_vars.innodb_undo_truncations, SHOW_LONG}, /* Status variables for page compression */ {"page_compression_saved", diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 7adfe295710..ecd2914515d 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -1022,6 +1022,8 @@ struct export_var_t{ ulint innodb_truncated_status_writes; /*!< srv_truncated_status_writes */ ulint innodb_available_undo_logs; /*!< srv_available_undo_logs */ + /** Number of undo tablespace truncation operations */ + ulong innodb_undo_truncations; ulint innodb_defragment_compression_failures; /*!< Number of defragment re-compression failures */ diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index c5f7b6c895b..6a88b335f17 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -1076,6 +1076,9 @@ trx_purge_initiate_truncate( os_file_truncate(file->name, file->handle, os_offset_t(size) << srv_page_size_shift, true); + /* This is only executed by the srv_coordinator_thread. */ + export_vars.innodb_undo_truncations++; + /* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */ mutex_enter(&fil_system->mutex);