mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-13564: Remove old crash-upgrade logic in 10.4
Stop supporting the additional *trunc.log files that were introduced via MySQL 5.7 to MariaDB Server 10.2 and 10.3. DB_TABLESPACE_TRUNCATED: Remove. purge_sys.truncate: A new structure to track undo tablespace file truncation. srv_start(): Remove the call to buf_pool_invalidate(). It is no longer necessary, given that we no longer access things in ways that violate the ARIES protocol. This call was originally added for innodb_file_format, and it may later have been necessary for the proper function of the MySQL 5.7 TRUNCATE recovery, which we are now removing. trx_purge_cleanse_purge_queue(): Take the undo tablespace as a parameter. trx_purge_truncate_history(): Rewrite everything mostly in a single function, replacing references to undo::Truncate. recv_apply_hashed_log_recs(): If any redo log is to be applied, and if the log_sys.log.subformat indicates that separately logged truncate may have been used, refuse to proceed except if innodb_force_recovery is set. We will still refuse crash-upgrade if TRUNCATE TABLE was logged. Undo tablespace truncation would only be logged in undo*trunc.log files, which we are no longer checking for.
This commit is contained in:
@@ -628,15 +628,6 @@ static void backup_optimized_ddl_op(ulint space_id)
|
|||||||
pthread_mutex_unlock(&backup_mutex);
|
pthread_mutex_unlock(&backup_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Callback whenever MLOG_TRUNCATE happens. */
|
|
||||||
static void backup_truncate_fail()
|
|
||||||
{
|
|
||||||
msg("mariabackup: Incompatible TRUNCATE operation detected.%s\n",
|
|
||||||
opt_lock_ddl_per_table
|
|
||||||
? ""
|
|
||||||
: " Use --lock-ddl-per-table to lock all tables before backup.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ======== Date copying thread context ======== */
|
/* ======== Date copying thread context ======== */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -4179,7 +4170,6 @@ fail_before_log_copying_thread_start:
|
|||||||
log_copy_scanned_lsn = checkpoint_lsn_start;
|
log_copy_scanned_lsn = checkpoint_lsn_start;
|
||||||
recv_sys->recovered_lsn = log_copy_scanned_lsn;
|
recv_sys->recovered_lsn = log_copy_scanned_lsn;
|
||||||
log_optimized_ddl_op = backup_optimized_ddl_op;
|
log_optimized_ddl_op = backup_optimized_ddl_op;
|
||||||
log_truncate = backup_truncate_fail;
|
|
||||||
|
|
||||||
if (xtrabackup_copy_logfile())
|
if (xtrabackup_copy_logfile())
|
||||||
goto fail_before_log_copying_thread_start;
|
goto fail_before_log_copying_thread_start;
|
||||||
|
@@ -125,13 +125,13 @@ WHERE engine = 'innodb'
|
|||||||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
1
|
1
|
||||||
FOUND 2 /InnoDB: Upgrading redo log:/ in mysqld.1.err
|
FOUND 3 /InnoDB: Upgrading redo log:/ in mysqld.1.err
|
||||||
# Minimal MariaDB 10.1.21 encrypted redo log
|
# Minimal MariaDB 10.1.21 encrypted redo log
|
||||||
SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
|
SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
|
||||||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||||
1
|
1
|
||||||
1
|
1
|
||||||
FOUND 2 /InnoDB: Encrypting redo log/ in mysqld.1.err
|
FOUND 1 /InnoDB: Encrypting redo log/ in mysqld.1.err
|
||||||
ib_buffer_pool
|
ib_buffer_pool
|
||||||
ib_logfile0
|
ib_logfile0
|
||||||
ib_logfile1
|
ib_logfile1
|
||||||
|
@@ -125,7 +125,7 @@ WHERE engine = 'innodb'
|
|||||||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||||
COUNT(*)
|
COUNT(*)
|
||||||
1
|
1
|
||||||
FOUND 2 /InnoDB: Upgrading redo log:/ in mysqld.1.err
|
FOUND 3 /InnoDB: Upgrading redo log:/ in mysqld.1.err
|
||||||
# Minimal MariaDB 10.1.21 encrypted redo log
|
# Minimal MariaDB 10.1.21 encrypted redo log
|
||||||
SELECT * FROM INFORMATION_SCHEMA.ENGINES
|
SELECT * FROM INFORMATION_SCHEMA.ENGINES
|
||||||
WHERE engine = 'innodb'
|
WHERE engine = 'innodb'
|
||||||
|
@@ -113,7 +113,6 @@ SET(INNOBASE_SOURCES
|
|||||||
row/row0purge.cc
|
row/row0purge.cc
|
||||||
row/row0row.cc
|
row/row0row.cc
|
||||||
row/row0sel.cc
|
row/row0sel.cc
|
||||||
row/row0trunc.cc
|
|
||||||
row/row0uins.cc
|
row/row0uins.cc
|
||||||
row/row0umod.cc
|
row/row0umod.cc
|
||||||
row/row0undo.cc
|
row/row0undo.cc
|
||||||
@@ -179,7 +178,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
|||||||
mtr/mtr0mtr.cc
|
mtr/mtr0mtr.cc
|
||||||
row/row0merge.cc
|
row/row0merge.cc
|
||||||
row/row0mysql.cc
|
row/row0mysql.cc
|
||||||
row/row0trunc.cc
|
|
||||||
srv/srv0srv.cc
|
srv/srv0srv.cc
|
||||||
COMPILE_FLAGS "-O0"
|
COMPILE_FLAGS "-O0"
|
||||||
)
|
)
|
||||||
|
@@ -438,7 +438,7 @@ btr_page_create(
|
|||||||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||||
|
|
||||||
if (page_zip) {
|
if (page_zip) {
|
||||||
page_create_zip(block, index, level, 0, NULL, mtr);
|
page_create_zip(block, index, level, 0, mtr);
|
||||||
} else {
|
} else {
|
||||||
page_create(block, mtr, dict_table_is_comp(index->table),
|
page_create(block, mtr, dict_table_is_comp(index->table),
|
||||||
dict_index_is_spatial(index));
|
dict_index_is_spatial(index));
|
||||||
@@ -1179,21 +1179,18 @@ btr_free_root_check(
|
|||||||
|
|
||||||
/** Create the root node for a new index tree.
|
/** Create the root node for a new index tree.
|
||||||
@param[in] type type of the index
|
@param[in] type type of the index
|
||||||
@param[in,out] space tablespace where created
|
|
||||||
@param[in] index_id index id
|
@param[in] index_id index id
|
||||||
@param[in] index index, or NULL when applying TRUNCATE
|
@param[in,out] space tablespace where created
|
||||||
log record during recovery
|
@param[in] index index
|
||||||
@param[in] btr_redo_create_info used for applying TRUNCATE log
|
@param[in,out] mtr mini-transaction
|
||||||
@param[in] mtr mini-transaction handle
|
@return page number of the created root
|
||||||
record during recovery
|
@retval FIL_NULL if did not succeed */
|
||||||
@return page number of the created root, FIL_NULL if did not succeed */
|
|
||||||
ulint
|
ulint
|
||||||
btr_create(
|
btr_create(
|
||||||
ulint type,
|
ulint type,
|
||||||
fil_space_t* space,
|
fil_space_t* space,
|
||||||
index_id_t index_id,
|
index_id_t index_id,
|
||||||
dict_index_t* index,
|
dict_index_t* index,
|
||||||
const btr_create_t* btr_redo_create_info,
|
|
||||||
mtr_t* mtr)
|
mtr_t* mtr)
|
||||||
{
|
{
|
||||||
buf_block_t* block;
|
buf_block_t* block;
|
||||||
@@ -1208,7 +1205,7 @@ btr_create(
|
|||||||
(for an ibuf tree, not in the root, but on a separate ibuf header
|
(for an ibuf tree, not in the root, but on a separate ibuf header
|
||||||
page) */
|
page) */
|
||||||
|
|
||||||
if (type & DICT_IBUF) {
|
if (UNIV_UNLIKELY(type & DICT_IBUF)) {
|
||||||
/* Allocate first the ibuf header page */
|
/* Allocate first the ibuf header page */
|
||||||
buf_block_t* ibuf_hdr_block = fseg_create(
|
buf_block_t* ibuf_hdr_block = fseg_create(
|
||||||
space, 0,
|
space, 0,
|
||||||
@@ -1273,44 +1270,11 @@ btr_create(
|
|||||||
page_zip = buf_block_get_page_zip(block);
|
page_zip = buf_block_get_page_zip(block);
|
||||||
|
|
||||||
if (page_zip) {
|
if (page_zip) {
|
||||||
if (index != NULL) {
|
page = page_create_zip(block, index, 0, 0, mtr);
|
||||||
page = page_create_zip(block, index, 0, 0, NULL, mtr);
|
|
||||||
} else {
|
} else {
|
||||||
/* Create a compressed index page when applying
|
|
||||||
TRUNCATE log record during recovery */
|
|
||||||
ut_ad(btr_redo_create_info != NULL);
|
|
||||||
|
|
||||||
redo_page_compress_t page_comp_info;
|
|
||||||
|
|
||||||
page_comp_info.type = type;
|
|
||||||
|
|
||||||
page_comp_info.index_id = index_id;
|
|
||||||
|
|
||||||
page_comp_info.n_fields =
|
|
||||||
btr_redo_create_info->n_fields;
|
|
||||||
|
|
||||||
page_comp_info.field_len =
|
|
||||||
btr_redo_create_info->field_len;
|
|
||||||
|
|
||||||
page_comp_info.fields = btr_redo_create_info->fields;
|
|
||||||
|
|
||||||
page_comp_info.trx_id_pos =
|
|
||||||
btr_redo_create_info->trx_id_pos;
|
|
||||||
|
|
||||||
page = page_create_zip(block, NULL, 0, 0,
|
|
||||||
&page_comp_info, mtr);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (index != NULL) {
|
|
||||||
page = page_create(block, mtr,
|
page = page_create(block, mtr,
|
||||||
dict_table_is_comp(index->table),
|
dict_table_is_comp(index->table),
|
||||||
dict_index_is_spatial(index));
|
dict_index_is_spatial(index));
|
||||||
} else {
|
|
||||||
ut_ad(btr_redo_create_info != NULL);
|
|
||||||
page = page_create(
|
|
||||||
block, mtr, btr_redo_create_info->format_flags,
|
|
||||||
type == DICT_SPATIAL);
|
|
||||||
}
|
|
||||||
/* Set the level of the new index page */
|
/* Set the level of the new index page */
|
||||||
btr_page_set_level(page, NULL, 0, mtr);
|
btr_page_set_level(page, NULL, 0, mtr);
|
||||||
}
|
}
|
||||||
@@ -1322,18 +1286,14 @@ btr_create(
|
|||||||
btr_page_set_next(page, page_zip, FIL_NULL, mtr);
|
btr_page_set_next(page, page_zip, FIL_NULL, mtr);
|
||||||
btr_page_set_prev(page, page_zip, FIL_NULL, mtr);
|
btr_page_set_prev(page, page_zip, FIL_NULL, mtr);
|
||||||
|
|
||||||
/* We reset the free bits for the page to allow creation of several
|
/* We reset the free bits for the page in a separate
|
||||||
trees in the same mtr, otherwise the latch on a bitmap page would
|
mini-transaction to allow creation of several trees in the
|
||||||
prevent it because of the latching order.
|
same mtr, otherwise the latch on a bitmap page would prevent
|
||||||
|
it because of the latching order.
|
||||||
index will be NULL if we are recreating the table during recovery
|
|
||||||
on behalf of TRUNCATE.
|
|
||||||
|
|
||||||
Note: Insert Buffering is disabled for temporary tables given that
|
Note: Insert Buffering is disabled for temporary tables given that
|
||||||
most temporary tables are smaller in size and short-lived. */
|
most temporary tables are smaller in size and short-lived. */
|
||||||
if (!(type & DICT_CLUSTERED)
|
if (!(type & DICT_CLUSTERED) && !index->table->is_temporary()) {
|
||||||
&& (index == NULL || !index->table->is_temporary())) {
|
|
||||||
|
|
||||||
ibuf_reset_free_bits(block);
|
ibuf_reset_free_bits(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1675,7 +1635,7 @@ btr_page_reorganize_low(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (page_zip
|
if (page_zip
|
||||||
&& !page_zip_compress(page_zip, page, index, z_level, NULL, mtr)) {
|
&& !page_zip_compress(page_zip, page, index, z_level, mtr)) {
|
||||||
|
|
||||||
/* Restore the old page and exit. */
|
/* Restore the old page and exit. */
|
||||||
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
|
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
|
||||||
@@ -1924,7 +1884,7 @@ btr_page_empty(
|
|||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
if (page_zip) {
|
if (page_zip) {
|
||||||
page_create_zip(block, index, level, autoinc, NULL, mtr);
|
page_create_zip(block, index, level, autoinc, mtr);
|
||||||
} else {
|
} else {
|
||||||
page_create(block, mtr, dict_table_is_comp(index->table),
|
page_create(block, mtr, dict_table_is_comp(index->table),
|
||||||
dict_index_is_spatial(index));
|
dict_index_is_spatial(index));
|
||||||
|
@@ -94,7 +94,7 @@ PageBulk::init()
|
|||||||
|
|
||||||
if (new_page_zip) {
|
if (new_page_zip) {
|
||||||
page_create_zip(new_block, m_index, m_level, 0,
|
page_create_zip(new_block, m_index, m_level, 0,
|
||||||
NULL, &m_mtr);
|
&m_mtr);
|
||||||
memset(FIL_PAGE_PREV + new_page, 0xff, 8);
|
memset(FIL_PAGE_PREV + new_page, 0xff, 8);
|
||||||
page_zip_write_header(new_page_zip,
|
page_zip_write_header(new_page_zip,
|
||||||
FIL_PAGE_PREV + new_page,
|
FIL_PAGE_PREV + new_page,
|
||||||
@@ -374,7 +374,7 @@ PageBulk::compress()
|
|||||||
ut_ad(m_page_zip != NULL);
|
ut_ad(m_page_zip != NULL);
|
||||||
|
|
||||||
return(page_zip_compress(m_page_zip, m_page, m_index,
|
return(page_zip_compress(m_page_zip, m_page, m_index,
|
||||||
page_zip_level, NULL, &m_mtr));
|
page_zip_level, &m_mtr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get node pointer
|
/** Get node pointer
|
||||||
|
@@ -6248,7 +6248,6 @@ database_corrupted:
|
|||||||
&& !recv_no_ibuf_operations
|
&& !recv_no_ibuf_operations
|
||||||
&& (bpage->id.space() == 0
|
&& (bpage->id.space() == 0
|
||||||
|| !is_predefined_tablespace(bpage->id.space()))
|
|| !is_predefined_tablespace(bpage->id.space()))
|
||||||
&& !srv_is_tablespace_truncated(bpage->id.space())
|
|
||||||
&& fil_page_get_type(frame) == FIL_PAGE_INDEX
|
&& fil_page_get_type(frame) == FIL_PAGE_INDEX
|
||||||
&& page_is_leaf(frame)) {
|
&& page_is_leaf(frame)) {
|
||||||
|
|
||||||
|
@@ -556,12 +556,9 @@ buf_dblwr_process()
|
|||||||
|
|
||||||
if (page_no >= space->size) {
|
if (page_no >= space->size) {
|
||||||
|
|
||||||
/* Do not report the warning if the tablespace
|
/* Do not report the warning for undo
|
||||||
is scheduled for truncation or was truncated
|
tablespaces, because they can be truncated in place. */
|
||||||
and we have parsed an MLOG_TRUNCATE record. */
|
if (!srv_is_undo_tablespace(space_id)) {
|
||||||
if (!srv_is_tablespace_truncated(space_id)
|
|
||||||
&& !srv_was_tablespace_truncated(space)
|
|
||||||
&& !srv_is_undo_tablespace(space_id)) {
|
|
||||||
ib::warn() << "A copy of page " << page_id
|
ib::warn() << "A copy of page " << page_id
|
||||||
<< " in the doublewrite buffer slot "
|
<< " in the doublewrite buffer slot "
|
||||||
<< page_no_dblwr
|
<< page_no_dblwr
|
||||||
|
@@ -95,11 +95,9 @@ buffer buf_pool if it is not already there, in which case does nothing.
|
|||||||
Sets the io_fix flag and sets an exclusive lock on the buffer frame. The
|
Sets the io_fix flag and sets an exclusive lock on the buffer frame. The
|
||||||
flag is cleared and the x-lock released by an i/o-handler thread.
|
flag is cleared and the x-lock released by an i/o-handler thread.
|
||||||
|
|
||||||
@param[out] err DB_SUCCESS, DB_TABLESPACE_DELETED or
|
@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
|
||||||
DB_TABLESPACE_TRUNCATED if we are trying
|
if we are trying
|
||||||
to read from a non-existent tablespace, a
|
to read from a non-existent tablespace
|
||||||
tablespace which is just now being dropped,
|
|
||||||
or a tablespace which is truncated
|
|
||||||
@param[in] sync true if synchronous aio is desired
|
@param[in] sync true if synchronous aio is desired
|
||||||
@param[in] type IO type, SIMULATED, IGNORE_MISSING
|
@param[in] type IO type, SIMULATED, IGNORE_MISSING
|
||||||
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
|
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
|
||||||
@@ -187,19 +185,7 @@ buf_read_page_low(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (*err != DB_SUCCESS) {
|
if (*err != DB_SUCCESS) {
|
||||||
if (*err == DB_TABLESPACE_TRUNCATED) {
|
if (IORequest::ignore_missing(type)
|
||||||
/* Remove the page which is outside the
|
|
||||||
truncated tablespace bounds when recovering
|
|
||||||
from a crash happened during a truncation */
|
|
||||||
buf_read_page_handle_error(bpage);
|
|
||||||
if (recv_recovery_on) {
|
|
||||||
mutex_enter(&recv_sys->mutex);
|
|
||||||
ut_ad(recv_sys->n_addrs > 0);
|
|
||||||
recv_sys->n_addrs--;
|
|
||||||
mutex_exit(&recv_sys->mutex);
|
|
||||||
}
|
|
||||||
return(0);
|
|
||||||
} else if (IORequest::ignore_missing(type)
|
|
||||||
|| *err == DB_TABLESPACE_DELETED) {
|
|| *err == DB_TABLESPACE_DELETED) {
|
||||||
buf_read_page_handle_error(bpage);
|
buf_read_page_handle_error(bpage);
|
||||||
return(0);
|
return(0);
|
||||||
@@ -369,7 +355,6 @@ read_ahead:
|
|||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case DB_SUCCESS:
|
case DB_SUCCESS:
|
||||||
case DB_TABLESPACE_TRUNCATED:
|
|
||||||
case DB_ERROR:
|
case DB_ERROR:
|
||||||
break;
|
break;
|
||||||
case DB_TABLESPACE_DELETED:
|
case DB_TABLESPACE_DELETED:
|
||||||
@@ -472,7 +457,6 @@ buf_read_page_background(
|
|||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case DB_SUCCESS:
|
case DB_SUCCESS:
|
||||||
case DB_TABLESPACE_TRUNCATED:
|
|
||||||
case DB_ERROR:
|
case DB_ERROR:
|
||||||
break;
|
break;
|
||||||
case DB_TABLESPACE_DELETED:
|
case DB_TABLESPACE_DELETED:
|
||||||
@@ -755,7 +739,6 @@ buf_read_ahead_linear(
|
|||||||
|
|
||||||
switch (err) {
|
switch (err) {
|
||||||
case DB_SUCCESS:
|
case DB_SUCCESS:
|
||||||
case DB_TABLESPACE_TRUNCATED:
|
|
||||||
case DB_TABLESPACE_DELETED:
|
case DB_TABLESPACE_DELETED:
|
||||||
case DB_ERROR:
|
case DB_ERROR:
|
||||||
break;
|
break;
|
||||||
@@ -853,7 +836,6 @@ tablespace_deleted:
|
|||||||
|
|
||||||
switch(err) {
|
switch(err) {
|
||||||
case DB_SUCCESS:
|
case DB_SUCCESS:
|
||||||
case DB_TABLESPACE_TRUNCATED:
|
|
||||||
case DB_ERROR:
|
case DB_ERROR:
|
||||||
break;
|
break;
|
||||||
case DB_TABLESPACE_DELETED:
|
case DB_TABLESPACE_DELETED:
|
||||||
|
@@ -214,7 +214,7 @@ dict_hdr_create(
|
|||||||
/*--------------------------*/
|
/*--------------------------*/
|
||||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||||
fil_system.sys_space, DICT_TABLES_ID,
|
fil_system.sys_space, DICT_TABLES_ID,
|
||||||
dict_ind_redundant, NULL, mtr);
|
dict_ind_redundant, mtr);
|
||||||
if (root_page_no == FIL_NULL) {
|
if (root_page_no == FIL_NULL) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@@ -225,7 +225,7 @@ dict_hdr_create(
|
|||||||
/*--------------------------*/
|
/*--------------------------*/
|
||||||
root_page_no = btr_create(DICT_UNIQUE,
|
root_page_no = btr_create(DICT_UNIQUE,
|
||||||
fil_system.sys_space, DICT_TABLE_IDS_ID,
|
fil_system.sys_space, DICT_TABLE_IDS_ID,
|
||||||
dict_ind_redundant, NULL, mtr);
|
dict_ind_redundant, mtr);
|
||||||
if (root_page_no == FIL_NULL) {
|
if (root_page_no == FIL_NULL) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@@ -236,7 +236,7 @@ dict_hdr_create(
|
|||||||
/*--------------------------*/
|
/*--------------------------*/
|
||||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||||
fil_system.sys_space, DICT_COLUMNS_ID,
|
fil_system.sys_space, DICT_COLUMNS_ID,
|
||||||
dict_ind_redundant, NULL, mtr);
|
dict_ind_redundant, mtr);
|
||||||
if (root_page_no == FIL_NULL) {
|
if (root_page_no == FIL_NULL) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@@ -247,7 +247,7 @@ dict_hdr_create(
|
|||||||
/*--------------------------*/
|
/*--------------------------*/
|
||||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||||
fil_system.sys_space, DICT_INDEXES_ID,
|
fil_system.sys_space, DICT_INDEXES_ID,
|
||||||
dict_ind_redundant, NULL, mtr);
|
dict_ind_redundant, mtr);
|
||||||
if (root_page_no == FIL_NULL) {
|
if (root_page_no == FIL_NULL) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
@@ -258,7 +258,7 @@ dict_hdr_create(
|
|||||||
/*--------------------------*/
|
/*--------------------------*/
|
||||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||||
fil_system.sys_space, DICT_FIELDS_ID,
|
fil_system.sys_space, DICT_FIELDS_ID,
|
||||||
dict_ind_redundant, NULL, mtr);
|
dict_ind_redundant, mtr);
|
||||||
if (root_page_no == FIL_NULL) {
|
if (root_page_no == FIL_NULL) {
|
||||||
|
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
|
@@ -863,7 +863,7 @@ dict_create_index_tree_step(
|
|||||||
|
|
||||||
node->page_no = btr_create(
|
node->page_no = btr_create(
|
||||||
index->type, index->table->space,
|
index->type, index->table->space,
|
||||||
index->id, index, NULL, &mtr);
|
index->id, index, &mtr);
|
||||||
|
|
||||||
if (node->page_no == FIL_NULL) {
|
if (node->page_no == FIL_NULL) {
|
||||||
err = DB_OUT_OF_FILE_SPACE;
|
err = DB_OUT_OF_FILE_SPACE;
|
||||||
@@ -909,7 +909,7 @@ dict_create_index_tree_in_mem(
|
|||||||
ut_ad(!(index->table->flags2 & DICT_TF2_DISCARDED));
|
ut_ad(!(index->table->flags2 & DICT_TF2_DISCARDED));
|
||||||
|
|
||||||
index->page = btr_create(index->type, index->table->space,
|
index->page = btr_create(index->type, index->table->space,
|
||||||
index->id, index, NULL, &mtr);
|
index->id, index, &mtr);
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
index->trx_id = trx->id;
|
index->trx_id = trx->id;
|
||||||
@@ -975,13 +975,6 @@ dict_drop_index_tree(
|
|||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If tablespace is scheduled for truncate, do not try to drop
|
|
||||||
the indexes in that tablespace. There is a truncate fixup action
|
|
||||||
which will take care of it. */
|
|
||||||
if (srv_is_tablespace_truncated(space)) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
btr_free_if_exists(page_id_t(space, root_page_no), page_size,
|
btr_free_if_exists(page_id_t(space, root_page_no), page_size,
|
||||||
mach_read_from_8(ptr), mtr);
|
mach_read_from_8(ptr), mtr);
|
||||||
|
|
||||||
@@ -1057,7 +1050,7 @@ dict_recreate_index_tree(
|
|||||||
ulint root_page_no = (index->type & DICT_FTS)
|
ulint root_page_no = (index->type & DICT_FTS)
|
||||||
? FIL_NULL
|
? FIL_NULL
|
||||||
: btr_create(type, table->space,
|
: btr_create(type, table->space,
|
||||||
index_id, index, NULL, mtr);
|
index_id, index, mtr);
|
||||||
index->page = unsigned(root_page_no);
|
index->page = unsigned(root_page_no);
|
||||||
return root_page_no;
|
return root_page_no;
|
||||||
}
|
}
|
||||||
|
@@ -45,7 +45,6 @@ Created 10/25/1995 Heikki Tuuri
|
|||||||
#include "os0file.h"
|
#include "os0file.h"
|
||||||
#include "page0zip.h"
|
#include "page0zip.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "srv0start.h"
|
#include "srv0start.h"
|
||||||
#include "trx0purge.h"
|
#include "trx0purge.h"
|
||||||
#include "ut0new.h"
|
#include "ut0new.h"
|
||||||
@@ -553,8 +552,7 @@ fil_node_open_file(
|
|||||||
if (first_time_open
|
if (first_time_open
|
||||||
|| (space->purpose == FIL_TYPE_TABLESPACE
|
|| (space->purpose == FIL_TYPE_TABLESPACE
|
||||||
&& node == UT_LIST_GET_FIRST(space->chain)
|
&& node == UT_LIST_GET_FIRST(space->chain)
|
||||||
&& srv_startup_is_before_trx_rollback_phase
|
&& srv_startup_is_before_trx_rollback_phase)) {
|
||||||
&& !undo::Truncate::was_tablespace_truncated(space->id))) {
|
|
||||||
/* We do not know the size of the file yet. First we
|
/* We do not know the size of the file yet. First we
|
||||||
open the file in the normal mode, no async I/O here,
|
open the file in the normal mode, no async I/O here,
|
||||||
for simplicity. Then do some checks, and close the
|
for simplicity. Then do some checks, and close the
|
||||||
@@ -4241,7 +4239,7 @@ fil_report_invalid_page_access(
|
|||||||
@param[in] message message for aio handler if non-sync aio
|
@param[in] message message for aio handler if non-sync aio
|
||||||
used, else ignored
|
used, else ignored
|
||||||
@param[in] ignore_missing_space true=ignore missing space duging read
|
@param[in] ignore_missing_space true=ignore missing space duging read
|
||||||
@return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
|
@return DB_SUCCESS, or DB_TABLESPACE_DELETED
|
||||||
if we are trying to do i/o on a tablespace which does not exist */
|
if we are trying to do i/o on a tablespace which does not exist */
|
||||||
dberr_t
|
dberr_t
|
||||||
fil_io(
|
fil_io(
|
||||||
@@ -4373,19 +4371,6 @@ fil_io(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (space->id != TRX_SYS_SPACE
|
|
||||||
&& UT_LIST_GET_LEN(space->chain) == 1
|
|
||||||
&& (srv_is_tablespace_truncated(space->id)
|
|
||||||
|| srv_was_tablespace_truncated(space))
|
|
||||||
&& req_type.is_read()) {
|
|
||||||
|
|
||||||
/* Handle page which is outside the truncated
|
|
||||||
tablespace bounds when recovering from a crash
|
|
||||||
happened during a truncation */
|
|
||||||
mutex_exit(&fil_system.mutex);
|
|
||||||
return(DB_TABLESPACE_TRUNCATED);
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_page_no -= node->size;
|
cur_page_no -= node->size;
|
||||||
|
|
||||||
node = UT_LIST_GET_NEXT(chain, node);
|
node = UT_LIST_GET_NEXT(chain, node);
|
||||||
@@ -5126,116 +5111,6 @@ fil_names_clear(
|
|||||||
return(do_write);
|
return(do_write);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Truncate a single-table tablespace. The tablespace must be cached
|
|
||||||
in the memory cache.
|
|
||||||
@param space_id space id
|
|
||||||
@param dir_path directory path
|
|
||||||
@param tablename the table name in the usual
|
|
||||||
databasename/tablename format of InnoDB
|
|
||||||
@param flags tablespace flags
|
|
||||||
@param trunc_to_default truncate to default size if tablespace
|
|
||||||
is being newly re-initialized.
|
|
||||||
@return DB_SUCCESS or error */
|
|
||||||
dberr_t
|
|
||||||
truncate_t::truncate(
|
|
||||||
/*=================*/
|
|
||||||
ulint space_id,
|
|
||||||
const char* dir_path,
|
|
||||||
const char* tablename,
|
|
||||||
ulint flags,
|
|
||||||
bool trunc_to_default)
|
|
||||||
{
|
|
||||||
dberr_t err = DB_SUCCESS;
|
|
||||||
char* path;
|
|
||||||
|
|
||||||
ut_a(!is_system_tablespace(space_id));
|
|
||||||
|
|
||||||
if (FSP_FLAGS_HAS_DATA_DIR(flags)) {
|
|
||||||
ut_ad(dir_path != NULL);
|
|
||||||
path = fil_make_filepath(dir_path, tablename, IBD, true);
|
|
||||||
} else {
|
|
||||||
path = fil_make_filepath(NULL, tablename, IBD, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (path == NULL) {
|
|
||||||
return(DB_OUT_OF_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_enter(&fil_system.mutex);
|
|
||||||
|
|
||||||
fil_space_t* space = fil_space_get_by_id(space_id);
|
|
||||||
|
|
||||||
/* The following code must change when InnoDB supports
|
|
||||||
multiple datafiles per tablespace. */
|
|
||||||
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
|
|
||||||
|
|
||||||
fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
|
|
||||||
|
|
||||||
if (trunc_to_default) {
|
|
||||||
space->size = node->size = FIL_IBD_FILE_INITIAL_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool already_open = node->is_open();
|
|
||||||
|
|
||||||
if (!already_open) {
|
|
||||||
|
|
||||||
bool ret;
|
|
||||||
|
|
||||||
node->handle = os_file_create_simple_no_error_handling(
|
|
||||||
innodb_data_file_key, path, OS_FILE_OPEN,
|
|
||||||
OS_FILE_READ_WRITE,
|
|
||||||
space->purpose != FIL_TYPE_TEMPORARY
|
|
||||||
&& srv_read_only_mode, &ret);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
ib::error() << "Failed to open tablespace file "
|
|
||||||
<< path << ".";
|
|
||||||
|
|
||||||
ut_free(path);
|
|
||||||
|
|
||||||
return(DB_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_a(node->is_open());
|
|
||||||
}
|
|
||||||
|
|
||||||
os_offset_t trunc_size = trunc_to_default
|
|
||||||
? FIL_IBD_FILE_INITIAL_SIZE
|
|
||||||
: space->size;
|
|
||||||
|
|
||||||
const bool success = os_file_truncate(
|
|
||||||
path, node->handle, trunc_size << srv_page_size_shift);
|
|
||||||
|
|
||||||
if (!success) {
|
|
||||||
ib::error() << "Cannot truncate file " << path
|
|
||||||
<< " in TRUNCATE TABLESPACE.";
|
|
||||||
err = DB_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
space->stop_new_ops = false;
|
|
||||||
|
|
||||||
/* If we opened the file in this function, close it. */
|
|
||||||
if (!already_open) {
|
|
||||||
bool closed = os_file_close(node->handle);
|
|
||||||
|
|
||||||
if (!closed) {
|
|
||||||
|
|
||||||
ib::error() << "Failed to close tablespace file "
|
|
||||||
<< path << ".";
|
|
||||||
|
|
||||||
err = DB_ERROR;
|
|
||||||
} else {
|
|
||||||
node->handle = OS_FILE_CLOSED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_exit(&fil_system.mutex);
|
|
||||||
|
|
||||||
ut_free(path);
|
|
||||||
|
|
||||||
return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unit Tests */
|
/* Unit Tests */
|
||||||
#ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
|
#ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
|
||||||
#define MF fil_make_filepath
|
#define MF fil_make_filepath
|
||||||
|
@@ -624,8 +624,7 @@ fsp_space_modify_check(
|
|||||||
case MTR_LOG_NO_REDO:
|
case MTR_LOG_NO_REDO:
|
||||||
ut_ad(space->purpose == FIL_TYPE_TEMPORARY
|
ut_ad(space->purpose == FIL_TYPE_TEMPORARY
|
||||||
|| space->purpose == FIL_TYPE_IMPORT
|
|| space->purpose == FIL_TYPE_IMPORT
|
||||||
|| my_atomic_loadlint(&space->redo_skipped_count)
|
|| my_atomic_loadlint(&space->redo_skipped_count));
|
||||||
|| srv_is_tablespace_truncated(space->id));
|
|
||||||
return;
|
return;
|
||||||
case MTR_LOG_ALL:
|
case MTR_LOG_ALL:
|
||||||
/* We may only write redo log for a persistent tablespace. */
|
/* We may only write redo log for a persistent tablespace. */
|
||||||
@@ -1065,13 +1064,6 @@ fsp_fill_free_list(
|
|||||||
mtr_start(&ibuf_mtr);
|
mtr_start(&ibuf_mtr);
|
||||||
ibuf_mtr.set_named_space(space);
|
ibuf_mtr.set_named_space(space);
|
||||||
|
|
||||||
/* Avoid logging while truncate table
|
|
||||||
fix-up is active. */
|
|
||||||
if (srv_is_tablespace_truncated(space->id)) {
|
|
||||||
mtr_set_log_mode(
|
|
||||||
&ibuf_mtr, MTR_LOG_NO_REDO);
|
|
||||||
}
|
|
||||||
|
|
||||||
const page_id_t page_id(
|
const page_id_t page_id(
|
||||||
space->id,
|
space->id,
|
||||||
i + FSP_IBUF_BITMAP_OFFSET);
|
i + FSP_IBUF_BITMAP_OFFSET);
|
||||||
|
@@ -914,7 +914,7 @@ rtr_split_page_move_rec_list(
|
|||||||
mtr_set_log_mode(mtr, log_mode);
|
mtr_set_log_mode(mtr, log_mode);
|
||||||
|
|
||||||
if (!page_zip_compress(new_page_zip, new_page, index,
|
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||||
page_zip_level, NULL, mtr)) {
|
page_zip_level, mtr)) {
|
||||||
ulint ret_pos;
|
ulint ret_pos;
|
||||||
|
|
||||||
/* Before trying to reorganize the page,
|
/* Before trying to reorganize the page,
|
||||||
|
@@ -100,7 +100,6 @@ this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "row0quiesce.h"
|
#include "row0quiesce.h"
|
||||||
#include "row0sel.h"
|
#include "row0sel.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "fil0crypt.h"
|
#include "fil0crypt.h"
|
||||||
#include "ut0timer.h"
|
#include "ut0timer.h"
|
||||||
|
@@ -916,10 +916,7 @@ ibuf_set_free_bits_func(
|
|||||||
ut_ad(0);
|
ut_ad(0);
|
||||||
break;
|
break;
|
||||||
case FIL_TYPE_TABLESPACE:
|
case FIL_TYPE_TABLESPACE:
|
||||||
/* Avoid logging while fixing up truncate of table. */
|
|
||||||
if (!srv_is_tablespace_truncated(block->page.id.space())) {
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case FIL_TYPE_TEMPORARY:
|
case FIL_TYPE_TEMPORARY:
|
||||||
case FIL_TYPE_IMPORT:
|
case FIL_TYPE_IMPORT:
|
||||||
|
@@ -361,19 +361,16 @@ btr_node_ptr_get_child_page_no(
|
|||||||
@param[in] type type of the index
|
@param[in] type type of the index
|
||||||
@param[in,out] space tablespace where created
|
@param[in,out] space tablespace where created
|
||||||
@param[in] index_id index id
|
@param[in] index_id index id
|
||||||
@param[in] index index, or NULL when applying TRUNCATE
|
@param[in] index index
|
||||||
log record during recovery
|
@param[in,out] mtr mini-transaction
|
||||||
@param[in] btr_redo_create_info used for applying TRUNCATE log
|
@return page number of the created root
|
||||||
@param[in] mtr mini-transaction handle
|
@retval FIL_NULL if did not succeed */
|
||||||
record during recovery
|
|
||||||
@return page number of the created root, FIL_NULL if did not succeed */
|
|
||||||
ulint
|
ulint
|
||||||
btr_create(
|
btr_create(
|
||||||
ulint type,
|
ulint type,
|
||||||
fil_space_t* space,
|
fil_space_t* space,
|
||||||
index_id_t index_id,
|
index_id_t index_id,
|
||||||
dict_index_t* index,
|
dict_index_t* index,
|
||||||
const btr_create_t* btr_redo_create_info,
|
|
||||||
mtr_t* mtr);
|
mtr_t* mtr);
|
||||||
|
|
||||||
/** Free a persistent index tree if it exists.
|
/** Free a persistent index tree if it exists.
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
|
Copyright (c) 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -58,35 +59,4 @@ in the index record. */
|
|||||||
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
|
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
|
||||||
(BTR_EXTERN_FIELD_REF_SIZE * 2)
|
(BTR_EXTERN_FIELD_REF_SIZE * 2)
|
||||||
|
|
||||||
/** The information is used for creating a new index tree when
|
|
||||||
applying TRUNCATE log record during recovery */
|
|
||||||
struct btr_create_t {
|
|
||||||
|
|
||||||
explicit btr_create_t(const byte* const ptr)
|
|
||||||
:
|
|
||||||
format_flags(),
|
|
||||||
n_fields(),
|
|
||||||
field_len(),
|
|
||||||
fields(ptr),
|
|
||||||
trx_id_pos(ULINT_UNDEFINED)
|
|
||||||
{
|
|
||||||
/* Do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Page format */
|
|
||||||
ulint format_flags;
|
|
||||||
|
|
||||||
/** Numbr of index fields */
|
|
||||||
ulint n_fields;
|
|
||||||
|
|
||||||
/** The length of the encoded meta-data */
|
|
||||||
ulint field_len;
|
|
||||||
|
|
||||||
/** Field meta-data, encoded. */
|
|
||||||
const byte* const fields;
|
|
||||||
|
|
||||||
/** Position of trx-id column. */
|
|
||||||
ulint trx_id_pos;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -135,8 +135,6 @@ enum dberr_t {
|
|||||||
DB_FTS_TOO_MANY_WORDS_IN_PHRASE,
|
DB_FTS_TOO_MANY_WORDS_IN_PHRASE,
|
||||||
/*< Too many words in a phrase */
|
/*< Too many words in a phrase */
|
||||||
|
|
||||||
DB_TABLESPACE_TRUNCATED, /*!< tablespace was truncated */
|
|
||||||
|
|
||||||
DB_DECRYPTION_FAILED, /* Tablespace encrypted and
|
DB_DECRYPTION_FAILED, /* Tablespace encrypted and
|
||||||
decrypt operation failed because
|
decrypt operation failed because
|
||||||
of missing key management plugin,
|
of missing key management plugin,
|
||||||
|
@@ -40,7 +40,6 @@ extern my_bool srv_use_doublewrite_buf;
|
|||||||
extern struct buf_dblwr_t* buf_dblwr;
|
extern struct buf_dblwr_t* buf_dblwr;
|
||||||
struct trx_t;
|
struct trx_t;
|
||||||
class page_id_t;
|
class page_id_t;
|
||||||
class truncate_t;
|
|
||||||
|
|
||||||
/** Structure containing encryption specification */
|
/** Structure containing encryption specification */
|
||||||
struct fil_space_crypt_t;
|
struct fil_space_crypt_t;
|
||||||
@@ -1086,7 +1085,7 @@ fil_space_extend(
|
|||||||
@param[in] message message for aio handler if non-sync aio
|
@param[in] message message for aio handler if non-sync aio
|
||||||
used, else ignored
|
used, else ignored
|
||||||
@param[in] ignore_missing_space true=ignore missing space during read
|
@param[in] ignore_missing_space true=ignore missing space during read
|
||||||
@return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
|
@return DB_SUCCESS, or DB_TABLESPACE_DELETED
|
||||||
if we are trying to do i/o on a tablespace which does not exist */
|
if we are trying to do i/o on a tablespace which does not exist */
|
||||||
dberr_t
|
dberr_t
|
||||||
fil_io(
|
fil_io(
|
||||||
|
@@ -145,10 +145,6 @@ corresponding to MLOG_INDEX_LOAD.
|
|||||||
*/
|
*/
|
||||||
extern void (*log_optimized_ddl_op)(ulint space_id);
|
extern void (*log_optimized_ddl_op)(ulint space_id);
|
||||||
|
|
||||||
/** Report backup-unfriendly TRUNCATE operation (with separate log file),
|
|
||||||
corresponding to MLOG_TRUNCATE. */
|
|
||||||
extern void (*log_truncate)();
|
|
||||||
|
|
||||||
/** Report an operation to create, delete, or rename a file during backup.
|
/** Report an operation to create, delete, or rename a file during backup.
|
||||||
@param[in] space_id tablespace identifier
|
@param[in] space_id tablespace identifier
|
||||||
@param[in] flags tablespace flags (NULL if not create)
|
@param[in] flags tablespace flags (NULL if not create)
|
||||||
|
@@ -216,7 +216,8 @@ enum mlog_id_t {
|
|||||||
/** initialize a file page */
|
/** initialize a file page */
|
||||||
MLOG_INIT_FILE_PAGE2 = 59,
|
MLOG_INIT_FILE_PAGE2 = 59,
|
||||||
|
|
||||||
/** Table is being truncated. (Marked only for file-per-table) */
|
/** Table is being truncated. (Was used in 10.2 and 10.3;
|
||||||
|
not supported for crash-upgrade to 10.4 or later.) */
|
||||||
MLOG_TRUNCATE = 60,
|
MLOG_TRUNCATE = 60,
|
||||||
|
|
||||||
/** notify that an index tree is being loaded without writing
|
/** notify that an index tree is being loaded without writing
|
||||||
|
@@ -1061,10 +1061,6 @@ page_create_zip(
|
|||||||
ulint level, /*!< in: the B-tree level of
|
ulint level, /*!< in: the B-tree level of
|
||||||
the page */
|
the page */
|
||||||
trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */
|
trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */
|
||||||
const redo_page_compress_t* page_comp_info,
|
|
||||||
/*!< in: used for applying
|
|
||||||
TRUNCATE log
|
|
||||||
record during recovery */
|
|
||||||
mtr_t* mtr); /*!< in/out: mini-transaction
|
mtr_t* mtr); /*!< in/out: mini-transaction
|
||||||
handle */
|
handle */
|
||||||
/**********************************************************//**
|
/**********************************************************//**
|
||||||
|
@@ -85,18 +85,6 @@ enum page_cur_mode_t {
|
|||||||
PAGE_CUR_RTREE_GET_FATHER = 14
|
PAGE_CUR_RTREE_GET_FATHER = 14
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** The information used for compressing a page when applying
|
|
||||||
TRUNCATE log record during recovery */
|
|
||||||
struct redo_page_compress_t {
|
|
||||||
ulint type; /*!< index type */
|
|
||||||
index_id_t index_id; /*!< index id */
|
|
||||||
ulint n_fields; /*!< number of index fields */
|
|
||||||
ulint field_len; /*!< the length of index field */
|
|
||||||
const byte* fields; /*!< index field information */
|
|
||||||
ulint trx_id_pos; /*!< position of trx-id column. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Compressed page descriptor */
|
/** Compressed page descriptor */
|
||||||
struct page_zip_des_t
|
struct page_zip_des_t
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2012, Facebook Inc.
|
Copyright (c) 2012, Facebook Inc.
|
||||||
Copyright (c) 2017, MariaDB Corporation.
|
Copyright (c) 2017, 2018, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@@ -164,10 +164,6 @@ page_zip_compress(
|
|||||||
dict_index_t* index, /*!< in: index of the B-tree
|
dict_index_t* index, /*!< in: index of the B-tree
|
||||||
node */
|
node */
|
||||||
ulint level, /*!< in: commpression level */
|
ulint level, /*!< in: commpression level */
|
||||||
const redo_page_compress_t* page_comp_info,
|
|
||||||
/*!< in: used for applying
|
|
||||||
TRUNCATE log
|
|
||||||
record during recovery */
|
|
||||||
mtr_t* mtr); /*!< in/out: mini-transaction,
|
mtr_t* mtr); /*!< in/out: mini-transaction,
|
||||||
or NULL */
|
or NULL */
|
||||||
|
|
||||||
|
@@ -414,7 +414,7 @@ page_zip_parse_compress_no_data(
|
|||||||
was successful. Crash in this case. */
|
was successful. Crash in this case. */
|
||||||
|
|
||||||
if (page
|
if (page
|
||||||
&& !page_zip_compress(page_zip, page, index, level, NULL, NULL)) {
|
&& !page_zip_compress(page_zip, page, index, level, NULL)) {
|
||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,417 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
|
|
||||||
Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
|
|
||||||
Copyright (c) 2018, MariaDB Corporation.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; version 2 of the License.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
|
||||||
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**************************************************//**
|
|
||||||
@file include/row0trunc.h
|
|
||||||
TRUNCATE implementation
|
|
||||||
|
|
||||||
Created 2013-04-25 Krunal Bauskar
|
|
||||||
*******************************************************/
|
|
||||||
|
|
||||||
#ifndef row0trunc_h
|
|
||||||
#define row0trunc_h
|
|
||||||
|
|
||||||
#include "row0mysql.h"
|
|
||||||
#include "dict0boot.h"
|
|
||||||
#include "fil0fil.h"
|
|
||||||
#include "srv0start.h"
|
|
||||||
#include "ut0new.h"
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
/** The information of TRUNCATE log record.
|
|
||||||
This class handles the recovery stage of TRUNCATE table. */
|
|
||||||
class truncate_t {
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
Constructor
|
|
||||||
|
|
||||||
@param old_table_id old table id assigned to table before truncate
|
|
||||||
@param new_table_id new table id that will be assigned to table
|
|
||||||
after truncate
|
|
||||||
@param dir_path directory path */
|
|
||||||
truncate_t(
|
|
||||||
table_id_t old_table_id,
|
|
||||||
table_id_t new_table_id,
|
|
||||||
const char* dir_path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Constructor
|
|
||||||
|
|
||||||
@param log_file_name parse the log file during recovery to populate
|
|
||||||
information related to table to truncate */
|
|
||||||
truncate_t(const char* log_file_name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Consturctor
|
|
||||||
|
|
||||||
@param space_id space in which table reisde
|
|
||||||
@param name table name
|
|
||||||
@param tablespace_flags tablespace flags use for recreating tablespace
|
|
||||||
@param log_flags page format flag
|
|
||||||
@param recv_lsn lsn of redo log record. */
|
|
||||||
truncate_t(
|
|
||||||
ulint space_id,
|
|
||||||
const char* name,
|
|
||||||
ulint tablespace_flags,
|
|
||||||
ulint log_flags,
|
|
||||||
lsn_t recv_lsn);
|
|
||||||
|
|
||||||
/** Destructor */
|
|
||||||
~truncate_t();
|
|
||||||
|
|
||||||
/** The index information of MLOG_FILE_TRUNCATE redo record */
|
|
||||||
struct index_t {
|
|
||||||
|
|
||||||
/* Default copy constructor and destructor should be OK. */
|
|
||||||
|
|
||||||
index_t();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Set the truncate log values for a compressed table.
|
|
||||||
@return DB_CORRUPTION or error code */
|
|
||||||
dberr_t set(const dict_index_t* index);
|
|
||||||
|
|
||||||
typedef std::vector<byte, ut_allocator<byte> > fields_t;
|
|
||||||
|
|
||||||
/** Index id */
|
|
||||||
index_id_t m_id;
|
|
||||||
|
|
||||||
/** Index type */
|
|
||||||
ulint m_type;
|
|
||||||
|
|
||||||
/** Root Page Number */
|
|
||||||
ulint m_root_page_no;
|
|
||||||
|
|
||||||
/** New Root Page Number.
|
|
||||||
Note: This field is not persisted to TRUNCATE log but used
|
|
||||||
during truncate table fix-up for updating SYS_XXXX tables. */
|
|
||||||
ulint m_new_root_page_no;
|
|
||||||
|
|
||||||
/** Number of index fields */
|
|
||||||
ulint m_n_fields;
|
|
||||||
|
|
||||||
/** DATA_TRX_ID column position. */
|
|
||||||
ulint m_trx_id_pos;
|
|
||||||
|
|
||||||
/** Compressed table field meta data, encode by
|
|
||||||
page_zip_fields_encode. Empty for non-compressed tables.
|
|
||||||
Should be NUL terminated. */
|
|
||||||
fields_t m_fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return the directory path, can be NULL */
|
|
||||||
const char* get_dir_path() const
|
|
||||||
{
|
|
||||||
return(m_dir_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Register index information
|
|
||||||
|
|
||||||
@param index index information logged as part of truncate log. */
|
|
||||||
void add(index_t& index)
|
|
||||||
{
|
|
||||||
m_indexes.push_back(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Add table to truncate post recovery.
|
|
||||||
|
|
||||||
@param ptr table information need to complete truncate of table. */
|
|
||||||
static void add(truncate_t* ptr)
|
|
||||||
{
|
|
||||||
s_tables.push_back(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Clear registered index vector */
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
m_indexes.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return old table id of the table to truncate */
|
|
||||||
table_id_t old_table_id() const
|
|
||||||
{
|
|
||||||
return(m_old_table_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return new table id of the table to truncate */
|
|
||||||
table_id_t new_table_id() const
|
|
||||||
{
|
|
||||||
return(m_new_table_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Update root page number in SYS_XXXX tables.
|
|
||||||
|
|
||||||
@param trx transaction object
|
|
||||||
@param table_id table id for which information needs to
|
|
||||||
be updated.
|
|
||||||
@param reserve_dict_mutex if TRUE, acquire/release
|
|
||||||
dict_sys->mutex around call to pars_sql.
|
|
||||||
@param mark_index_corrupted if true, then mark index corrupted
|
|
||||||
@return DB_SUCCESS or error code */
|
|
||||||
dberr_t update_root_page_no(
|
|
||||||
trx_t* trx,
|
|
||||||
table_id_t table_id,
|
|
||||||
ibool reserve_dict_mutex,
|
|
||||||
bool mark_index_corrupted) const;
|
|
||||||
|
|
||||||
/** Create an index for a table.
|
|
||||||
@param[in] table_name table name, for which to create
|
|
||||||
the index
|
|
||||||
@param[in,out] space tablespace
|
|
||||||
@param[in] index_type type of index to truncate
|
|
||||||
@param[in] index_id id of index to truncate
|
|
||||||
@param[in] btr_redo_create_info control info for ::btr_create()
|
|
||||||
@param[in,out] mtr mini-transaction covering the
|
|
||||||
create index
|
|
||||||
@return root page no or FIL_NULL on failure */
|
|
||||||
inline ulint create_index(
|
|
||||||
const char* table_name,
|
|
||||||
fil_space_t* space,
|
|
||||||
ulint index_type,
|
|
||||||
index_id_t index_id,
|
|
||||||
const btr_create_t& btr_redo_create_info,
|
|
||||||
mtr_t* mtr) const;
|
|
||||||
|
|
||||||
/** Create the indexes for a table
|
|
||||||
@param[in] table_name table name, for which to create the
|
|
||||||
indexes
|
|
||||||
@param[in,out] space tablespace
|
|
||||||
@param[in] format_flags page format flags
|
|
||||||
@return DB_SUCCESS or error code. */
|
|
||||||
inline dberr_t create_indexes(
|
|
||||||
const char* table_name,
|
|
||||||
fil_space_t* space,
|
|
||||||
ulint format_flags);
|
|
||||||
|
|
||||||
/** Check if index has been modified since TRUNCATE log snapshot
|
|
||||||
was recorded.
|
|
||||||
@param[in] space tablespace
|
|
||||||
@param[in] root_page_no index root page number
|
|
||||||
@return true if modified else false */
|
|
||||||
inline bool is_index_modified_since_logged(
|
|
||||||
const fil_space_t* space,
|
|
||||||
ulint root_page_no) const;
|
|
||||||
|
|
||||||
/** Drop indexes for a table.
|
|
||||||
@param[in,out] space tablespace
|
|
||||||
@return DB_SUCCESS or error code. */
|
|
||||||
void drop_indexes(fil_space_t* space) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parses log record during recovery
|
|
||||||
@param start_ptr buffer containing log body to parse
|
|
||||||
@param end_ptr buffer end
|
|
||||||
|
|
||||||
@return DB_SUCCESS or error code */
|
|
||||||
dberr_t parse(
|
|
||||||
byte* start_ptr,
|
|
||||||
const byte* end_ptr);
|
|
||||||
|
|
||||||
/** Parse MLOG_TRUNCATE log record from REDO log file during recovery.
|
|
||||||
@param[in,out] start_ptr buffer containing log body to parse
|
|
||||||
@param[in] end_ptr buffer end
|
|
||||||
@param[in] space_id tablespace identifier
|
|
||||||
@return parsed upto or NULL. */
|
|
||||||
static byte* parse_redo_entry(
|
|
||||||
byte* start_ptr,
|
|
||||||
const byte* end_ptr,
|
|
||||||
ulint space_id);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Write a log record for truncating a single-table tablespace.
|
|
||||||
|
|
||||||
@param start_ptr buffer to write log record
|
|
||||||
@param end_ptr buffer end
|
|
||||||
@param space_id space id
|
|
||||||
@param tablename the table name in the usual
|
|
||||||
databasename/tablename format of InnoDB
|
|
||||||
@param flags tablespace flags
|
|
||||||
@param format_flags page format
|
|
||||||
@param lsn lsn while logging */
|
|
||||||
dberr_t write(
|
|
||||||
byte* start_ptr,
|
|
||||||
byte* end_ptr,
|
|
||||||
ulint space_id,
|
|
||||||
const char* tablename,
|
|
||||||
ulint flags,
|
|
||||||
ulint format_flags,
|
|
||||||
lsn_t lsn) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
@return number of indexes parsed from the truncate log record */
|
|
||||||
size_t indexes() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Truncate a single-table tablespace. The tablespace must be cached
|
|
||||||
in the memory cache.
|
|
||||||
|
|
||||||
Note: This is defined in fil0fil.cc because it needs to access some
|
|
||||||
types that are local to that file.
|
|
||||||
|
|
||||||
@param space_id space id
|
|
||||||
@param dir_path directory path
|
|
||||||
@param tablename the table name in the usual
|
|
||||||
databasename/tablename format of InnoDB
|
|
||||||
@param flags tablespace flags
|
|
||||||
@param default_size if true, truncate to default size if tablespace
|
|
||||||
is being newly re-initialized.
|
|
||||||
@return DB_SUCCESS or error */
|
|
||||||
static dberr_t truncate(
|
|
||||||
ulint space_id,
|
|
||||||
const char* dir_path,
|
|
||||||
const char* tablename,
|
|
||||||
ulint flags,
|
|
||||||
bool default_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Fix the table truncate by applying information parsed from TRUNCATE log.
|
|
||||||
Fix-up includes re-creating table (drop and re-create indexes)
|
|
||||||
@return error code or DB_SUCCESS */
|
|
||||||
static dberr_t fixup_tables_in_system_tablespace();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Fix the table truncate by applying information parsed from TRUNCATE log.
|
|
||||||
Fix-up includes re-creating tablespace.
|
|
||||||
@return error code or DB_SUCCESS */
|
|
||||||
static dberr_t fixup_tables_in_non_system_tablespace();
|
|
||||||
|
|
||||||
/**
|
|
||||||
Check whether a tablespace was truncated during recovery
|
|
||||||
@param space_id tablespace id to check
|
|
||||||
@return true if the tablespace was truncated */
|
|
||||||
static bool is_tablespace_truncated(ulint space_id);
|
|
||||||
|
|
||||||
/** Was tablespace truncated (on crash before checkpoint).
|
|
||||||
If the MLOG_TRUNCATE redo-record is still available then tablespace
|
|
||||||
was truncated and checkpoint is yet to happen.
|
|
||||||
@param[in] space_id tablespace id to check.
|
|
||||||
@return true if tablespace was truncated. */
|
|
||||||
static bool was_tablespace_truncated(ulint space_id);
|
|
||||||
|
|
||||||
/** Get the lsn associated with space.
|
|
||||||
@param[in] space_id tablespace id to check.
|
|
||||||
@return associated lsn. */
|
|
||||||
static lsn_t get_truncated_tablespace_init_lsn(ulint space_id);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::vector<index_t, ut_allocator<index_t> > indexes_t;
|
|
||||||
|
|
||||||
/** Space ID of tablespace */
|
|
||||||
ulint m_space_id;
|
|
||||||
|
|
||||||
/** ID of table that is being truncated. */
|
|
||||||
table_id_t m_old_table_id;
|
|
||||||
|
|
||||||
/** New ID that will be assigned to table on truncation. */
|
|
||||||
table_id_t m_new_table_id;
|
|
||||||
|
|
||||||
/** Data dir path of tablespace */
|
|
||||||
char* m_dir_path;
|
|
||||||
|
|
||||||
/** Table name */
|
|
||||||
char* m_tablename;
|
|
||||||
|
|
||||||
/** Tablespace Flags */
|
|
||||||
ulint m_tablespace_flags;
|
|
||||||
|
|
||||||
/** Format flags (log flags; stored in page-no field of header) */
|
|
||||||
ulint m_format_flags;
|
|
||||||
|
|
||||||
/** Index meta-data */
|
|
||||||
indexes_t m_indexes;
|
|
||||||
|
|
||||||
/** LSN of TRUNCATE log record. */
|
|
||||||
lsn_t m_log_lsn;
|
|
||||||
|
|
||||||
/** Log file name. */
|
|
||||||
char* m_log_file_name;
|
|
||||||
|
|
||||||
/** Encryption information of the table */
|
|
||||||
fil_encryption_t m_encryption;
|
|
||||||
uint32_t m_key_id;
|
|
||||||
|
|
||||||
/** Vector of tables to truncate. */
|
|
||||||
typedef std::vector<truncate_t*, ut_allocator<truncate_t*> >
|
|
||||||
tables_t;
|
|
||||||
|
|
||||||
/** Information about tables to truncate post recovery */
|
|
||||||
static tables_t s_tables;
|
|
||||||
|
|
||||||
/** Information about truncated table
|
|
||||||
This is case when truncate is complete but checkpoint hasn't. */
|
|
||||||
typedef std::map<ulint, lsn_t> truncated_tables_t;
|
|
||||||
static truncated_tables_t s_truncated_tables;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** If true then fix-up of table is active and so while creating
|
|
||||||
index instead of grabbing information from dict_index_t, grab it
|
|
||||||
from parsed truncate log record. */
|
|
||||||
static bool s_fix_up_active;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse truncate log file. */
|
|
||||||
class TruncateLogParser {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
Scan and Parse truncate log files.
|
|
||||||
|
|
||||||
@param dir_path look for log directory in following path
|
|
||||||
@return DB_SUCCESS or error code. */
|
|
||||||
static dberr_t scan_and_parse(
|
|
||||||
const char* dir_path);
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef std::vector<char*, ut_allocator<char*> >
|
|
||||||
trunc_log_files_t;
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
Scan to find out truncate log file from the given directory path.
|
|
||||||
|
|
||||||
@param dir_path look for log directory in following path.
|
|
||||||
@param log_files cache to hold truncate log file name found.
|
|
||||||
@return DB_SUCCESS or error code. */
|
|
||||||
static dberr_t scan(
|
|
||||||
const char* dir_path,
|
|
||||||
trunc_log_files_t& log_files);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Parse the log file and populate table to truncate information.
|
|
||||||
(Add this table to truncate information to central vector that is then
|
|
||||||
used by truncate fix-up routine to fix-up truncate action of the table.)
|
|
||||||
|
|
||||||
@param log_file_name log file to parse
|
|
||||||
@return DB_SUCCESS or error code. */
|
|
||||||
static dberr_t parse(
|
|
||||||
const char* log_file_name);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* row0trunc_h */
|
|
@@ -900,23 +900,6 @@ srv_purge_wakeup();
|
|||||||
/** Shut down the purge threads. */
|
/** Shut down the purge threads. */
|
||||||
void srv_purge_shutdown();
|
void srv_purge_shutdown();
|
||||||
|
|
||||||
/** Check if tablespace is being truncated.
|
|
||||||
(Ignore system-tablespace as we don't re-create the tablespace
|
|
||||||
and so some of the action that are suppressed by this function
|
|
||||||
for independent tablespace are not applicable to system-tablespace).
|
|
||||||
@param space_id space_id to check for truncate action
|
|
||||||
@return true if being truncated, false if not being
|
|
||||||
truncated or tablespace is system-tablespace. */
|
|
||||||
bool
|
|
||||||
srv_is_tablespace_truncated(ulint space_id);
|
|
||||||
|
|
||||||
/** Check if tablespace was truncated.
|
|
||||||
@param[in] space space object to check for truncate action
|
|
||||||
@return true if tablespace was truncated and we still have an active
|
|
||||||
MLOG_TRUNCATE REDO log record. */
|
|
||||||
bool
|
|
||||||
srv_was_tablespace_truncated(const fil_space_t* space);
|
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
/** Disables master thread. It's used by:
|
/** Disables master thread. It's used by:
|
||||||
SET GLOBAL innodb_master_thread_disabled_debug = 1 (0).
|
SET GLOBAL innodb_master_thread_disabled_debug = 1 (0).
|
||||||
|
@@ -133,202 +133,6 @@ private:
|
|||||||
TrxUndoRsegs::const_iterator m_iter;
|
TrxUndoRsegs::const_iterator m_iter;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Namespace to hold all the related functions and variables need for truncate
|
|
||||||
of undo tablespace. */
|
|
||||||
namespace undo {
|
|
||||||
|
|
||||||
typedef std::vector<ulint> undo_spaces_t;
|
|
||||||
typedef std::vector<trx_rseg_t*> rseg_for_trunc_t;
|
|
||||||
|
|
||||||
/** Mark completion of undo truncate action by writing magic number to
|
|
||||||
the log file and then removing it from the disk.
|
|
||||||
If we are going to remove it from disk then why write magic number ?
|
|
||||||
This is to safeguard from unlink (file-system) anomalies that will keep
|
|
||||||
the link to the file even after unlink action is successfull and
|
|
||||||
ref-count = 0.
|
|
||||||
@param[in] space_id id of the undo tablespace to truncate.*/
|
|
||||||
void done(ulint space_id);
|
|
||||||
|
|
||||||
/** Check if TRUNCATE_DDL_LOG file exist.
|
|
||||||
@param[in] space_id id of the undo tablespace.
|
|
||||||
@return true if exist else false. */
|
|
||||||
bool is_log_present(ulint space_id);
|
|
||||||
|
|
||||||
/** Track UNDO tablespace mark for truncate. */
|
|
||||||
class Truncate {
|
|
||||||
public:
|
|
||||||
void create()
|
|
||||||
{
|
|
||||||
m_undo_for_trunc = ULINT_UNDEFINED;
|
|
||||||
m_scan_start = 1;
|
|
||||||
m_purge_rseg_truncate_frequency =
|
|
||||||
ulint(srv_purge_rseg_truncate_frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clear the cached rollback segment. Normally done
|
|
||||||
when purge is about to shutdown. */
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
rseg_for_trunc_t temp;
|
|
||||||
m_rseg_for_trunc.swap(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Is tablespace selected for truncate.
|
|
||||||
@return true if undo tablespace is marked for truncate */
|
|
||||||
bool is_marked() const
|
|
||||||
{
|
|
||||||
return(!(m_undo_for_trunc == ULINT_UNDEFINED));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mark the tablespace for truncate.
|
|
||||||
@param[in] undo_id tablespace for truncate. */
|
|
||||||
void mark(ulint undo_id)
|
|
||||||
{
|
|
||||||
m_undo_for_trunc = undo_id;
|
|
||||||
|
|
||||||
m_scan_start = (undo_id + 1)
|
|
||||||
% (srv_undo_tablespaces_active + 1);
|
|
||||||
if (m_scan_start == 0) {
|
|
||||||
/* Note: UNDO tablespace ids starts from 1. */
|
|
||||||
m_scan_start = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We found an UNDO-tablespace to truncate so set the
|
|
||||||
local purge rseg truncate frequency to 1. This will help
|
|
||||||
accelerate the purge action and in turn truncate. */
|
|
||||||
m_purge_rseg_truncate_frequency = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the tablespace marked for truncate.
|
|
||||||
@return tablespace id marked for truncate. */
|
|
||||||
ulint get_marked_space_id() const
|
|
||||||
{
|
|
||||||
return(m_undo_for_trunc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add rseg to truncate vector.
|
|
||||||
@param[in,out] rseg rseg for truncate */
|
|
||||||
void add_rseg_to_trunc(trx_rseg_t* rseg)
|
|
||||||
{
|
|
||||||
m_rseg_for_trunc.push_back(rseg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get number of rsegs registered for truncate.
|
|
||||||
@return return number of rseg that belongs to tablespace mark
|
|
||||||
for truncate. */
|
|
||||||
ulint rsegs_size() const
|
|
||||||
{
|
|
||||||
return(m_rseg_for_trunc.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get ith registered rseg.
|
|
||||||
@param[in] id index of rseg to get.
|
|
||||||
@return reference to registered rseg. */
|
|
||||||
trx_rseg_t* get_ith_rseg(ulint id)
|
|
||||||
{
|
|
||||||
ut_ad(id < m_rseg_for_trunc.size());
|
|
||||||
return(m_rseg_for_trunc.at(id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Reset for next rseg truncate. */
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
m_undo_for_trunc = ULINT_UNDEFINED;
|
|
||||||
m_rseg_for_trunc.clear();
|
|
||||||
|
|
||||||
/* Sync with global value as we are done with
|
|
||||||
truncate now. */
|
|
||||||
m_purge_rseg_truncate_frequency = static_cast<ulint>(
|
|
||||||
srv_purge_rseg_truncate_frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get the tablespace id to start scanning from.
|
|
||||||
@return id of UNDO tablespace to start scanning from. */
|
|
||||||
ulint get_scan_start() const
|
|
||||||
{
|
|
||||||
return(m_scan_start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if the tablespace needs fix-up (based on presence of
|
|
||||||
DDL truncate log)
|
|
||||||
@param space_id space id of the undo tablespace to check
|
|
||||||
@return true if fix up is needed else false */
|
|
||||||
bool needs_fix_up(ulint space_id) const
|
|
||||||
{
|
|
||||||
return(is_log_present(space_id));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add undo tablespace to truncate vector.
|
|
||||||
@param[in] space_id space id of tablespace to
|
|
||||||
truncate */
|
|
||||||
static void add_space_to_trunc_list(ulint space_id)
|
|
||||||
{
|
|
||||||
s_spaces_to_truncate.push_back(space_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Clear the truncate vector. */
|
|
||||||
static void clear_trunc_list()
|
|
||||||
{
|
|
||||||
s_spaces_to_truncate.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Is tablespace marked for truncate.
|
|
||||||
@param[in] space_id space id to check
|
|
||||||
@return true if marked for truncate, else false. */
|
|
||||||
static bool is_tablespace_truncated(ulint space_id)
|
|
||||||
{
|
|
||||||
return(std::find(s_spaces_to_truncate.begin(),
|
|
||||||
s_spaces_to_truncate.end(), space_id)
|
|
||||||
!= s_spaces_to_truncate.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Was a tablespace truncated at startup
|
|
||||||
@param[in] space_id space id to check
|
|
||||||
@return whether space_id was truncated at startup */
|
|
||||||
static bool was_tablespace_truncated(ulint space_id)
|
|
||||||
{
|
|
||||||
return(std::find(s_fix_up_spaces.begin(),
|
|
||||||
s_fix_up_spaces.end(),
|
|
||||||
space_id)
|
|
||||||
!= s_fix_up_spaces.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Get local rseg purge truncate frequency
|
|
||||||
@return rseg purge truncate frequency. */
|
|
||||||
ulint get_rseg_truncate_frequency() const
|
|
||||||
{
|
|
||||||
return(m_purge_rseg_truncate_frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/** UNDO tablespace is mark for truncate. */
|
|
||||||
ulint m_undo_for_trunc;
|
|
||||||
|
|
||||||
/** rseg that resides in UNDO tablespace is marked for
|
|
||||||
truncate. */
|
|
||||||
rseg_for_trunc_t m_rseg_for_trunc;
|
|
||||||
|
|
||||||
/** Start scanning for UNDO tablespace from this space_id.
|
|
||||||
This is to avoid bias selection of one tablespace always. */
|
|
||||||
ulint m_scan_start;
|
|
||||||
|
|
||||||
/** Rollback segment(s) purge frequency. This is local
|
|
||||||
value maintained along with global value. It is set to global
|
|
||||||
value on start but when tablespace is marked for truncate it
|
|
||||||
is updated to 1 and then minimum value among 2 is used by
|
|
||||||
purge action. */
|
|
||||||
ulint m_purge_rseg_truncate_frequency;
|
|
||||||
|
|
||||||
/** List of UNDO tablespace(s) to truncate. */
|
|
||||||
static undo_spaces_t s_spaces_to_truncate;
|
|
||||||
public:
|
|
||||||
/** Undo tablespaces that were truncated at startup */
|
|
||||||
static undo_spaces_t s_fix_up_spaces;
|
|
||||||
}; /* class Truncate */
|
|
||||||
|
|
||||||
}; /* namespace undo */
|
|
||||||
|
|
||||||
/** The control structure used in the purge operation */
|
/** The control structure used in the purge operation */
|
||||||
class purge_sys_t
|
class purge_sys_t
|
||||||
{
|
{
|
||||||
@@ -410,9 +214,14 @@ public:
|
|||||||
by the pq_mutex */
|
by the pq_mutex */
|
||||||
PQMutex pq_mutex; /*!< Mutex protecting purge_queue */
|
PQMutex pq_mutex; /*!< Mutex protecting purge_queue */
|
||||||
|
|
||||||
undo::Truncate undo_trunc; /*!< Track UNDO tablespace marked
|
/** Undo tablespace file truncation (only accessed by the
|
||||||
for truncate. */
|
srv_purge_coordinator_thread) */
|
||||||
|
struct {
|
||||||
|
/** The undo tablespace that is currently being truncated */
|
||||||
|
fil_space_t* current;
|
||||||
|
/** The undo tablespace that was last truncated */
|
||||||
|
fil_space_t* last;
|
||||||
|
} truncate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Constructor.
|
Constructor.
|
||||||
|
@@ -54,7 +54,6 @@ Created 9/20/1997 Heikki Tuuri
|
|||||||
#include "fil0fil.h"
|
#include "fil0fil.h"
|
||||||
#include "fsp0sysspace.h"
|
#include "fsp0sysspace.h"
|
||||||
#include "ut0new.h"
|
#include "ut0new.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "buf0rea.h"
|
#include "buf0rea.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "srv0start.h"
|
#include "srv0start.h"
|
||||||
@@ -203,10 +202,6 @@ corresponding to MLOG_INDEX_LOAD.
|
|||||||
*/
|
*/
|
||||||
void (*log_optimized_ddl_op)(ulint space_id);
|
void (*log_optimized_ddl_op)(ulint space_id);
|
||||||
|
|
||||||
/** Report backup-unfriendly TRUNCATE operation (with separate log file),
|
|
||||||
corresponding to MLOG_TRUNCATE. */
|
|
||||||
void (*log_truncate)();
|
|
||||||
|
|
||||||
/** Report an operation to create, delete, or rename a file during backup.
|
/** Report an operation to create, delete, or rename a file during backup.
|
||||||
@param[in] space_id tablespace identifier
|
@param[in] space_id tablespace identifier
|
||||||
@param[in] flags tablespace flags (NULL if not create)
|
@param[in] flags tablespace flags (NULL if not create)
|
||||||
@@ -1205,14 +1200,10 @@ recv_parse_or_apply_log_rec_body(
|
|||||||
}
|
}
|
||||||
return(ptr + 8);
|
return(ptr + 8);
|
||||||
case MLOG_TRUNCATE:
|
case MLOG_TRUNCATE:
|
||||||
if (log_truncate) {
|
ib::error() << "Cannot crash-upgrade from "
|
||||||
ut_ad(srv_operation != SRV_OPERATION_NORMAL);
|
"old-style TRUNCATE TABLE";
|
||||||
log_truncate();
|
recv_sys->found_corrupt_log = true;
|
||||||
recv_sys->found_corrupt_fs = true;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
return(truncate_t::parse_redo_entry(ptr, end_ptr, space_id));
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1795,13 +1786,10 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||||||
page_t* page;
|
page_t* page;
|
||||||
page_zip_des_t* page_zip;
|
page_zip_des_t* page_zip;
|
||||||
recv_addr_t* recv_addr;
|
recv_addr_t* recv_addr;
|
||||||
recv_t* recv;
|
|
||||||
byte* buf;
|
|
||||||
lsn_t start_lsn;
|
lsn_t start_lsn;
|
||||||
lsn_t end_lsn;
|
lsn_t end_lsn;
|
||||||
lsn_t page_lsn;
|
lsn_t page_lsn;
|
||||||
lsn_t page_newest_lsn;
|
lsn_t page_newest_lsn;
|
||||||
ibool modification_to_page;
|
|
||||||
mtr_t mtr;
|
mtr_t mtr;
|
||||||
|
|
||||||
mutex_enter(&(recv_sys->mutex));
|
mutex_enter(&(recv_sys->mutex));
|
||||||
@@ -1876,57 +1864,19 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||||||
page_lsn = page_newest_lsn;
|
page_lsn = page_newest_lsn;
|
||||||
}
|
}
|
||||||
|
|
||||||
modification_to_page = FALSE;
|
|
||||||
start_lsn = end_lsn = 0;
|
start_lsn = end_lsn = 0;
|
||||||
|
|
||||||
recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
|
|
||||||
fil_space_t* space = fil_space_acquire(block->page.id.space());
|
fil_space_t* space = fil_space_acquire(block->page.id.space());
|
||||||
|
|
||||||
while (recv) {
|
for (recv_t* recv = UT_LIST_GET_FIRST(recv_addr->rec_list);
|
||||||
|
recv; recv = UT_LIST_GET_NEXT(rec_list, recv)) {
|
||||||
end_lsn = recv->end_lsn;
|
end_lsn = recv->end_lsn;
|
||||||
|
|
||||||
ut_ad(end_lsn <= log_sys.log.scanned_lsn);
|
ut_ad(end_lsn <= log_sys.log.scanned_lsn);
|
||||||
|
|
||||||
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
ut_ad(recv->start_lsn);
|
||||||
/* We have to copy the record body to a separate
|
if (recv->start_lsn >= page_lsn) {
|
||||||
buffer */
|
if (!start_lsn) {
|
||||||
|
|
||||||
buf = static_cast<byte*>(ut_malloc_nokey(recv->len));
|
|
||||||
|
|
||||||
recv_data_copy_to_buf(buf, recv);
|
|
||||||
} else {
|
|
||||||
buf = ((byte*)(recv->data)) + sizeof(recv_data_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If per-table tablespace was truncated and there exist REDO
|
|
||||||
records before truncate that are to be applied as part of
|
|
||||||
recovery (checkpoint didn't happen since truncate was done)
|
|
||||||
skip such records using lsn check as they may not stand valid
|
|
||||||
post truncate.
|
|
||||||
LSN at start of truncate is recorded and any redo record
|
|
||||||
with LSN less than recorded LSN is skipped.
|
|
||||||
Note: We can't skip complete recv_addr as same page may have
|
|
||||||
valid REDO records post truncate those needs to be applied. */
|
|
||||||
|
|
||||||
/* Ignore applying the redo logs for tablespace that is
|
|
||||||
truncated. Post recovery there is fixup action that will
|
|
||||||
restore the tablespace back to normal state.
|
|
||||||
Applying redo at this stage can result in error given that
|
|
||||||
redo will have action recorded on page before tablespace
|
|
||||||
was re-inited and that would lead to an error while applying
|
|
||||||
such action. */
|
|
||||||
if (recv->start_lsn >= page_lsn
|
|
||||||
&& !srv_is_tablespace_truncated(space->id)
|
|
||||||
&& !(srv_was_tablespace_truncated(space)
|
|
||||||
&& recv->start_lsn
|
|
||||||
< truncate_t::get_truncated_tablespace_init_lsn(
|
|
||||||
space->id))) {
|
|
||||||
|
|
||||||
lsn_t end_lsn;
|
|
||||||
|
|
||||||
if (!modification_to_page) {
|
|
||||||
|
|
||||||
modification_to_page = TRUE;
|
|
||||||
start_lsn = recv->start_lsn;
|
start_lsn = recv->start_lsn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1942,29 +1892,41 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||||||
<< " len " << recv->len
|
<< " len " << recv->len
|
||||||
<< " page " << block->page.id);
|
<< " page " << block->page.id);
|
||||||
|
|
||||||
|
byte* buf;
|
||||||
|
|
||||||
|
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
||||||
|
/* We have to copy the record body to
|
||||||
|
a separate buffer */
|
||||||
|
|
||||||
|
buf = static_cast<byte*>(ut_malloc_nokey(
|
||||||
|
recv->len));
|
||||||
|
|
||||||
|
recv_data_copy_to_buf(buf, recv);
|
||||||
|
} else {
|
||||||
|
buf = reinterpret_cast<byte*>(recv->data)
|
||||||
|
+ sizeof *recv->data;
|
||||||
|
}
|
||||||
|
|
||||||
recv_parse_or_apply_log_rec_body(
|
recv_parse_or_apply_log_rec_body(
|
||||||
recv->type, buf, buf + recv->len,
|
recv->type, buf, buf + recv->len,
|
||||||
block->page.id.space(),
|
block->page.id.space(),
|
||||||
block->page.id.page_no(),
|
block->page.id.page_no(), true, block, &mtr);
|
||||||
true, block, &mtr);
|
|
||||||
|
|
||||||
end_lsn = recv->start_lsn + recv->len;
|
lsn_t end_lsn = recv->start_lsn + recv->len;
|
||||||
mach_write_to_8(FIL_PAGE_LSN + page, end_lsn);
|
mach_write_to_8(FIL_PAGE_LSN + page, end_lsn);
|
||||||
mach_write_to_8(srv_page_size
|
mach_write_to_8(srv_page_size
|
||||||
- FIL_PAGE_END_LSN_OLD_CHKSUM
|
- FIL_PAGE_END_LSN_OLD_CHKSUM
|
||||||
+ page, end_lsn);
|
+ page, end_lsn);
|
||||||
|
|
||||||
if (page_zip) {
|
if (page_zip) {
|
||||||
mach_write_to_8(FIL_PAGE_LSN
|
mach_write_to_8(FIL_PAGE_LSN + page_zip->data,
|
||||||
+ page_zip->data, end_lsn);
|
end_lsn);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
||||||
ut_free(buf);
|
ut_free(buf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
recv = UT_LIST_GET_NEXT(rec_list, recv);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
space->release();
|
space->release();
|
||||||
@@ -1978,9 +1940,7 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||||||
}
|
}
|
||||||
#endif /* UNIV_ZIP_DEBUG */
|
#endif /* UNIV_ZIP_DEBUG */
|
||||||
|
|
||||||
if (modification_to_page) {
|
if (start_lsn) {
|
||||||
ut_a(block);
|
|
||||||
|
|
||||||
log_flush_order_mutex_enter();
|
log_flush_order_mutex_enter();
|
||||||
buf_flush_recv_note_modification(block, start_lsn, end_lsn);
|
buf_flush_recv_note_modification(block, start_lsn, end_lsn);
|
||||||
log_flush_order_mutex_exit();
|
log_flush_order_mutex_exit();
|
||||||
@@ -2095,6 +2055,17 @@ recv_apply_hashed_log_recs(bool last_batch)
|
|||||||
ut_d(recv_no_log_write = recv_no_ibuf_operations);
|
ut_d(recv_no_log_write = recv_no_ibuf_operations);
|
||||||
|
|
||||||
if (ulint n = recv_sys->n_addrs) {
|
if (ulint n = recv_sys->n_addrs) {
|
||||||
|
if (!log_sys.log.subformat && !srv_force_recovery
|
||||||
|
&& srv_undo_tablespaces_open) {
|
||||||
|
ib::error() << "Recovery of separately logged"
|
||||||
|
" TRUNCATE operations is no longer supported."
|
||||||
|
" Set innodb_force_recovery=1"
|
||||||
|
" if no *trunc.log files exist";
|
||||||
|
recv_sys->found_corrupt_log = true;
|
||||||
|
mutex_exit(&recv_sys->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char* msg = last_batch
|
const char* msg = last_batch
|
||||||
? "Starting final batch to recover "
|
? "Starting final batch to recover "
|
||||||
: "Starting a batch to recover ";
|
: "Starting a batch to recover ";
|
||||||
@@ -2120,15 +2091,6 @@ recv_apply_hashed_log_recs(bool last_batch)
|
|||||||
recv_addr = static_cast<recv_addr_t*>(
|
recv_addr = static_cast<recv_addr_t*>(
|
||||||
HASH_GET_NEXT(addr_hash, recv_addr))) {
|
HASH_GET_NEXT(addr_hash, recv_addr))) {
|
||||||
|
|
||||||
if (srv_is_tablespace_truncated(recv_addr->space)) {
|
|
||||||
/* Avoid applying REDO log for the tablespace
|
|
||||||
that is schedule for TRUNCATE. */
|
|
||||||
ut_a(recv_sys->n_addrs);
|
|
||||||
recv_addr->state = RECV_DISCARDED;
|
|
||||||
recv_sys->n_addrs--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recv_addr->state == RECV_DISCARDED) {
|
if (recv_addr->state == RECV_DISCARDED) {
|
||||||
ut_a(recv_sys->n_addrs);
|
ut_a(recv_sys->n_addrs);
|
||||||
recv_sys->n_addrs--;
|
recv_sys->n_addrs--;
|
||||||
|
@@ -32,7 +32,6 @@ Created 11/26/1995 Heikki Tuuri
|
|||||||
#include "page0types.h"
|
#include "page0types.h"
|
||||||
#include "mtr0log.h"
|
#include "mtr0log.h"
|
||||||
#include "log0log.h"
|
#include "log0log.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
|
|
||||||
#include "log0recv.h"
|
#include "log0recv.h"
|
||||||
|
|
||||||
@@ -695,8 +694,7 @@ mtr_t::x_lock_space(ulint space_id, const char* file, unsigned line)
|
|||||||
ut_ad(get_log_mode() != MTR_LOG_NO_REDO
|
ut_ad(get_log_mode() != MTR_LOG_NO_REDO
|
||||||
|| space->purpose == FIL_TYPE_TEMPORARY
|
|| space->purpose == FIL_TYPE_TEMPORARY
|
||||||
|| space->purpose == FIL_TYPE_IMPORT
|
|| space->purpose == FIL_TYPE_IMPORT
|
||||||
|| my_atomic_loadlint(&space->redo_skipped_count) > 0
|
|| my_atomic_loadlint(&space->redo_skipped_count) > 0);
|
||||||
|| srv_is_tablespace_truncated(space->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ut_ad(space);
|
ut_ad(space);
|
||||||
|
@@ -1566,7 +1566,7 @@ page_cur_insert_rec_zip(
|
|||||||
get rid of the modification log. */
|
get rid of the modification log. */
|
||||||
page_create_zip(page_cur_get_block(cursor), index,
|
page_create_zip(page_cur_get_block(cursor), index,
|
||||||
page_header_get_field(page, PAGE_LEVEL),
|
page_header_get_field(page, PAGE_LEVEL),
|
||||||
0, NULL, mtr);
|
0, mtr);
|
||||||
ut_ad(!page_header_get_ptr(page, PAGE_FREE));
|
ut_ad(!page_header_get_ptr(page, PAGE_FREE));
|
||||||
|
|
||||||
if (page_zip_available(
|
if (page_zip_available(
|
||||||
@@ -1641,7 +1641,7 @@ page_cur_insert_rec_zip(
|
|||||||
if (!log_compressed) {
|
if (!log_compressed) {
|
||||||
if (page_zip_compress(
|
if (page_zip_compress(
|
||||||
page_zip, page, index,
|
page_zip, page, index,
|
||||||
level, NULL, NULL)) {
|
level, NULL)) {
|
||||||
page_cur_insert_rec_write_log(
|
page_cur_insert_rec_write_log(
|
||||||
insert_rec, rec_size,
|
insert_rec, rec_size,
|
||||||
cursor->rec, index, mtr);
|
cursor->rec, index, mtr);
|
||||||
|
@@ -30,7 +30,6 @@ Created 2/2/1994 Heikki Tuuri
|
|||||||
#include "page0zip.h"
|
#include "page0zip.h"
|
||||||
#include "buf0buf.h"
|
#include "buf0buf.h"
|
||||||
#include "btr0btr.h"
|
#include "btr0btr.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "lock0lock.h"
|
#include "lock0lock.h"
|
||||||
#include "fut0lst.h"
|
#include "fut0lst.h"
|
||||||
@@ -454,22 +453,15 @@ page_create_zip(
|
|||||||
ulint level, /*!< in: the B-tree level
|
ulint level, /*!< in: the B-tree level
|
||||||
of the page */
|
of the page */
|
||||||
trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */
|
trx_id_t max_trx_id, /*!< in: PAGE_MAX_TRX_ID */
|
||||||
const redo_page_compress_t* page_comp_info,
|
|
||||||
/*!< in: used for applying
|
|
||||||
TRUNCATE log
|
|
||||||
record during recovery */
|
|
||||||
mtr_t* mtr) /*!< in/out: mini-transaction
|
mtr_t* mtr) /*!< in/out: mini-transaction
|
||||||
handle */
|
handle */
|
||||||
{
|
{
|
||||||
page_t* page;
|
page_t* page;
|
||||||
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
|
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
|
||||||
bool is_spatial;
|
|
||||||
|
|
||||||
ut_ad(block);
|
ut_ad(block);
|
||||||
ut_ad(page_zip);
|
ut_ad(page_zip);
|
||||||
ut_ad(index == NULL || dict_table_is_comp(index->table));
|
ut_ad(dict_table_is_comp(index->table));
|
||||||
is_spatial = index ? dict_index_is_spatial(index)
|
|
||||||
: page_comp_info->type & DICT_SPATIAL;
|
|
||||||
|
|
||||||
/* PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC are always 0 for
|
/* PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC are always 0 for
|
||||||
temporary tables. */
|
temporary tables. */
|
||||||
@@ -487,22 +479,11 @@ page_create_zip(
|
|||||||
|| !dict_index_is_sec_or_ibuf(index)
|
|| !dict_index_is_sec_or_ibuf(index)
|
||||||
|| index->table->is_temporary());
|
|| index->table->is_temporary());
|
||||||
|
|
||||||
page = page_create_low(block, TRUE, is_spatial);
|
page = page_create_low(block, TRUE, dict_index_is_spatial(index));
|
||||||
mach_write_to_2(PAGE_HEADER + PAGE_LEVEL + page, level);
|
mach_write_to_2(PAGE_HEADER + PAGE_LEVEL + page, level);
|
||||||
mach_write_to_8(PAGE_HEADER + PAGE_MAX_TRX_ID + page, max_trx_id);
|
mach_write_to_8(PAGE_HEADER + PAGE_MAX_TRX_ID + page, max_trx_id);
|
||||||
|
|
||||||
if (truncate_t::s_fix_up_active) {
|
if (!page_zip_compress(page_zip, page, index, page_zip_level, mtr)) {
|
||||||
/* Compress the index page created when applying
|
|
||||||
TRUNCATE log during recovery */
|
|
||||||
if (!page_zip_compress(page_zip, page, index, page_zip_level,
|
|
||||||
page_comp_info, NULL)) {
|
|
||||||
/* The compression of a newly created
|
|
||||||
page should always succeed. */
|
|
||||||
ut_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (!page_zip_compress(page_zip, page, index,
|
|
||||||
page_zip_level, NULL, mtr)) {
|
|
||||||
/* The compression of a newly created
|
/* The compression of a newly created
|
||||||
page should always succeed. */
|
page should always succeed. */
|
||||||
ut_error;
|
ut_error;
|
||||||
@@ -546,7 +527,7 @@ page_create_empty(
|
|||||||
ut_ad(!index->table->is_temporary());
|
ut_ad(!index->table->is_temporary());
|
||||||
page_create_zip(block, index,
|
page_create_zip(block, index,
|
||||||
page_header_get_field(page, PAGE_LEVEL),
|
page_header_get_field(page, PAGE_LEVEL),
|
||||||
max_trx_id, NULL, mtr);
|
max_trx_id, mtr);
|
||||||
} else {
|
} else {
|
||||||
page_create(block, mtr, page_is_comp(page),
|
page_create(block, mtr, page_is_comp(page),
|
||||||
dict_index_is_spatial(index));
|
dict_index_is_spatial(index));
|
||||||
@@ -721,11 +702,8 @@ page_copy_rec_list_end(
|
|||||||
if (new_page_zip) {
|
if (new_page_zip) {
|
||||||
mtr_set_log_mode(mtr, log_mode);
|
mtr_set_log_mode(mtr, log_mode);
|
||||||
|
|
||||||
if (!page_zip_compress(new_page_zip,
|
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||||
new_page,
|
page_zip_level, mtr)) {
|
||||||
index,
|
|
||||||
page_zip_level,
|
|
||||||
NULL, mtr)) {
|
|
||||||
/* Before trying to reorganize the page,
|
/* Before trying to reorganize the page,
|
||||||
store the number of preceding records on the page. */
|
store the number of preceding records on the page. */
|
||||||
ulint ret_pos
|
ulint ret_pos
|
||||||
@@ -887,7 +865,7 @@ page_copy_rec_list_start(
|
|||||||
goto zip_reorganize;);
|
goto zip_reorganize;);
|
||||||
|
|
||||||
if (!page_zip_compress(new_page_zip, new_page, index,
|
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||||
page_zip_level, NULL, mtr)) {
|
page_zip_level, mtr)) {
|
||||||
ulint ret_pos;
|
ulint ret_pos;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
zip_reorganize:
|
zip_reorganize:
|
||||||
|
@@ -46,7 +46,6 @@ const byte field_ref_zero[FIELD_REF_SIZE] = {
|
|||||||
#include "page0types.h"
|
#include "page0types.h"
|
||||||
#include "log0recv.h"
|
#include "log0recv.h"
|
||||||
#include "row0row.h"
|
#include "row0row.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include "buf0buf.h"
|
#include "buf0buf.h"
|
||||||
#include "buf0types.h"
|
#include "buf0types.h"
|
||||||
@@ -1248,17 +1247,11 @@ page_zip_compress(
|
|||||||
dict_index_t* index, /*!< in: index of the B-tree
|
dict_index_t* index, /*!< in: index of the B-tree
|
||||||
node */
|
node */
|
||||||
ulint level, /*!< in: commpression level */
|
ulint level, /*!< in: commpression level */
|
||||||
const redo_page_compress_t* page_comp_info,
|
|
||||||
/*!< in: used for applying
|
|
||||||
TRUNCATE log
|
|
||||||
record during recovery */
|
|
||||||
mtr_t* mtr) /*!< in/out: mini-transaction,
|
mtr_t* mtr) /*!< in/out: mini-transaction,
|
||||||
or NULL */
|
or NULL */
|
||||||
{
|
{
|
||||||
z_stream c_stream;
|
z_stream c_stream;
|
||||||
int err;
|
int err;
|
||||||
ulint n_fields; /* number of index fields
|
|
||||||
needed */
|
|
||||||
byte* fields; /*!< index field information */
|
byte* fields; /*!< index field information */
|
||||||
byte* buf; /*!< compressed payload of the
|
byte* buf; /*!< compressed payload of the
|
||||||
page */
|
page */
|
||||||
@@ -1273,7 +1266,6 @@ page_zip_compress(
|
|||||||
ulint n_blobs = 0;
|
ulint n_blobs = 0;
|
||||||
byte* storage; /* storage of uncompressed
|
byte* storage; /* storage of uncompressed
|
||||||
columns */
|
columns */
|
||||||
index_id_t ind_id;
|
|
||||||
uintmax_t usec = ut_time_us(NULL);
|
uintmax_t usec = ut_time_us(NULL);
|
||||||
#ifdef PAGE_ZIP_COMPRESS_DBG
|
#ifdef PAGE_ZIP_COMPRESS_DBG
|
||||||
FILE* logfile = NULL;
|
FILE* logfile = NULL;
|
||||||
@@ -1288,10 +1280,8 @@ page_zip_compress(
|
|||||||
ut_a(fil_page_index_page_check(page));
|
ut_a(fil_page_index_page_check(page));
|
||||||
ut_ad(page_simple_validate_new((page_t*) page));
|
ut_ad(page_simple_validate_new((page_t*) page));
|
||||||
ut_ad(page_zip_simple_validate(page_zip));
|
ut_ad(page_zip_simple_validate(page_zip));
|
||||||
ut_ad(!index
|
ut_ad(dict_table_is_comp(index->table));
|
||||||
|| (index
|
ut_ad(!dict_index_is_ibuf(index));
|
||||||
&& dict_table_is_comp(index->table)
|
|
||||||
&& !dict_index_is_ibuf(index)));
|
|
||||||
|
|
||||||
UNIV_MEM_ASSERT_RW(page, srv_page_size);
|
UNIV_MEM_ASSERT_RW(page, srv_page_size);
|
||||||
|
|
||||||
@@ -1311,18 +1301,10 @@ page_zip_compress(
|
|||||||
== PAGE_NEW_SUPREMUM);
|
== PAGE_NEW_SUPREMUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (truncate_t::s_fix_up_active) {
|
const ulint n_fields = page_is_leaf(page)
|
||||||
ut_ad(page_comp_info != NULL);
|
? dict_index_get_n_fields(index)
|
||||||
n_fields = page_comp_info->n_fields;
|
: dict_index_get_n_unique_in_tree_nonleaf(index);
|
||||||
ind_id = page_comp_info->index_id;
|
index_id_t ind_id = index->id;
|
||||||
} else {
|
|
||||||
if (page_is_leaf(page)) {
|
|
||||||
n_fields = dict_index_get_n_fields(index);
|
|
||||||
} else {
|
|
||||||
n_fields = dict_index_get_n_unique_in_tree_nonleaf(index);
|
|
||||||
}
|
|
||||||
ind_id = index->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The dense directory excludes the infimum and supremum records. */
|
/* The dense directory excludes the infimum and supremum records. */
|
||||||
n_dense = ulint(page_dir_get_n_heap(page)) - PAGE_HEAP_NO_USER_LOW;
|
n_dense = ulint(page_dir_get_n_heap(page)) - PAGE_HEAP_NO_USER_LOW;
|
||||||
@@ -1433,20 +1415,11 @@ page_zip_compress(
|
|||||||
|
|
||||||
/* Dense page directory and uncompressed columns, if any */
|
/* Dense page directory and uncompressed columns, if any */
|
||||||
if (page_is_leaf(page)) {
|
if (page_is_leaf(page)) {
|
||||||
if ((index && dict_index_is_clust(index))
|
if (dict_index_is_clust(index)) {
|
||||||
|| (page_comp_info
|
|
||||||
&& (page_comp_info->type & DICT_CLUSTERED))) {
|
|
||||||
|
|
||||||
if (index) {
|
|
||||||
trx_id_col = dict_index_get_sys_col_pos(
|
trx_id_col = dict_index_get_sys_col_pos(
|
||||||
index, DATA_TRX_ID);
|
index, DATA_TRX_ID);
|
||||||
ut_ad(trx_id_col > 0);
|
ut_ad(trx_id_col > 0);
|
||||||
ut_ad(trx_id_col != ULINT_UNDEFINED);
|
ut_ad(trx_id_col != ULINT_UNDEFINED);
|
||||||
} else if (page_comp_info
|
|
||||||
&& (page_comp_info->type
|
|
||||||
& DICT_CLUSTERED)) {
|
|
||||||
trx_id_col = page_comp_info->trx_id_pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot_size = PAGE_ZIP_DIR_SLOT_SIZE
|
slot_size = PAGE_ZIP_DIR_SLOT_SIZE
|
||||||
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
|
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
|
||||||
@@ -1454,10 +1427,8 @@ page_zip_compress(
|
|||||||
} else {
|
} else {
|
||||||
/* Signal the absence of trx_id
|
/* Signal the absence of trx_id
|
||||||
in page_zip_fields_encode() */
|
in page_zip_fields_encode() */
|
||||||
if (index) {
|
|
||||||
ut_ad(dict_index_get_sys_col_pos(
|
ut_ad(dict_index_get_sys_col_pos(
|
||||||
index, DATA_TRX_ID) == ULINT_UNDEFINED);
|
index, DATA_TRX_ID) == ULINT_UNDEFINED);
|
||||||
}
|
|
||||||
trx_id_col = 0;
|
trx_id_col = 0;
|
||||||
slot_size = PAGE_ZIP_DIR_SLOT_SIZE;
|
slot_size = PAGE_ZIP_DIR_SLOT_SIZE;
|
||||||
}
|
}
|
||||||
@@ -1471,19 +1442,9 @@ page_zip_compress(
|
|||||||
goto zlib_error;
|
goto zlib_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
c_stream.avail_out -= static_cast<uInt>(n_dense * slot_size);
|
c_stream.avail_out -= uInt(n_dense * slot_size);
|
||||||
if (truncate_t::s_fix_up_active) {
|
c_stream.avail_in = uInt(page_zip_fields_encode(n_fields, index,
|
||||||
ut_ad(page_comp_info != NULL);
|
trx_id_col, fields));
|
||||||
c_stream.avail_in = static_cast<uInt>(
|
|
||||||
page_comp_info->field_len);
|
|
||||||
for (ulint i = 0; i < page_comp_info->field_len; i++) {
|
|
||||||
fields[i] = page_comp_info->fields[i];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
c_stream.avail_in = static_cast<uInt>(
|
|
||||||
page_zip_fields_encode(
|
|
||||||
n_fields, index, trx_id_col, fields));
|
|
||||||
}
|
|
||||||
c_stream.next_in = fields;
|
c_stream.next_in = fields;
|
||||||
|
|
||||||
if (UNIV_LIKELY(!trx_id_col)) {
|
if (UNIV_LIKELY(!trx_id_col)) {
|
||||||
@@ -1637,7 +1598,7 @@ err_exit:
|
|||||||
mutex_exit(&page_zip_stat_per_index_mutex);
|
mutex_exit(&page_zip_stat_per_index_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (page_is_leaf(page) && !truncate_t::s_fix_up_active) {
|
if (page_is_leaf(page)) {
|
||||||
dict_index_zip_success(index);
|
dict_index_zip_success(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4807,9 +4768,7 @@ page_zip_reorganize(
|
|||||||
/* Restore logging. */
|
/* Restore logging. */
|
||||||
mtr_set_log_mode(mtr, log_mode);
|
mtr_set_log_mode(mtr, log_mode);
|
||||||
|
|
||||||
if (!page_zip_compress(page_zip, page, index,
|
if (!page_zip_compress(page_zip, page, index, page_zip_level, mtr)) {
|
||||||
page_zip_level, NULL, mtr)) {
|
|
||||||
|
|
||||||
buf_block_free(temp_block);
|
buf_block_free(temp_block);
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,6 @@ Created 10/8/1995 Heikki Tuuri
|
|||||||
#include "pars0pars.h"
|
#include "pars0pars.h"
|
||||||
#include "que0que.h"
|
#include "que0que.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "row0log.h"
|
#include "row0log.h"
|
||||||
#include "srv0mon.h"
|
#include "srv0mon.h"
|
||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
@@ -2585,16 +2584,10 @@ srv_do_purge(ulint* n_total_purged)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ulint undo_trunc_freq =
|
|
||||||
purge_sys.undo_trunc.get_rseg_truncate_frequency();
|
|
||||||
|
|
||||||
ulint rseg_truncate_frequency = ut_min(
|
|
||||||
static_cast<ulint>(srv_purge_rseg_truncate_frequency),
|
|
||||||
undo_trunc_freq);
|
|
||||||
|
|
||||||
n_pages_purged = trx_purge(
|
n_pages_purged = trx_purge(
|
||||||
n_use_threads,
|
n_use_threads,
|
||||||
(++count % rseg_truncate_frequency) == 0);
|
!(++count % srv_purge_rseg_truncate_frequency)
|
||||||
|
|| purge_sys.truncate.current);
|
||||||
|
|
||||||
*n_total_purged += n_pages_purged;
|
*n_total_purged += n_pages_purged;
|
||||||
} while (n_pages_purged > 0 && !purge_sys.paused()
|
} while (n_pages_purged > 0 && !purge_sys.paused()
|
||||||
@@ -2729,11 +2722,6 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
|
|||||||
/* Note that we are shutting down. */
|
/* Note that we are shutting down. */
|
||||||
rw_lock_x_lock(&purge_sys.latch);
|
rw_lock_x_lock(&purge_sys.latch);
|
||||||
purge_sys.coordinator_shutdown();
|
purge_sys.coordinator_shutdown();
|
||||||
|
|
||||||
/* If there are any pending undo-tablespace truncate then clear
|
|
||||||
it off as we plan to shutdown the purge thread. */
|
|
||||||
purge_sys.undo_trunc.clear();
|
|
||||||
|
|
||||||
/* Ensure that the wait in purge_sys_t::stop() will terminate. */
|
/* Ensure that the wait in purge_sys_t::stop() will terminate. */
|
||||||
os_event_set(purge_sys.event);
|
os_event_set(purge_sys.event);
|
||||||
|
|
||||||
@@ -2840,38 +2828,3 @@ void srv_purge_shutdown()
|
|||||||
srv_purge_wakeup();
|
srv_purge_wakeup();
|
||||||
} while (srv_sys.sys_threads[SRV_PURGE_SLOT].in_use);
|
} while (srv_sys.sys_threads[SRV_PURGE_SLOT].in_use);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if tablespace is being truncated.
|
|
||||||
(Ignore system-tablespace as we don't re-create the tablespace
|
|
||||||
and so some of the action that are suppressed by this function
|
|
||||||
for independent tablespace are not applicable to system-tablespace).
|
|
||||||
@param space_id space_id to check for truncate action
|
|
||||||
@return true if being truncated, false if not being
|
|
||||||
truncated or tablespace is system-tablespace. */
|
|
||||||
bool
|
|
||||||
srv_is_tablespace_truncated(ulint space_id)
|
|
||||||
{
|
|
||||||
if (is_system_tablespace(space_id)) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(truncate_t::is_tablespace_truncated(space_id)
|
|
||||||
|| undo::Truncate::is_tablespace_truncated(space_id));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if tablespace was truncated.
|
|
||||||
@param[in] space space object to check for truncate action
|
|
||||||
@return true if tablespace was truncated and we still have an active
|
|
||||||
MLOG_TRUNCATE REDO log record. */
|
|
||||||
bool
|
|
||||||
srv_was_tablespace_truncated(const fil_space_t* space)
|
|
||||||
{
|
|
||||||
if (space == NULL) {
|
|
||||||
ut_ad(0);
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (!is_system_tablespace(space->id)
|
|
||||||
&& truncate_t::was_tablespace_truncated(space->id));
|
|
||||||
}
|
|
||||||
|
@@ -77,7 +77,6 @@ Created 2/16/1996 Heikki Tuuri
|
|||||||
#include "srv0srv.h"
|
#include "srv0srv.h"
|
||||||
#include "btr0defragment.h"
|
#include "btr0defragment.h"
|
||||||
#include "fsp0sysspace.h"
|
#include "fsp0sysspace.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "mysql/service_wsrep.h" /* wsrep_recovery */
|
#include "mysql/service_wsrep.h" /* wsrep_recovery */
|
||||||
#include "trx0rseg.h"
|
#include "trx0rseg.h"
|
||||||
#include "os0proc.h"
|
#include "os0proc.h"
|
||||||
@@ -100,7 +99,6 @@ Created 2/16/1996 Heikki Tuuri
|
|||||||
#include "row0upd.h"
|
#include "row0upd.h"
|
||||||
#include "row0row.h"
|
#include "row0row.h"
|
||||||
#include "row0mysql.h"
|
#include "row0mysql.h"
|
||||||
#include "row0trunc.h"
|
|
||||||
#include "btr0pcur.h"
|
#include "btr0pcur.h"
|
||||||
#include "os0event.h"
|
#include "os0event.h"
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
@@ -815,8 +813,6 @@ srv_check_undo_redo_logs_exists()
|
|||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
undo::undo_spaces_t undo::Truncate::s_fix_up_spaces;
|
|
||||||
|
|
||||||
/** Open the configured number of dedicated undo tablespaces.
|
/** Open the configured number of dedicated undo tablespaces.
|
||||||
@param[in] create_new_db whether the database is being initialized
|
@param[in] create_new_db whether the database is being initialized
|
||||||
@return DB_SUCCESS or error code */
|
@return DB_SUCCESS or error code */
|
||||||
@@ -898,46 +894,8 @@ srv_undo_tablespaces_init(bool create_new_db)
|
|||||||
prev_space_id = srv_undo_space_id_start - 1;
|
prev_space_id = srv_undo_space_id_start - 1;
|
||||||
break;
|
break;
|
||||||
case SRV_OPERATION_NORMAL:
|
case SRV_OPERATION_NORMAL:
|
||||||
if (create_new_db) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* fall through */
|
|
||||||
case SRV_OPERATION_RESTORE:
|
case SRV_OPERATION_RESTORE:
|
||||||
case SRV_OPERATION_RESTORE_EXPORT:
|
case SRV_OPERATION_RESTORE_EXPORT:
|
||||||
ut_ad(!create_new_db);
|
|
||||||
|
|
||||||
/* Check if any of the UNDO tablespace needs fix-up because
|
|
||||||
server crashed while truncate was active on UNDO tablespace.*/
|
|
||||||
for (i = 0; i < n_undo_tablespaces; ++i) {
|
|
||||||
|
|
||||||
undo::Truncate undo_trunc;
|
|
||||||
|
|
||||||
if (undo_trunc.needs_fix_up(undo_tablespace_ids[i])) {
|
|
||||||
|
|
||||||
char name[OS_FILE_MAX_PATH];
|
|
||||||
|
|
||||||
snprintf(name, sizeof(name),
|
|
||||||
"%s%cundo%03zu",
|
|
||||||
srv_undo_dir, OS_PATH_SEPARATOR,
|
|
||||||
undo_tablespace_ids[i]);
|
|
||||||
|
|
||||||
os_file_delete(innodb_data_file_key, name);
|
|
||||||
|
|
||||||
err = srv_undo_tablespace_create(
|
|
||||||
name,
|
|
||||||
SRV_UNDO_TABLESPACE_SIZE_IN_PAGES);
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
ib::error() << "Could not fix-up undo "
|
|
||||||
" tablespace truncate '"
|
|
||||||
<< name << "'.";
|
|
||||||
return(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
undo::Truncate::s_fix_up_spaces.push_back(
|
|
||||||
undo_tablespace_ids[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1044,64 +1002,6 @@ srv_undo_tablespaces_init(bool create_new_db)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!undo::Truncate::s_fix_up_spaces.empty()) {
|
|
||||||
|
|
||||||
/* Step-1: Initialize the tablespace header and rsegs header. */
|
|
||||||
mtr_t mtr;
|
|
||||||
|
|
||||||
mtr_start(&mtr);
|
|
||||||
/* Turn off REDO logging. We are in server start mode and fixing
|
|
||||||
UNDO tablespace even before REDO log is read. Let's say we
|
|
||||||
do REDO logging here then this REDO log record will be applied
|
|
||||||
as part of the current recovery process. We surely don't need
|
|
||||||
that as this is fix-up action parallel to REDO logging. */
|
|
||||||
mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
|
|
||||||
buf_block_t* sys_header = trx_sysf_get(&mtr);
|
|
||||||
if (!sys_header) {
|
|
||||||
mtr.commit();
|
|
||||||
return DB_CORRUPTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (undo::undo_spaces_t::const_iterator it
|
|
||||||
= undo::Truncate::s_fix_up_spaces.begin();
|
|
||||||
it != undo::Truncate::s_fix_up_spaces.end();
|
|
||||||
++it) {
|
|
||||||
|
|
||||||
undo::Truncate::add_space_to_trunc_list(*it);
|
|
||||||
|
|
||||||
fil_space_t* space = fil_space_get(*it);
|
|
||||||
|
|
||||||
fsp_header_init(space,
|
|
||||||
SRV_UNDO_TABLESPACE_SIZE_IN_PAGES,
|
|
||||||
&mtr);
|
|
||||||
|
|
||||||
for (ulint i = 0; i < TRX_SYS_N_RSEGS; i++) {
|
|
||||||
if (trx_sysf_rseg_get_space(sys_header, i)
|
|
||||||
== *it) {
|
|
||||||
trx_rseg_header_create(
|
|
||||||
space, i, sys_header, &mtr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
undo::Truncate::clear_trunc_list();
|
|
||||||
}
|
|
||||||
mtr_commit(&mtr);
|
|
||||||
|
|
||||||
/* Step-2: Flush the dirty pages from the buffer pool. */
|
|
||||||
for (undo::undo_spaces_t::const_iterator it
|
|
||||||
= undo::Truncate::s_fix_up_spaces.begin();
|
|
||||||
it != undo::Truncate::s_fix_up_spaces.end();
|
|
||||||
++it) {
|
|
||||||
FlushObserver dummy(fil_system.sys_space, NULL, NULL);
|
|
||||||
buf_LRU_flush_or_remove_pages(TRX_SYS_SPACE, &dummy);
|
|
||||||
FlushObserver dummy2(fil_space_get(*it), NULL, NULL);
|
|
||||||
buf_LRU_flush_or_remove_pages(*it, &dummy2);
|
|
||||||
|
|
||||||
/* Remove the truncate redo log file. */
|
|
||||||
undo::done(*it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
return(DB_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1943,7 +1843,7 @@ files_checked:
|
|||||||
|
|
||||||
ulint ibuf_root = btr_create(
|
ulint ibuf_root = btr_create(
|
||||||
DICT_CLUSTERED | DICT_IBUF, fil_system.sys_space,
|
DICT_CLUSTERED | DICT_IBUF, fil_system.sys_space,
|
||||||
DICT_IBUF_ID_MIN, dict_ind_redundant, NULL, &mtr);
|
DICT_IBUF_ID_MIN, dict_ind_redundant, &mtr);
|
||||||
|
|
||||||
mtr_commit(&mtr);
|
mtr_commit(&mtr);
|
||||||
|
|
||||||
@@ -1982,22 +1882,6 @@ files_checked:
|
|||||||
return(srv_init_abort(err));
|
return(srv_init_abort(err));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Invalidate the buffer pool to ensure that we reread
|
|
||||||
the page that we read above, during recovery.
|
|
||||||
Note that this is not as heavy weight as it seems. At
|
|
||||||
this point there will be only ONE page in the buf_LRU
|
|
||||||
and there must be no page in the buf_flush list. */
|
|
||||||
buf_pool_invalidate();
|
|
||||||
|
|
||||||
/* Scan and locate truncate log files. Parsed located files
|
|
||||||
and add table to truncate information to central vector for
|
|
||||||
truncate fix-up action post recovery. */
|
|
||||||
err = TruncateLogParser::scan_and_parse(srv_log_group_home_dir);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
|
|
||||||
return(srv_init_abort(DB_ERROR));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We always try to do a recovery, even if the database had
|
/* We always try to do a recovery, even if the database had
|
||||||
been shut down normally: this is the normal startup path */
|
been shut down normally: this is the normal startup path */
|
||||||
|
|
||||||
@@ -2276,14 +2160,6 @@ files_checked:
|
|||||||
trx_rollback_recovered(false);
|
trx_rollback_recovered(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix-up truncate of tables in the system tablespace
|
|
||||||
if server crashed while truncate was active. The non-
|
|
||||||
system tables are done after tablespace discovery. Do
|
|
||||||
this now because this procedure assumes that no pages
|
|
||||||
have changed since redo recovery. Tablespace discovery
|
|
||||||
can do updates to pages in the system tablespace.*/
|
|
||||||
err = truncate_t::fixup_tables_in_system_tablespace();
|
|
||||||
|
|
||||||
if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
|
if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
|
||||||
/* Open or Create SYS_TABLESPACES and SYS_DATAFILES
|
/* Open or Create SYS_TABLESPACES and SYS_DATAFILES
|
||||||
so that tablespace names and other metadata can be
|
so that tablespace names and other metadata can be
|
||||||
@@ -2321,10 +2197,6 @@ files_checked:
|
|||||||
dict_check_tablespaces_and_store_max_id(validate);
|
dict_check_tablespaces_and_store_max_id(validate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fix-up truncate of table if server crashed while truncate
|
|
||||||
was active. */
|
|
||||||
err = truncate_t::fixup_tables_in_non_system_tablespace();
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
if (err != DB_SUCCESS) {
|
||||||
return(srv_init_abort(err));
|
return(srv_init_abort(err));
|
||||||
}
|
}
|
||||||
|
@@ -177,7 +177,8 @@ void purge_sys_t::create()
|
|||||||
hdr_offset= 0;
|
hdr_offset= 0;
|
||||||
rw_lock_create(trx_purge_latch_key, &latch, SYNC_PURGE_LATCH);
|
rw_lock_create(trx_purge_latch_key, &latch, SYNC_PURGE_LATCH);
|
||||||
mutex_create(LATCH_ID_PURGE_SYS_PQ, &pq_mutex);
|
mutex_create(LATCH_ID_PURGE_SYS_PQ, &pq_mutex);
|
||||||
undo_trunc.create();
|
truncate.current= NULL;
|
||||||
|
truncate.last= NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Close the purge subsystem on shutdown. */
|
/** Close the purge subsystem on shutdown. */
|
||||||
@@ -513,309 +514,22 @@ func_exit:
|
|||||||
goto loop;
|
goto loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** UNDO log truncate logger. Needed to track state of truncate during crash.
|
|
||||||
An auxiliary redo log file undo_<space_id>_trunc.log will created while the
|
|
||||||
truncate of the UNDO is in progress. This file is required during recovery
|
|
||||||
to complete the truncate. */
|
|
||||||
|
|
||||||
namespace undo {
|
|
||||||
/** Magic Number to indicate truncate action is complete. */
|
|
||||||
static const ib_uint32_t s_magic = 76845412;
|
|
||||||
|
|
||||||
/** Populate log file name based on space_id
|
|
||||||
@param[in] space_id id of the undo tablespace.
|
|
||||||
@return DB_SUCCESS or error code */
|
|
||||||
static dberr_t populate_log_file_name(
|
|
||||||
ulint space_id,
|
|
||||||
char*& log_file_name)
|
|
||||||
{
|
|
||||||
static const char s_log_prefix[] = "undo_";
|
|
||||||
static const char s_log_ext[] = "trunc.log";
|
|
||||||
|
|
||||||
ulint log_file_name_sz = strlen(srv_log_group_home_dir)
|
|
||||||
+ (22 - 1 /* NUL */
|
|
||||||
+ sizeof s_log_prefix + sizeof s_log_ext);
|
|
||||||
|
|
||||||
log_file_name = new (std::nothrow) char[log_file_name_sz];
|
|
||||||
if (log_file_name == 0) {
|
|
||||||
return(DB_OUT_OF_MEMORY);
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(log_file_name, 0, log_file_name_sz);
|
|
||||||
|
|
||||||
strcpy(log_file_name, srv_log_group_home_dir);
|
|
||||||
ulint log_file_name_len = strlen(log_file_name);
|
|
||||||
|
|
||||||
if (log_file_name[log_file_name_len - 1]
|
|
||||||
!= OS_PATH_SEPARATOR) {
|
|
||||||
|
|
||||||
log_file_name[log_file_name_len]
|
|
||||||
= OS_PATH_SEPARATOR;
|
|
||||||
log_file_name_len = strlen(log_file_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(log_file_name + log_file_name_len,
|
|
||||||
log_file_name_sz - log_file_name_len,
|
|
||||||
"%s" ULINTPF "_%s", s_log_prefix,
|
|
||||||
space_id, s_log_ext);
|
|
||||||
|
|
||||||
return(DB_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Mark completion of undo truncate action by writing magic number to
|
|
||||||
the log file and then removing it from the disk.
|
|
||||||
If we are going to remove it from disk then why write magic number ?
|
|
||||||
This is to safeguard from unlink (file-system) anomalies that will keep
|
|
||||||
the link to the file even after unlink action is successfull and
|
|
||||||
ref-count = 0.
|
|
||||||
@param[in] space_id id of the undo tablespace to truncate.*/
|
|
||||||
void done(
|
|
||||||
ulint space_id)
|
|
||||||
{
|
|
||||||
dberr_t err;
|
|
||||||
char* log_file_name;
|
|
||||||
|
|
||||||
/* Step-1: Create the log file name using the pre-decided
|
|
||||||
prefix/suffix and table id of undo tablepsace to truncate. */
|
|
||||||
err = populate_log_file_name(space_id, log_file_name);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step-2: Open log file and write magic number to
|
|
||||||
indicate done phase. */
|
|
||||||
bool ret;
|
|
||||||
os_file_t handle =
|
|
||||||
os_file_create_simple_no_error_handling(
|
|
||||||
innodb_log_file_key, log_file_name,
|
|
||||||
OS_FILE_OPEN, OS_FILE_READ_WRITE,
|
|
||||||
srv_read_only_mode, &ret);
|
|
||||||
|
|
||||||
if (!ret) {
|
|
||||||
os_file_delete(innodb_log_file_key, log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ulint sz = srv_page_size;
|
|
||||||
void* buf = ut_zalloc_nokey(sz + srv_page_size);
|
|
||||||
if (buf == NULL) {
|
|
||||||
os_file_close(handle);
|
|
||||||
os_file_delete(innodb_log_file_key, log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte* log_buf = static_cast<byte*>(
|
|
||||||
ut_align(buf, srv_page_size));
|
|
||||||
|
|
||||||
mach_write_to_4(log_buf, undo::s_magic);
|
|
||||||
|
|
||||||
IORequest request(IORequest::WRITE);
|
|
||||||
|
|
||||||
err = os_file_write(
|
|
||||||
request, log_file_name, handle, log_buf, 0, sz);
|
|
||||||
|
|
||||||
ut_ad(err == DB_SUCCESS);
|
|
||||||
|
|
||||||
os_file_flush(handle);
|
|
||||||
os_file_close(handle);
|
|
||||||
|
|
||||||
ut_free(buf);
|
|
||||||
os_file_delete(innodb_log_file_key, log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if TRUNCATE_DDL_LOG file exist.
|
|
||||||
@param[in] space_id id of the undo tablespace.
|
|
||||||
@return true if exist else false. */
|
|
||||||
bool is_log_present(
|
|
||||||
ulint space_id)
|
|
||||||
{
|
|
||||||
dberr_t err;
|
|
||||||
char* log_file_name;
|
|
||||||
|
|
||||||
/* Step-1: Populate log file name. */
|
|
||||||
err = populate_log_file_name(space_id, log_file_name);
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step-2: Check for existence of the file. */
|
|
||||||
bool exist;
|
|
||||||
os_file_type_t type;
|
|
||||||
os_file_status(log_file_name, &exist, &type);
|
|
||||||
|
|
||||||
/* Step-3: If file exists, check it for presence of magic
|
|
||||||
number. If found, then delete the file and report file
|
|
||||||
doesn't exist as presence of magic number suggest that
|
|
||||||
truncate action was complete. */
|
|
||||||
|
|
||||||
if (exist) {
|
|
||||||
bool ret;
|
|
||||||
os_file_t handle =
|
|
||||||
os_file_create_simple_no_error_handling(
|
|
||||||
innodb_log_file_key, log_file_name,
|
|
||||||
OS_FILE_OPEN, OS_FILE_READ_WRITE,
|
|
||||||
srv_read_only_mode, &ret);
|
|
||||||
if (!ret) {
|
|
||||||
os_file_delete(innodb_log_file_key,
|
|
||||||
log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ulint sz = srv_page_size;
|
|
||||||
void* buf = ut_zalloc_nokey(sz + srv_page_size);
|
|
||||||
if (buf == NULL) {
|
|
||||||
os_file_close(handle);
|
|
||||||
os_file_delete(innodb_log_file_key,
|
|
||||||
log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte* log_buf = static_cast<byte*>(
|
|
||||||
ut_align(buf, srv_page_size));
|
|
||||||
|
|
||||||
IORequest request(IORequest::READ);
|
|
||||||
|
|
||||||
dberr_t err;
|
|
||||||
|
|
||||||
err = os_file_read(request, handle, log_buf, 0, sz);
|
|
||||||
|
|
||||||
os_file_close(handle);
|
|
||||||
|
|
||||||
if (err != DB_SUCCESS) {
|
|
||||||
|
|
||||||
ib::info()
|
|
||||||
<< "Unable to read '"
|
|
||||||
<< log_file_name << "' : "
|
|
||||||
<< ut_strerr(err);
|
|
||||||
|
|
||||||
os_file_delete(
|
|
||||||
innodb_log_file_key, log_file_name);
|
|
||||||
|
|
||||||
ut_free(buf);
|
|
||||||
|
|
||||||
delete[] log_file_name;
|
|
||||||
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
ulint magic_no = mach_read_from_4(log_buf);
|
|
||||||
|
|
||||||
ut_free(buf);
|
|
||||||
|
|
||||||
if (magic_no == undo::s_magic) {
|
|
||||||
/* Found magic number. */
|
|
||||||
os_file_delete(innodb_log_file_key,
|
|
||||||
log_file_name);
|
|
||||||
delete[] log_file_name;
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] log_file_name;
|
|
||||||
|
|
||||||
return(exist);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Iterate over all the UNDO tablespaces and check if any of the UNDO
|
|
||||||
tablespace qualifies for TRUNCATE (size > threshold).
|
|
||||||
@param[in,out] undo_trunc undo truncate tracker */
|
|
||||||
static
|
|
||||||
void
|
|
||||||
trx_purge_mark_undo_for_truncate(
|
|
||||||
undo::Truncate* undo_trunc)
|
|
||||||
{
|
|
||||||
/* Step-1: If UNDO Tablespace
|
|
||||||
- already marked for truncate (OR)
|
|
||||||
- truncate disabled
|
|
||||||
return immediately else search for qualifying tablespace. */
|
|
||||||
if (undo_trunc->is_marked() || !srv_undo_log_truncate) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step-2: Validation/Qualification checks
|
|
||||||
a. At-least 2 UNDO tablespaces so even if one UNDO tablespace
|
|
||||||
is being truncated server can continue to operate.
|
|
||||||
b. At-least 2 persistent UNDO logs (besides the default rseg-0)
|
|
||||||
b. At-least 1 UNDO tablespace size > threshold. */
|
|
||||||
if (srv_undo_tablespaces_active < 2 || srv_undo_logs < 3) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Avoid bias selection and so start the scan from immediate next
|
|
||||||
of last selected UNDO tablespace for truncate. */
|
|
||||||
ulint space_id = undo_trunc->get_scan_start();
|
|
||||||
|
|
||||||
for (ulint i = 1; i <= srv_undo_tablespaces_active; i++) {
|
|
||||||
|
|
||||||
if (fil_space_get_size(space_id)
|
|
||||||
> (srv_max_undo_log_size >> srv_page_size_shift)) {
|
|
||||||
/* Tablespace qualifies for truncate. */
|
|
||||||
undo_trunc->mark(space_id);
|
|
||||||
undo::Truncate::add_space_to_trunc_list(space_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
space_id = ((space_id + 1) % (srv_undo_tablespaces_active + 1));
|
|
||||||
if (space_id == 0) {
|
|
||||||
/* Note: UNDO tablespace ids starts from 1. */
|
|
||||||
++space_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Couldn't make any selection. */
|
|
||||||
if (!undo_trunc->is_marked()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_LOG("undo",
|
|
||||||
"marking for truncate UNDO tablespace "
|
|
||||||
<< undo_trunc->get_marked_space_id());
|
|
||||||
|
|
||||||
/* Step-3: Iterate over all the rsegs of selected UNDO tablespace
|
|
||||||
and mark them temporarily unavailable for allocation.*/
|
|
||||||
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
|
||||||
if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) {
|
|
||||||
ut_ad(rseg->is_persistent());
|
|
||||||
if (rseg->space->id
|
|
||||||
== undo_trunc->get_marked_space_id()) {
|
|
||||||
|
|
||||||
/* Once set this rseg will not be allocated
|
|
||||||
to new booting transaction but we will wait
|
|
||||||
for existing active transaction to finish. */
|
|
||||||
rseg->skip_allocation = true;
|
|
||||||
undo_trunc->add_rseg_to_trunc(rseg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
undo::undo_spaces_t undo::Truncate::s_spaces_to_truncate;
|
|
||||||
|
|
||||||
/** Cleanse purge queue to remove the rseg that reside in undo-tablespace
|
/** Cleanse purge queue to remove the rseg that reside in undo-tablespace
|
||||||
marked for truncate.
|
marked for truncate.
|
||||||
@param[in,out] undo_trunc undo truncate tracker */
|
@param[in] space undo tablespace being truncated */
|
||||||
static
|
static void trx_purge_cleanse_purge_queue(const fil_space_t& space)
|
||||||
void
|
|
||||||
trx_purge_cleanse_purge_queue(
|
|
||||||
undo::Truncate* undo_trunc)
|
|
||||||
{
|
{
|
||||||
mutex_enter(&purge_sys.pq_mutex);
|
|
||||||
typedef std::vector<TrxUndoRsegs> purge_elem_list_t;
|
typedef std::vector<TrxUndoRsegs> purge_elem_list_t;
|
||||||
purge_elem_list_t purge_elem_list;
|
purge_elem_list_t purge_elem_list;
|
||||||
|
|
||||||
|
mutex_enter(&purge_sys.pq_mutex);
|
||||||
|
|
||||||
/* Remove rseg instances that are in the purge queue before we start
|
/* Remove rseg instances that are in the purge queue before we start
|
||||||
truncate of corresponding UNDO truncate. */
|
truncate of corresponding UNDO truncate. */
|
||||||
while (!purge_sys.purge_queue.empty()) {
|
while (!purge_sys.purge_queue.empty()) {
|
||||||
purge_elem_list.push_back(purge_sys.purge_queue.top());
|
purge_elem_list.push_back(purge_sys.purge_queue.top());
|
||||||
purge_sys.purge_queue.pop();
|
purge_sys.purge_queue.pop();
|
||||||
}
|
}
|
||||||
ut_ad(purge_sys.purge_queue.empty());
|
|
||||||
|
|
||||||
for (purge_elem_list_t::iterator it = purge_elem_list.begin();
|
for (purge_elem_list_t::iterator it = purge_elem_list.begin();
|
||||||
it != purge_elem_list.end();
|
it != purge_elem_list.end();
|
||||||
@@ -824,9 +538,7 @@ trx_purge_cleanse_purge_queue(
|
|||||||
for (TrxUndoRsegs::iterator it2 = it->begin();
|
for (TrxUndoRsegs::iterator it2 = it->begin();
|
||||||
it2 != it->end();
|
it2 != it->end();
|
||||||
++it2) {
|
++it2) {
|
||||||
|
if ((*it2)->space == &space) {
|
||||||
if ((*it2)->space->id
|
|
||||||
== undo_trunc->get_marked_space_id()) {
|
|
||||||
it->erase(it2);
|
it->erase(it2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -836,251 +548,10 @@ trx_purge_cleanse_purge_queue(
|
|||||||
purge_sys.purge_queue.push(*it);
|
purge_sys.purge_queue.push(*it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_exit(&purge_sys.pq_mutex);
|
mutex_exit(&purge_sys.pq_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Iterate over selected UNDO tablespace and check if all the rsegs
|
|
||||||
that resides in the tablespace are free.
|
|
||||||
@param[in] limit truncate_limit
|
|
||||||
@param[in,out] undo_trunc undo truncate tracker */
|
|
||||||
static
|
|
||||||
void
|
|
||||||
trx_purge_initiate_truncate(
|
|
||||||
const purge_sys_t::iterator& limit,
|
|
||||||
undo::Truncate* undo_trunc)
|
|
||||||
{
|
|
||||||
/* Step-1: Early check to findout if any of the the UNDO tablespace
|
|
||||||
is marked for truncate. */
|
|
||||||
if (!undo_trunc->is_marked()) {
|
|
||||||
/* No tablespace marked for truncate yet. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step-2: Scan over each rseg and ensure that it doesn't hold any
|
|
||||||
active undo records. */
|
|
||||||
bool all_free = true;
|
|
||||||
|
|
||||||
for (ulint i = 0; i < undo_trunc->rsegs_size() && all_free; ++i) {
|
|
||||||
|
|
||||||
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
|
|
||||||
|
|
||||||
mutex_enter(&rseg->mutex);
|
|
||||||
|
|
||||||
if (rseg->trx_ref_count > 0) {
|
|
||||||
/* This rseg is still being held by an active
|
|
||||||
transaction. */
|
|
||||||
all_free = false;
|
|
||||||
mutex_exit(&rseg->mutex);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(rseg->trx_ref_count == 0);
|
|
||||||
ut_ad(rseg->skip_allocation);
|
|
||||||
|
|
||||||
ulint size_of_rsegs = rseg->curr_size;
|
|
||||||
|
|
||||||
if (size_of_rsegs == 1) {
|
|
||||||
mutex_exit(&rseg->mutex);
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* There could be cached undo segment. Check if records
|
|
||||||
in these segments can be purged. Normal purge history
|
|
||||||
will not touch these cached segment. */
|
|
||||||
ulint cached_undo_size = 0;
|
|
||||||
|
|
||||||
for (trx_undo_t* undo =
|
|
||||||
UT_LIST_GET_FIRST(rseg->undo_cached);
|
|
||||||
undo != NULL && all_free;
|
|
||||||
undo = UT_LIST_GET_NEXT(undo_list, undo)) {
|
|
||||||
|
|
||||||
if (limit.trx_no() < undo->trx_id) {
|
|
||||||
all_free = false;
|
|
||||||
} else {
|
|
||||||
cached_undo_size += undo->size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ut_ad(size_of_rsegs >= (cached_undo_size + 1));
|
|
||||||
|
|
||||||
if (size_of_rsegs > (cached_undo_size + 1)) {
|
|
||||||
/* There are pages besides cached pages that
|
|
||||||
still hold active data. */
|
|
||||||
all_free = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_exit(&rseg->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!all_free) {
|
|
||||||
/* rseg still holds active data.*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Step-3: Start the actual truncate.
|
|
||||||
a. Remove rseg instance if added to purge queue before we
|
|
||||||
initiate truncate.
|
|
||||||
b. Execute actual truncate */
|
|
||||||
|
|
||||||
const ulint space_id = undo_trunc->get_marked_space_id();
|
|
||||||
|
|
||||||
ib::info() << "Truncating UNDO tablespace " << space_id;
|
|
||||||
|
|
||||||
trx_purge_cleanse_purge_queue(undo_trunc);
|
|
||||||
|
|
||||||
ut_a(srv_is_undo_tablespace(space_id));
|
|
||||||
|
|
||||||
fil_space_t* space = fil_space_get(space_id);
|
|
||||||
|
|
||||||
if (!space) {
|
|
||||||
not_found:
|
|
||||||
ib::error() << "Failed to find UNDO tablespace " << space_id;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Flush all to-be-discarded pages of the tablespace.
|
|
||||||
|
|
||||||
During truncation, we do not want any writes to the
|
|
||||||
to-be-discarded area, because we must set the space->size
|
|
||||||
early in order to have deterministic page allocation.
|
|
||||||
|
|
||||||
If a log checkpoint was completed at LSN earlier than our
|
|
||||||
mini-transaction commit and the server was killed, then
|
|
||||||
discarding the to-be-trimmed pages without flushing would
|
|
||||||
break crash recovery. So, we cannot avoid the write. */
|
|
||||||
{
|
|
||||||
FlushObserver observer(
|
|
||||||
space,
|
|
||||||
UT_LIST_GET_FIRST(purge_sys.query->thrs)->graph->trx,
|
|
||||||
NULL);
|
|
||||||
buf_LRU_flush_or_remove_pages(space_id, &observer);
|
|
||||||
}
|
|
||||||
|
|
||||||
log_free_check();
|
|
||||||
|
|
||||||
/* Adjust the tablespace metadata. */
|
|
||||||
space = fil_truncate_prepare(space_id);
|
|
||||||
|
|
||||||
if (!space) {
|
|
||||||
goto not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Undo tablespace always are a single file. */
|
|
||||||
ut_a(UT_LIST_GET_LEN(space->chain) == 1);
|
|
||||||
fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
|
|
||||||
/* The undo tablespace files are never closed. */
|
|
||||||
ut_ad(file->is_open());
|
|
||||||
|
|
||||||
/* Re-initialize tablespace, in a single mini-transaction. */
|
|
||||||
mtr_t mtr;
|
|
||||||
const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
|
|
||||||
mtr.start();
|
|
||||||
mtr_x_lock(&space->latch, &mtr);
|
|
||||||
fil_truncate_log(space, size, &mtr);
|
|
||||||
fsp_header_init(space, size, &mtr);
|
|
||||||
mutex_enter(&fil_system.mutex);
|
|
||||||
space->size = file->size = size;
|
|
||||||
mutex_exit(&fil_system.mutex);
|
|
||||||
|
|
||||||
buf_block_t* sys_header = trx_sysf_get(&mtr);
|
|
||||||
|
|
||||||
for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) {
|
|
||||||
trx_rsegf_t* rseg_header;
|
|
||||||
|
|
||||||
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
|
|
||||||
|
|
||||||
rseg->page_no = trx_rseg_header_create(
|
|
||||||
space, rseg->id, sys_header, &mtr);
|
|
||||||
|
|
||||||
rseg_header = trx_rsegf_get_new(
|
|
||||||
space_id, rseg->page_no, &mtr);
|
|
||||||
|
|
||||||
/* Before re-initialization ensure that we free the existing
|
|
||||||
structure. There can't be any active transactions. */
|
|
||||||
ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
|
|
||||||
ut_a(UT_LIST_GET_LEN(rseg->old_insert_list) == 0);
|
|
||||||
|
|
||||||
trx_undo_t* next_undo;
|
|
||||||
|
|
||||||
for (trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
|
|
||||||
undo != NULL;
|
|
||||||
undo = next_undo) {
|
|
||||||
|
|
||||||
next_undo = UT_LIST_GET_NEXT(undo_list, undo);
|
|
||||||
UT_LIST_REMOVE(rseg->undo_cached, undo);
|
|
||||||
MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
|
|
||||||
ut_free(undo);
|
|
||||||
}
|
|
||||||
|
|
||||||
UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
|
|
||||||
UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
|
|
||||||
UT_LIST_INIT(rseg->old_insert_list, &trx_undo_t::undo_list);
|
|
||||||
|
|
||||||
/* These were written by trx_rseg_header_create(). */
|
|
||||||
ut_ad(!mach_read_from_4(rseg_header + TRX_RSEG_FORMAT));
|
|
||||||
ut_ad(!mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE));
|
|
||||||
|
|
||||||
/* Initialize the undo log lists according to the rseg header */
|
|
||||||
rseg->curr_size = 1;
|
|
||||||
rseg->trx_ref_count = 0;
|
|
||||||
rseg->last_page_no = FIL_NULL;
|
|
||||||
rseg->last_offset = 0;
|
|
||||||
rseg->last_commit = 0;
|
|
||||||
rseg->needs_purge = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mtr.commit();
|
|
||||||
/* Write-ahead the redo log record. */
|
|
||||||
log_write_up_to(mtr.commit_lsn(), true);
|
|
||||||
|
|
||||||
/* Trim the file size. */
|
|
||||||
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);
|
|
||||||
ut_ad(space->stop_new_ops);
|
|
||||||
ut_ad(space->is_being_truncated);
|
|
||||||
space->stop_new_ops = false;
|
|
||||||
space->is_being_truncated = false;
|
|
||||||
mutex_exit(&fil_system.mutex);
|
|
||||||
|
|
||||||
if (purge_sys.rseg != NULL
|
|
||||||
&& purge_sys.rseg->last_page_no == FIL_NULL) {
|
|
||||||
/* If purge_sys.rseg is pointing to rseg that was recently
|
|
||||||
truncated then move to next rseg element.
|
|
||||||
Note: Ideally purge_sys.rseg should be NULL because purge
|
|
||||||
should complete processing of all the records but there is
|
|
||||||
purge_batch_size that can force the purge loop to exit before
|
|
||||||
all the records are purged and in this case purge_sys.rseg
|
|
||||||
could point to a valid rseg waiting for next purge cycle. */
|
|
||||||
purge_sys.next_stored = false;
|
|
||||||
purge_sys.rseg = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_EXECUTE_IF("ib_undo_trunc",
|
|
||||||
ib::info() << "ib_undo_trunc";
|
|
||||||
log_write_up_to(LSN_MAX, true);
|
|
||||||
DBUG_SUICIDE(););
|
|
||||||
|
|
||||||
/* Completed truncate. Now it is safe to re-use the tablespace. */
|
|
||||||
for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) {
|
|
||||||
trx_rseg_t* rseg = undo_trunc->get_ith_rseg(i);
|
|
||||||
rseg->skip_allocation = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ib::info() << "Truncated UNDO tablespace " << space_id;
|
|
||||||
|
|
||||||
undo_trunc->reset();
|
|
||||||
undo::Truncate::clear_trunc_list();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Removes unnecessary history data from rollback segments. NOTE that when this
|
Removes unnecessary history data from rollback segments. NOTE that when this
|
||||||
function is called, the caller must not have any latches on undo log pages!
|
function is called, the caller must not have any latches on undo log pages!
|
||||||
@@ -1104,12 +575,258 @@ static void trx_purge_truncate_history()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* UNDO tablespace truncate. We will try to truncate as much as we
|
if (srv_undo_tablespaces_active < 2) {
|
||||||
can (greedy approach). This will ensure when the server is idle we
|
return;
|
||||||
try and truncate all the UNDO tablespaces. */
|
}
|
||||||
for (ulint i = srv_undo_tablespaces_active; i--; ) {
|
|
||||||
trx_purge_mark_undo_for_truncate(&purge_sys.undo_trunc);
|
while (srv_undo_log_truncate && srv_undo_logs >= 3) {
|
||||||
trx_purge_initiate_truncate(head, &purge_sys.undo_trunc);
|
if (!purge_sys.truncate.current) {
|
||||||
|
const ulint threshold = ulint(srv_max_undo_log_size
|
||||||
|
>> srv_page_size_shift);
|
||||||
|
for (ulint i = purge_sys.truncate.last
|
||||||
|
? purge_sys.truncate.last->id
|
||||||
|
- srv_undo_space_id_start
|
||||||
|
: 0, j = i;; ) {
|
||||||
|
ulint space_id = srv_undo_space_id_start + i;
|
||||||
|
ut_ad(srv_is_undo_tablespace(space_id));
|
||||||
|
|
||||||
|
if (fil_space_get_size(space_id)
|
||||||
|
> threshold) {
|
||||||
|
purge_sys.truncate.current
|
||||||
|
= fil_space_get(space_id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
i %= srv_undo_tablespaces_active;
|
||||||
|
if (i == j) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!purge_sys.truncate.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fil_space_t& space = *purge_sys.truncate.current;
|
||||||
|
/* Undo tablespace always are a single file. */
|
||||||
|
ut_a(UT_LIST_GET_LEN(space.chain) == 1);
|
||||||
|
fil_node_t* file = UT_LIST_GET_FIRST(space.chain);
|
||||||
|
/* The undo tablespace files are never closed. */
|
||||||
|
ut_ad(file->is_open());
|
||||||
|
|
||||||
|
DBUG_LOG("undo", "marking for truncate: " << file->name);
|
||||||
|
|
||||||
|
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
||||||
|
if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) {
|
||||||
|
ut_ad(rseg->is_persistent());
|
||||||
|
if (rseg->space == &space) {
|
||||||
|
/* Once set, this rseg will
|
||||||
|
not be allocated to subsequent
|
||||||
|
transactions, but we will wait
|
||||||
|
for existing active
|
||||||
|
transactions to finish. */
|
||||||
|
rseg->skip_allocation = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
||||||
|
trx_rseg_t* rseg = trx_sys.rseg_array[i];
|
||||||
|
if (!rseg || rseg->space != &space) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
mutex_enter(&rseg->mutex);
|
||||||
|
ut_ad(rseg->skip_allocation);
|
||||||
|
if (rseg->trx_ref_count) {
|
||||||
|
not_free:
|
||||||
|
mutex_exit(&rseg->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rseg->curr_size != 1) {
|
||||||
|
/* Check if all segments are
|
||||||
|
cached and safe to remove. */
|
||||||
|
ulint cached = 0;
|
||||||
|
|
||||||
|
for (trx_undo_t* undo = UT_LIST_GET_FIRST(
|
||||||
|
rseg->undo_cached);
|
||||||
|
undo;
|
||||||
|
undo = UT_LIST_GET_NEXT(undo_list,
|
||||||
|
undo)) {
|
||||||
|
if (head.trx_no() < undo->trx_id) {
|
||||||
|
goto not_free;
|
||||||
|
} else {
|
||||||
|
cached += undo->size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(rseg->curr_size > cached);
|
||||||
|
|
||||||
|
if (rseg->curr_size > cached + 1) {
|
||||||
|
goto not_free;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_exit(&rseg->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
ib::info() << "Truncating " << file->name;
|
||||||
|
trx_purge_cleanse_purge_queue(space);
|
||||||
|
|
||||||
|
/* Flush all to-be-discarded pages of the tablespace.
|
||||||
|
|
||||||
|
During truncation, we do not want any writes to the
|
||||||
|
to-be-discarded area, because we must set the space.size
|
||||||
|
early in order to have deterministic page allocation.
|
||||||
|
|
||||||
|
If a log checkpoint was completed at LSN earlier than our
|
||||||
|
mini-transaction commit and the server was killed, then
|
||||||
|
discarding the to-be-trimmed pages without flushing would
|
||||||
|
break crash recovery. So, we cannot avoid the write. */
|
||||||
|
{
|
||||||
|
FlushObserver observer(
|
||||||
|
purge_sys.truncate.current,
|
||||||
|
UT_LIST_GET_FIRST(purge_sys.query->thrs)
|
||||||
|
->graph->trx,
|
||||||
|
NULL);
|
||||||
|
buf_LRU_flush_or_remove_pages(space.id, &observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_free_check();
|
||||||
|
|
||||||
|
/* Adjust the tablespace metadata. */
|
||||||
|
if (!fil_truncate_prepare(space.id)) {
|
||||||
|
ib::error() << "Failed to find UNDO tablespace "
|
||||||
|
<< file->name;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Re-initialize tablespace, in a single mini-transaction. */
|
||||||
|
mtr_t mtr;
|
||||||
|
const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
|
||||||
|
mtr.start();
|
||||||
|
mtr_x_lock(&purge_sys.truncate.current->latch, &mtr);
|
||||||
|
fil_truncate_log(purge_sys.truncate.current, size, &mtr);
|
||||||
|
fsp_header_init(purge_sys.truncate.current, size, &mtr);
|
||||||
|
mutex_enter(&fil_system.mutex);
|
||||||
|
purge_sys.truncate.current->size = file->size = size;
|
||||||
|
mutex_exit(&fil_system.mutex);
|
||||||
|
|
||||||
|
buf_block_t* sys_header = trx_sysf_get(&mtr);
|
||||||
|
|
||||||
|
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
||||||
|
trx_rseg_t* rseg = trx_sys.rseg_array[i];
|
||||||
|
if (!rseg || rseg->space != &space) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ut_ad(rseg->is_persistent());
|
||||||
|
ut_d(const ulint old_page = rseg->page_no);
|
||||||
|
|
||||||
|
rseg->page_no = trx_rseg_header_create(
|
||||||
|
purge_sys.truncate.current,
|
||||||
|
rseg->id, sys_header, &mtr);
|
||||||
|
ut_ad(old_page == rseg->page_no);
|
||||||
|
|
||||||
|
trx_rsegf_t* rseg_header = trx_rsegf_get_new(
|
||||||
|
space.id, rseg->page_no, &mtr);
|
||||||
|
|
||||||
|
/* Before re-initialization ensure that we
|
||||||
|
free the existing structure. There can't be
|
||||||
|
any active transactions. */
|
||||||
|
ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
|
||||||
|
ut_a(UT_LIST_GET_LEN(rseg->old_insert_list) == 0);
|
||||||
|
|
||||||
|
trx_undo_t* next_undo;
|
||||||
|
|
||||||
|
for (trx_undo_t* undo = UT_LIST_GET_FIRST(
|
||||||
|
rseg->undo_cached);
|
||||||
|
undo; undo = next_undo) {
|
||||||
|
|
||||||
|
next_undo = UT_LIST_GET_NEXT(undo_list, undo);
|
||||||
|
UT_LIST_REMOVE(rseg->undo_cached, undo);
|
||||||
|
MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
|
||||||
|
ut_free(undo);
|
||||||
|
}
|
||||||
|
|
||||||
|
UT_LIST_INIT(rseg->undo_list,
|
||||||
|
&trx_undo_t::undo_list);
|
||||||
|
UT_LIST_INIT(rseg->undo_cached,
|
||||||
|
&trx_undo_t::undo_list);
|
||||||
|
UT_LIST_INIT(rseg->old_insert_list,
|
||||||
|
&trx_undo_t::undo_list);
|
||||||
|
|
||||||
|
/* These were written by trx_rseg_header_create(). */
|
||||||
|
ut_ad(!mach_read_from_4(rseg_header
|
||||||
|
+ TRX_RSEG_FORMAT));
|
||||||
|
ut_ad(!mach_read_from_4(rseg_header
|
||||||
|
+ TRX_RSEG_HISTORY_SIZE));
|
||||||
|
|
||||||
|
/* Initialize the undo log lists according to
|
||||||
|
the rseg header */
|
||||||
|
rseg->curr_size = 1;
|
||||||
|
rseg->trx_ref_count = 0;
|
||||||
|
rseg->last_page_no = FIL_NULL;
|
||||||
|
rseg->last_offset = 0;
|
||||||
|
rseg->last_commit = 0;
|
||||||
|
rseg->needs_purge = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtr.commit();
|
||||||
|
/* Write-ahead the redo log record. */
|
||||||
|
log_write_up_to(mtr.commit_lsn(), true);
|
||||||
|
|
||||||
|
/* Trim the file size. */
|
||||||
|
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);
|
||||||
|
ut_ad(&space == purge_sys.truncate.current);
|
||||||
|
ut_ad(space.stop_new_ops);
|
||||||
|
ut_ad(space.is_being_truncated);
|
||||||
|
purge_sys.truncate.current->stop_new_ops = false;
|
||||||
|
purge_sys.truncate.current->is_being_truncated = false;
|
||||||
|
mutex_exit(&fil_system.mutex);
|
||||||
|
|
||||||
|
if (purge_sys.rseg != NULL
|
||||||
|
&& purge_sys.rseg->last_page_no == FIL_NULL) {
|
||||||
|
/* If purge_sys.rseg is pointing to rseg that
|
||||||
|
was recently truncated then move to next rseg
|
||||||
|
element. Note: Ideally purge_sys.rseg should
|
||||||
|
be NULL because purge should complete
|
||||||
|
processing of all the records but there is
|
||||||
|
purge_batch_size that can force the purge loop
|
||||||
|
to exit before all the records are purged and
|
||||||
|
in this case purge_sys.rseg could point to a
|
||||||
|
valid rseg waiting for next purge cycle. */
|
||||||
|
purge_sys.next_stored = false;
|
||||||
|
purge_sys.rseg = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_EXECUTE_IF("ib_undo_trunc",
|
||||||
|
ib::info() << "ib_undo_trunc";
|
||||||
|
log_write_up_to(LSN_MAX, true);
|
||||||
|
DBUG_SUICIDE(););
|
||||||
|
|
||||||
|
for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
|
||||||
|
if (trx_rseg_t* rseg = trx_sys.rseg_array[i]) {
|
||||||
|
ut_ad(rseg->is_persistent());
|
||||||
|
if (rseg->space == &space) {
|
||||||
|
rseg->skip_allocation = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ib::info() << "Truncated " << file->name;
|
||||||
|
purge_sys.truncate.last = purge_sys.truncate.current;
|
||||||
|
purge_sys.truncate.current = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -150,7 +150,6 @@ ut_new_boot()
|
|||||||
"row0merge",
|
"row0merge",
|
||||||
"row0mysql",
|
"row0mysql",
|
||||||
"row0sel",
|
"row0sel",
|
||||||
"row0trunc",
|
|
||||||
"srv0conc",
|
"srv0conc",
|
||||||
"srv0srv",
|
"srv0srv",
|
||||||
"srv0start",
|
"srv0start",
|
||||||
|
@@ -589,8 +589,6 @@ ut_strerr(
|
|||||||
return("Tablespace already exists");
|
return("Tablespace already exists");
|
||||||
case DB_TABLESPACE_DELETED:
|
case DB_TABLESPACE_DELETED:
|
||||||
return("Tablespace deleted or being deleted");
|
return("Tablespace deleted or being deleted");
|
||||||
case DB_TABLESPACE_TRUNCATED:
|
|
||||||
return("Tablespace was truncated");
|
|
||||||
case DB_TABLESPACE_NOT_FOUND:
|
case DB_TABLESPACE_NOT_FOUND:
|
||||||
return("Tablespace not found");
|
return("Tablespace not found");
|
||||||
case DB_LOCK_TABLE_FULL:
|
case DB_LOCK_TABLE_FULL:
|
||||||
|
Reference in New Issue
Block a user