MDEV-14795 InnoDB system tablespace cannot be shrunk

- Introduce the option :autoshrink attribute to be
added to innodb_data_file_path variable to allow
the shrinking of system tablespace during startup process.

Steps for shrinking the system tablespace:

1) Find the last used extent in system tablespace
by iterating through the BITMAP in extent descriptor pages

2) If the last used extent is lesser than user specified size
then set desired target size to user specified size.

3) Store the page contents of "to be modified" extent
descriptor pages, latches the "to be modified"
extent descriptor pages and check for buffer pool
memory availability

4) Make checkpoint to flush all pages in buffer pool, so
that pages in flush list doesn't have to use doublewrite
buffer and disable doublewrite buffer during shrinking process

5) Update the FSP_SIZE and FSP_FREE_LIMIT in header page

6) Remove the "to be truncated" pages from FSP_FREE and
FSP_FREE_FRAG list

7) Reset the bitmap in the last descriptor pages for the
"to be truncated" pages.

8) In case of multiple files, calculate the truncated last
file size and do the truncation in last file

9) Check whether mini-transaction log size doesn't exceed
the minimum value of innodb_log_buffer_size which is 2MB.
In that case, replace the modified buffer pool pages with
the page old content.

11) Commit the mini-transaction for shrinking the tablespace
and enable/disable the doublewrite buffer depends on user
specified value.

