Skip to content

Commit

Permalink
Port Compression: Making empty space reserved dynamic to 5.6
Browse files Browse the repository at this point in the history
Summary:
* segment_reserve_factor determines the ratio of empty pages, the last
segment in an ibd can have before innodb creates a new extent. If a new
page is needed and the last segment has less than
    segment_reserve_factor * (current number of pages in this segment)
empty pages, then a new extent is created and the new page is allocated
from the new extent. The empty pages are useful when B-tree grows so
that pages in the upper level of the B-tree can be allocated
contiguously. An extent is 64 pages, and a segment is 256 extents.

Before this diff, this variable was not configurable and it was
determined by 1/x where x was the value defined by the compile time
than 1/8th pages were empty, then InnoDB would allocate a new extent
leaving many empty pages in the current extent. This caused lots of
fragmentation.

The ideal value for this variable needs investigation. The current
default will have the previous behavior. A segment has 16384 pages, so
for eg. If we are okay with leaving at most 16 empty pages per segment,
then we can set innodb_segment_reserve_factor=0.001.

innodb_segment_reserve_factor.test loads data into two identical tables
but sets a lower segment_reserve_factor before loading data to the
second table. This makes the second table about 10% smaller than the
first table.

The default value for this variable is set to 0.01 which should mean 1%
of the pages will be allocated for growth.

Test Plan: Tested on Jenkins.

Reviewers: nizamordulu, jtolmer

Reviewed By: tianx
(Original Reviewed By: nizamordulu)
  • Loading branch information
steaphangreene authored and jtolmer committed Dec 28, 2015
1 parent 413b034 commit 0fd9494
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
--innodb-file-per-table
--innodb-file-format=Barracuda
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 11 additions & 2 deletions storage/innobase/fsp/fsp0fsp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
10 changes: 10 additions & 0 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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, "
Expand Down Expand Up @@ -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),
Expand Down
12 changes: 2 additions & 10 deletions storage/innobase/include/fsp0fsp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 @{ */
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 0fd9494

Please sign in to comment.