diff --git a/mysql-test/suite/innodb_stress/r/innodb_segment_reserve_factor.result b/mysql-test/suite/innodb_stress/r/innodb_segment_reserve_factor.result new file mode 100644 index 000000000000..c9baa343497c --- /dev/null +++ b/mysql-test/suite/innodb_stress/r/innodb_segment_reserve_factor.result @@ -0,0 +1,19 @@ +# create the actual table +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; +# decompress the data file +# t1 is populated with high segment_reserve_factor +SET GLOBAL innodb_segment_reserve_factor = 0.125; +LOAD DATA INFILE 'segment_reserve_factor.dat' INTO TABLE t1; +# t2 is populated with low segment_reserve_factor +SET GLOBAL innodb_segment_reserve_factor = 0.002; +CREATE TABLE t2 like t1; +LOAD DATA INFILE 'segment_reserve_factor.dat' INTO TABLE t2; +# comparing the sizes of t1.ibd and t2.ibd (t2.ibd must be at most 95% of t1.ibd) +'stat -c %s $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.ibd $MYSQLTEST_VARDIR/mysqld.1/data/test/t2.ibd | xargs | awk '{if ($2/$1 < .95) print "PASS"; else print "FAIL";}' +PASS diff --git a/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor-master.opt b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor-master.opt new file mode 100644 index 000000000000..828a7cd67c82 --- /dev/null +++ b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor-master.opt @@ -0,0 +1,2 @@ +--innodb-file-per-table +--innodb-file-format=Barracuda diff --git a/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.dat.gz b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.dat.gz new file mode 100644 index 000000000000..28da1dfe17b8 Binary files /dev/null and b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.dat.gz differ diff --git a/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.test b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.test new file mode 100644 index 000000000000..9dd46b5d1eb3 --- /dev/null +++ b/mysql-test/suite/innodb_stress/t/innodb_segment_reserve_factor.test @@ -0,0 +1,42 @@ +--source include/have_innodb.inc +--disable_query_log +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--exec rm -f var/mysqld.1/data/test/segment_reserve_factor.dat +--enable_warnings +--let $segment_reserve_factor_save = `SELECT @@innodb_segment_reserve_factor` +--enable_query_log + +--echo # create the actual table +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; + +--echo # decompress the data file +--exec gunzip -c suite/innodb_stress/t/innodb_segment_reserve_factor.dat.gz > $MYSQLTEST_VARDIR/mysqld.1/data/test/segment_reserve_factor.dat + +--echo # t1 is populated with high segment_reserve_factor +SET GLOBAL innodb_segment_reserve_factor = 0.125; +LOAD DATA INFILE 'segment_reserve_factor.dat' INTO TABLE t1; + +--echo # t2 is populated with low segment_reserve_factor +SET GLOBAL innodb_segment_reserve_factor = 0.002; +CREATE TABLE t2 like t1; +LOAD DATA INFILE 'segment_reserve_factor.dat' INTO TABLE t2; + +--echo # comparing the sizes of t1.ibd and t2.ibd (t2.ibd must be at most 95% of t1.ibd) + +--let $cmd_string = 'stat -c %s \$MYSQLTEST_VARDIR/mysqld.1/data/test/t1.ibd \$MYSQLTEST_VARDIR/mysqld.1/data/test/t2.ibd | xargs | awk '{if (\$2/\$1 < .95) print "PASS"; else print "FAIL";}' +--let $cmd = stat -c %s $MYSQLTEST_VARDIR/mysqld.1/data/test/t1.ibd $MYSQLTEST_VARDIR/mysqld.1/data/test/t2.ibd | xargs | awk '{if (\$2/\$1 < .95) print "PASS"; else print "FAIL";}' +--echo $cmd_string +--exec $cmd + +--disable_query_log +DROP TABLE t1, t2; +eval SET GLOBAL innodb_segment_reserve_factor=$segment_reserve_factor_save; +--exec rm -f $MYSQL_VARDIR/mysqld.1/data/test/segment_reserve_factor.dat +--enable_query_log diff --git a/mysql-test/suite/sys_vars/r/innodb_segment_reserve_factor_basic.result b/mysql-test/suite/sys_vars/r/innodb_segment_reserve_factor_basic.result new file mode 100644 index 000000000000..53400f6cda9b --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_segment_reserve_factor_basic.result @@ -0,0 +1,18 @@ +SET @start_value = @@innodb_segment_reserve_factor; +SELECT @start_value; +@start_value +0.01 +SET GLOBAL innodb_segment_reserve_factor = 0.0; +Warnings: +Warning 1292 Truncated incorrect innodb_segment_reserve_factor value: '0' +SELECT @@innodb_segment_reserve_factor; +@@innodb_segment_reserve_factor +0.000300 +SET GLOBAL innodb_segment_reserve_factor = 0.1; +SELECT @@innodb_segment_reserve_factor; +@@innodb_segment_reserve_factor +0.100000 +SET GLOBAL innodb_segment_reserve_factor = @start_value; +SELECT @@innodb_segment_reserve_factor; +@@innodb_segment_reserve_factor +0.010000 diff --git a/mysql-test/suite/sys_vars/t/innodb_segment_reserve_factor_basic.test b/mysql-test/suite/sys_vars/t/innodb_segment_reserve_factor_basic.test new file mode 100644 index 000000000000..423d27c93890 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_segment_reserve_factor_basic.test @@ -0,0 +1,13 @@ +--source include/load_sysvars.inc + + +SET @start_value = @@innodb_segment_reserve_factor; +SELECT @start_value; + +SET GLOBAL innodb_segment_reserve_factor = 0.0; +SELECT @@innodb_segment_reserve_factor; +SET GLOBAL innodb_segment_reserve_factor = 0.1; +SELECT @@innodb_segment_reserve_factor; + +SET GLOBAL innodb_segment_reserve_factor = @start_value; +SELECT @@innodb_segment_reserve_factor; diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 6ecf97aaeb6a..abb8018d8410 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -50,6 +50,15 @@ Created 11/29/1995 Heikki Tuuri #include "dict0mem.h" #include "srv0start.h" +double fseg_reserve_factor = 0.01; /* If this value is x, then if + the number of unused but reserved + pages in a segment is less than + reserved pages * x, and there are + at least FSEG_FRAG_LIMIT used pages, + then we allow a new empty extent to + be added to the segment in + fseg_alloc_free_page. Otherwise, we + use unused pages of the segment. */ #ifndef UNIV_HOTBACKUP /** Flag to indicate if we have printed the tablespace full error. */ @@ -2384,7 +2393,7 @@ fseg_alloc_free_page_low( goto got_hinted_page; /*-----------------------------------------------------------*/ } else if (xdes_get_state(descr, mtr) == XDES_FREE - && reserved - used < reserved / FSEG_FILLFACTOR + && reserved - used < reserved * fseg_reserve_factor && used >= FSEG_FRAG_LIMIT) { /* 2. We allocate the free extent from space and can take @@ -2406,7 +2415,7 @@ fseg_alloc_free_page_low( goto take_hinted_page; /*-----------------------------------------------------------*/ } else if ((direction != FSP_NO_DIR) - && ((reserved - used) < reserved / FSEG_FILLFACTOR) + && ((reserved - used) < reserved * fseg_reserve_factor) && (used >= FSEG_FRAG_LIMIT) && (!!(ret_descr = fseg_alloc_free_extent(seg_inode, diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index e6fb872b6332..58e04296bb74 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -16845,6 +16845,15 @@ static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages, " not deterministic.", NULL, innodb_log_compressed_pages_update, FALSE); +static MYSQL_SYSVAR_DOUBLE(segment_reserve_factor, fseg_reserve_factor, + PLUGIN_VAR_OPCMDARG, + "If this value is x, then if the number of unused but reserved" + " pages in a segment is less than reserved pages * x, and there are" + " at least FSEG_FRAG_LIMIT used pages, then we allow a new empty extent to" + " be added to the segment in fseg_alloc_free_page. Otherwise, we" + " use unused pages of the segment.", + NULL, NULL, 0.01, 0.0003, 0.4, 0); + static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, "DEPRECATED. This option may be removed in future releases, " @@ -17624,6 +17633,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(lra_pages_before_sleep), MYSQL_SYSVAR(lra_sleep), MYSQL_SYSVAR(lra_n_spaces), + MYSQL_SYSVAR(segment_reserve_factor), MYSQL_SYSVAR(zlib_wrap), MYSQL_SYSVAR(zlib_strategy), MYSQL_SYSVAR(lru_manager_max_sleep_time), diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h index a587ccc9f20d..575eb6ff140d 100644 --- a/storage/innobase/include/fsp0fsp.h +++ b/storage/innobase/include/fsp0fsp.h @@ -36,6 +36,8 @@ Created 12/18/1995 Heikki Tuuri #include "page0types.h" #include "fsp0types.h" +extern double fseg_reserve_factor; + #endif /* !UNIV_INNOCHECKSUM */ /* @defgroup fsp_flags InnoDB Tablespace Flag Constants @{ */ @@ -255,16 +257,6 @@ typedef byte fseg_inode_t; #define FSEG_MAGIC_N_VALUE 97937874 -#define FSEG_FILLFACTOR 8 /* If this value is x, then if - the number of unused but reserved - pages in a segment is less than - reserved pages * 1/x, and there are - at least FSEG_FRAG_LIMIT used pages, - then we allow a new empty extent to - be added to the segment in - fseg_alloc_free_page. Otherwise, we - use unused pages of the segment. */ - #define FSEG_FRAG_LIMIT FSEG_FRAG_ARR_N_SLOTS /* If the segment has >= this many used pages, it may be expanded by