recv_sys_t::apply(): Handle the truncation of system tablespace
only if the recovered tablespace size is lesser than actual
existing size.
parent e81fa345
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
Warnings:
Warning 1287 '@@innodb_file_per_table' is deprecated and will be removed in a future release
SET UNIQUE_CHECKS=0, FOREIGN_KEY_CHECKS=0;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
COMMIT;
DROP TABLE t1;
InnoDB 0 transactions not purged
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 77594624
# restart
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 10485760
call mtr.add_suppression("InnoDB: Cannot shrink the system tablespace");
call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' init function returned error");
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
SET GLOBAL INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG=2;
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
Warnings:
Warning 1287 '@@innodb_file_per_table' is deprecated and will be removed in a future release
SET UNIQUE_CHECKS=0, FOREIGN_KEY_CHECKS=0;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
COMMIT;
DROP TABLE t1;
InnoDB 0 transactions not purged
SELECT NAME, FILE_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 540016640
# restart: --debug_dbug=+d,sys_shrink_buffer_pool_full
FOUND 1 /\[Warning\] InnoDB: Cannot shrink the system tablespace/ in mysqld.1.err
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
InnoDB YES Supports transactions, row-level locking, foreign keys and encryption for tables YES YES YES
# restart: --debug_dbug=+d,mtr_log_max_size
FOUND 1 /\[ERROR\] InnoDB: Cannot shrink the system tablespace/ in mysqld.1.err
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
InnoDB YES Supports transactions, row-level locking, foreign keys and encryption for tables YES YES YES
# restart: --debug_dbug=+d,crash_after_sys_truncate
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
# restart: --innodb_buffer_pool_size=5M
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
ENGINE SUPPORT COMMENT TRANSACTIONS XA SAVEPOINTS
InnoDB YES Supports transactions, row-level locking, foreign keys and encryption for tables YES YES YES
SELECT NAME, FILE_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE=0;
NAME FILE_SIZE
innodb_system 3145728
set global innodb_file_per_table=0;
Warnings:
Warning 1287 '@@innodb_file_per_table' is deprecated and will be removed in a future release
set global innodb_limit_optimistic_insert_debug=2;
set unique_checks=0, foreign_key_checks=0;
create table t1(f1 int not null)engine=innodb;
begin;
insert into t1 select * from seq_1_to_8192;
insert into t1 select * from seq_1_to_8192;
insert into t1 select * from seq_1_to_65536;
commit;
create table t2(f1 int not null)engine=innodb;
insert into t2 select * from seq_1_to_65536;
create table t3(f1 int not null)engine=innodb;
insert into t3 select * from seq_1_to_65536;
CREATE TABLE t4(f1 int not null)engine=innodb;
insert into t4 select * from seq_1_to_65536;
drop table t2;
drop table t4;
InnoDB 0 transactions not purged
# restart
drop table t3, t1;
--innodb_data_file_path=ibdata1:10M:autoextend:autoshrink
--innodb_sys_tablespaces
--source include/have_innodb.inc
--source include/have_sequence.inc
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
SET UNIQUE_CHECKS=0, FOREIGN_KEY_CHECKS=0;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
COMMIT;
DROP TABLE t1;
--source include/wait_all_purged.inc
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
--source include/restart_mysqld.inc
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
--innodb_data_file_path=ibdata1:1M:autoextend:autoshrink
--innodb_sys_tablespaces
--innodb_page_size=4k
--source include/have_innodb.inc
--source include/have_sequence.inc
--source include/not_embedded.inc
--source include/have_debug.inc
--source include/not_windows.inc
call mtr.add_suppression("InnoDB: Cannot shrink the system tablespace");
call mtr.add_suppression("InnoDB: Plugin initialization aborted");
call mtr.add_suppression("Plugin 'InnoDB' init function returned error");
call mtr.add_suppression("Plugin 'InnoDB' registration as a STORAGE ENGINE failed");
SET GLOBAL INNODB_LIMIT_OPTIMISTIC_INSERT_DEBUG=2;
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
SET UNIQUE_CHECKS=0, FOREIGN_KEY_CHECKS=0;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
BEGIN;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
COMMIT;
DROP TABLE t1;
--source include/wait_all_purged.inc
SELECT NAME, FILE_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE = 0;
# Ran out of buffer pool
let $restart_parameters=--debug_dbug="+d,sys_shrink_buffer_pool_full";
--source include/restart_mysqld.inc
--let SEARCH_PATTERN= \[Warning\] InnoDB: Cannot shrink the system tablespace
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
--source include/search_pattern_in_file.inc
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
# Ran out of mtr log size
let $restart_parameters=--debug_dbug="+d,mtr_log_max_size";
--source include/restart_mysqld.inc
--let SEARCH_PATTERN= \[ERROR\] InnoDB: Cannot shrink the system tablespace
let SEARCH_FILE= $MYSQLTEST_VARDIR/log/mysqld.1.err;
--source include/search_pattern_in_file.inc
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
# Crash after shrinking the system tablespace
let $restart_parameters=--debug_dbug="+d,crash_after_sys_truncate";
--source include/restart_mysqld.inc
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
let $restart_parameters=--innodb_buffer_pool_size=5M;
--source include/restart_mysqld.inc
SELECT * FROM INFORMATION_SCHEMA.ENGINES
WHERE engine = 'innodb'
AND support IN ('YES', 'DEFAULT', 'ENABLED');
SELECT NAME, FILE_SIZE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESPACES WHERE SPACE=0;
--innodb_data_file_path=ibdata1:1M:autoextend:autoshrink
--innodb_page_size=4k
--source include/big_test.inc
--source include/have_innodb.inc
--source include/have_sequence.inc
--source include/not_valgrind.inc
--source include/have_debug.inc
set global innodb_file_per_table=0;
set global innodb_limit_optimistic_insert_debug=2;
set unique_checks=0, foreign_key_checks=0;
create table t1(f1 int not null)engine=innodb;
begin;
insert into t1 select * from seq_1_to_8192;
insert into t1 select * from seq_1_to_8192;
insert into t1 select * from seq_1_to_65536;
commit;
create table t2(f1 int not null)engine=innodb;
insert into t2 select * from seq_1_to_65536;
create table t3(f1 int not null)engine=innodb;
insert into t3 select * from seq_1_to_65536;
CREATE TABLE t4(f1 int not null)engine=innodb;
insert into t4 select * from seq_1_to_65536;
drop table t2;
drop table t4;
--source include/wait_all_purged.inc
--source include/restart_mysqld.inc
drop table t3, t1;
--innodb_data_file_path=ibdata1:1M:autoextend:autoshrink
--innodb_sys_tablespaces
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
Warnings:
Warning 1287 '@@innodb_file_per_table' is deprecated and will be removed in a future release
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
DROP TABLE t1;
InnoDB 0 transactions not purged
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 70254592
# restart
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 3145728
# Incremental backup
# Prepare full backup, apply incremental one
# Restore and check results
# shutdown server
# remove datadir
# xtrabackup move back
# restart
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
NAME FILE_SIZE
innodb_system 3145728
--source include/have_innodb.inc
--source include/have_sequence.inc
let basedir=$MYSQLTEST_VARDIR/tmp/backup;
let incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1;
SET GLOBAL INNODB_FILE_PER_TABLE= 0;
CREATE TABLE t1(f1 INT NOT NULL, f2 INT NOT NULL,
f3 INT NOT NULL, INDEX(f1),
INDEX(f2), INDEX(f3))ENGINE=InnoDB;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
INSERT INTO t1 SELECT seq, seq, seq FROM seq_1_to_16384;
DROP TABLE t1;
--source ../innodb/include/wait_all_purged.inc
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
--disable_result_log
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=10 --target-dir=$basedir --throttle=1000;
--enable_result_log
--source include/restart_mysqld.inc
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
--echo # Incremental backup
exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --parallel=2 --ftwrl-wait-timeout=5 --ftwrl-wait-threshold=300 --ftwrl-wait-query-type=all --target-dir=$incremental_dir --incremental-basedir=$basedir;
--disable_result_log
echo # Prepare full backup, apply incremental one;
exec $XTRABACKUP --prepare --target-dir=$basedir;
exec $XTRABACKUP --prepare --target-dir=$basedir --incremental-dir=$incremental_dir;
echo # Restore and check results;
let $targetdir=$basedir;
-- source include/restart_and_restore.inc
--enable_result_log
SELECT NAME, FILE_SIZE FROM information_schema.innodb_sys_tablespaces WHERE SPACE = 0;
# Cleanup
rmdir $basedir;
rmdir $incremental_dir;
......@@ -668,6 +668,19 @@ fil_space_extend_must_retry(
return false;
}
bool recv_sys_t::check_sys_truncate()
{
mysql_mutex_assert_owner(&fil_system.mutex);
if (!truncated_sys_space.lsn)
return false;
if (fil_system.sys_space->size <= fil_system.sys_space->recv_size)
{
truncated_sys_space={0,0};
return false;
}
return true;
}
/** @return whether the file is usable for io() */
ATTRIBUTE_COLD bool fil_space_t::prepare_acquired()
{
......@@ -684,6 +697,8 @@ ATTRIBUTE_COLD bool fil_space_t::prepare_acquired()
else if (node->deferred);
else if (auto desired_size= recv_size)
{
if (id == TRX_SYS_SPACE && recv_sys.check_sys_truncate())
goto clear;
bool success;
while (fil_space_extend_must_retry(this, node, desired_size, &success))
mysql_mutex_lock(&fil_system.mutex);
......
This diff is collapsed.
......@@ -100,6 +100,7 @@ SysTablespace::parse_params(
ut_ad(m_last_file_size_max == 0);
ut_ad(!m_auto_extend_last_file);
ut_ad(!m_auto_shrink);
char* new_str = mem_strdup(filepath_spec);
char* str = new_str;
......@@ -146,6 +147,11 @@ SysTablespace::parse_params(
str = parse_units(str, &size);
}
if (0 == strncmp(str, ":autoshrink",
(sizeof ":autoshrink") - 1)) {
str += (sizeof ":autoshrink") - 1;
}
if (*str != '\0') {
ut_free(new_str);
ib::error()
......@@ -266,6 +272,12 @@ SysTablespace::parse_params(
str = parse_units(str, &m_last_file_size_max);
}
if (0 == strncmp(str, ":autoshrink",
(sizeof ":autoshrink") - 1)) {
str += (sizeof ":autoshrink") - 1;
m_auto_shrink = true;
}
if (*str != '\0') {
ut_free(new_str);
ib::error() << "syntax error in file path or"
......@@ -333,6 +345,7 @@ SysTablespace::shutdown()
m_created_new_raw = 0;
m_is_tablespace_full = false;
m_sanity_checks_done = false;
m_auto_shrink = false;
}
/** Verify the size of the physical file.
......@@ -974,6 +987,7 @@ SysTablespace::normalize_size()
for (files_t::iterator it = m_files.begin(); it != end; ++it) {
it->m_size <<= (20U - srv_page_size_shift);
it->m_user_param_size = it->m_size;
}
m_last_file_size_max <<= (20U - srv_page_size_shift);
......
......@@ -35,8 +35,8 @@ Created 11/28/1995 Heikki Tuuri
@param[in] page page number
@param[in] boffset byte offset
@param[in,out] mtr mini-transaction */
static void flst_write_addr(const buf_block_t& block, byte *faddr,
uint32_t page, uint16_t boffset, mtr_t* mtr)
void flst_write_addr(const buf_block_t &block, byte *faddr,
uint32_t page, uint16_t boffset, mtr_t *mtr)
{
ut_ad(mtr->memo_contains_page_flagged(faddr, MTR_MEMO_PAGE_X_FIX |
MTR_MEMO_PAGE_SX_FIX));
......
......@@ -317,6 +317,8 @@ class Datafile {
void set_space_id(uint32_t space_id) { m_space_id= space_id; }
void set_flags(uint32_t flags) { m_flags = flags; }
uint32_t param_size() const { return m_user_param_size; }
private:
/** Free the filepath buffer. */
void free_filepath();
......@@ -406,6 +408,9 @@ class Datafile {
pages in SysTablespace::normalize_size() */
uint32_t m_size;
/** Size in pages; Initial parameter size */
uint32_t m_user_param_size;
/** ordinal position of this datafile in the tablespace */
ulint m_order;
......
......@@ -573,6 +573,9 @@ inline void fsp_init_file_page(
mtr->init(block);
}
/** Truncate the system tablespace */
void fsp_system_tablespace_truncate();
#ifndef UNIV_DEBUG
# define fsp_init_file_page(space, block, mtr) fsp_init_file_page(block, mtr)
#endif
......
......@@ -119,6 +119,12 @@ class SysTablespace : public Tablespace
return(m_auto_extend_last_file);
}
/** @return auto shrink */
bool can_auto_shrink() const
{
return m_auto_shrink;
}
/** Set the last file size.
@param[in] size the size to set */
void set_last_file_size(uint32_t size)
......@@ -143,6 +149,16 @@ class SysTablespace : public Tablespace
<< (20 - srv_page_size_shift);
}
/**
@return user specified tablespace size */
uint32_t get_min_size() const
{
uint32_t full_size= 0;
for (uint32_t i= 0; i < m_files.size(); i++)
full_size+= m_files.at(i).m_user_param_size;
return full_size;
}
/**
@return next increment size */
uint32_t get_increment() const;
......@@ -251,6 +267,10 @@ class SysTablespace : public Tablespace
/** if false, then sanity checks are still pending */
bool m_sanity_checks_done;
/** Shrink the system tablespace if the value is
enabled */
bool m_auto_shrink;
};
/* GLOBAL OBJECTS */
......
......@@ -148,6 +148,15 @@ inline fil_addr_t flst_get_prev_addr(const flst_node_t *node)
return flst_read_addr(node + FLST_PREV);
}
/** Write a file address.
@param[in] block file page
@param[in,out] faddr file address location
@param[in] page page number
@param[in] boffset byte offset
@param[in,out] mtr mini-transaction */
void flst_write_addr(const buf_block_t &block, byte *faddr,
uint32_t page, uint16_t boffset, mtr_t *mtr);
# ifdef UNIV_DEBUG
/** Validate a file-based list. */
void flst_validate(const buf_block_t *base, uint16_t boffset, mtr_t *mtr);
......
......@@ -235,7 +235,10 @@ struct recv_sys_t
lsn_t lsn;
/** truncated size of the tablespace, or 0 if not truncated */
unsigned pages;
} truncated_undo_spaces[127];
};
trunc truncated_undo_spaces[127];
trunc truncated_sys_space;
public:
/** The contents of the doublewrite buffer */
......@@ -260,6 +263,12 @@ struct recv_sys_t
pages_it= pages.end();
}
/** Allow to apply system tablespace truncate redo log only
if the size to be extended is lesser than current size.
@retval true To apply the truncate shrink redo log record
@retval false otherwise */
bool check_sys_truncate();
private:
/** Attempt to initialize a page based on redo log records.
@param p iterator
......
......@@ -1319,6 +1319,7 @@ void recv_sys_t::create()
recv_max_page_lsn = 0;
memset(truncated_undo_spaces, 0, sizeof truncated_undo_spaces);
truncated_sys_space= {0, 0};
UT_LIST_INIT(blocks, &buf_block_t::unzip_LRU);
}
......@@ -2665,23 +2666,28 @@ recv_sys_t::parse_mtr_result recv_sys_t::parse(source &l, bool if_exists)
cl= l.copy_if_needed(iv, decrypt_buf, recs, rlen);
if (rlen == 1 && *cl == TRIM_PAGES)
{
#if 0 /* For now, we can only truncate an undo log tablespace */
if (UNIV_UNLIKELY(!space_id || !page_no))
goto record_corrupted;
#else
if (!srv_is_undo_tablespace(space_id) ||
page_no != SRV_UNDO_TABLESPACE_SIZE_IN_PAGES)
goto record_corrupted;
if (srv_is_undo_tablespace(space_id))
{
if (page_no != SRV_UNDO_TABLESPACE_SIZE_IN_PAGES)
goto record_corrupted;
/* The entire undo tablespace will be reinitialized by
innodb_undo_log_truncate=ON. Discard old log for all
pages. */
trim({space_id, 0}, start_lsn);
truncated_undo_spaces[space_id - srv_undo_space_id_start]=
{ start_lsn, page_no};
}
else if (space_id != 0) goto record_corrupted;
else
{
/* Shrink the system tablespace */
trim({space_id, page_no}, start_lsn);
truncated_sys_space= {start_lsn, page_no};
}
static_assert(UT_ARR_SIZE(truncated_undo_spaces) ==
TRX_SYS_MAX_UNDO_SPACES, "compatibility");
/* The entire undo tablespace will be reinitialized by
innodb_undo_log_truncate=ON. Discard old log for all pages. */
trim({space_id, 0}, start_lsn);
truncated_undo_spaces[space_id - srv_undo_space_id_start]=
{ start_lsn, page_no };
if (!store && undo_space_trunc)
if (!store && undo_space_trunc && space_id)
undo_space_trunc(space_id);
#endif
last_offset= 1; /* the next record must not be same_page */
continue;
}
......@@ -3723,6 +3729,30 @@ void recv_sys_t::apply(bool last_batch)
apply_log_recs= true;
if (truncated_sys_space.lsn)
{
trim({0, truncated_sys_space.pages}, truncated_sys_space.lsn);
fil_node_t *file= UT_LIST_GET_LAST(fil_system.sys_space->chain);
ut_ad(file->is_open());
/* Last file new size after truncation */
uint32_t new_last_file_size=
truncated_sys_space.pages -
(srv_sys_space.get_min_size()
- srv_sys_space.m_files.at(
srv_sys_space.m_files.size() - 1). param_size());
os_file_truncate(
file->name, file->handle,
os_offset_t{new_last_file_size} << srv_page_size_shift, true);
mysql_mutex_lock(&fil_system.mutex);
fil_system.sys_space->size= truncated_sys_space.pages;
fil_system.sys_space->chain.end->size= new_last_file_size;
srv_sys_space.set_last_file_size(new_last_file_size);
truncated_sys_space={0, 0};
mysql_mutex_unlock(&fil_system.mutex);
}
for (auto id= srv_undo_tablespaces_open; id--;)
{
const trunc& t= truncated_undo_spaces[id];
......
......@@ -495,12 +495,11 @@ void mtr_t::commit_shrink(fil_space_t &space)
ut_ad(is_active());
ut_ad(!high_level_read_only);
ut_ad(m_modifications);
ut_ad(m_made_dirty);
ut_ad(!space.id || m_made_dirty);
ut_ad(!m_memo.empty());
ut_ad(!recv_recovery_is_on());
ut_ad(m_log_mode == MTR_LOG_ALL);
ut_ad(!m_freed_pages);
ut_ad(UT_LIST_GET_LEN(space.chain) == 1);
log_write_and_flush_prepare();
m_latch_ex= true;
......@@ -515,8 +514,9 @@ void mtr_t::commit_shrink(fil_space_t &space)
ut_ad(log_sys.latch.is_write_locked());
#endif
os_file_truncate(space.chain.start->name, space.chain.start->handle,
os_offset_t{space.size} << srv_page_size_shift, true);
os_file_truncate(
space.chain.end->name, space.chain.end->handle,
os_offset_t{space.chain.end->size} << srv_page_size_shift, true);
space.clear_freed_ranges();
......
......@@ -1733,6 +1733,13 @@ dberr_t srv_start(bool create_new_db)
ut_ad(high_level_read_only
|| srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN);
if (!high_level_read_only
&& srv_sys_space.can_auto_shrink()) {
fsp_system_tablespace_truncate();
DBUG_EXECUTE_IF("crash_after_sys_truncate",
return srv_init_abort(DB_ERROR););
}
/* Validate a few system page types that were left
uninitialized before MySQL or MariaDB 5.5. */
if (!high_level_read_only
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment