mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01: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:
parent
67fa97dc2c
commit
09af00cbde
40 changed files with 397 additions and 3829 deletions
|
@ -628,15 +628,6 @@ static void backup_optimized_ddl_op(ulint space_id)
|
|||
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 ======== */
|
||||
|
||||
typedef struct {
|
||||
|
@ -4179,7 +4170,6 @@ fail_before_log_copying_thread_start:
|
|||
log_copy_scanned_lsn = checkpoint_lsn_start;
|
||||
recv_sys->recovered_lsn = log_copy_scanned_lsn;
|
||||
log_optimized_ddl_op = backup_optimized_ddl_op;
|
||||
log_truncate = backup_truncate_fail;
|
||||
|
||||
if (xtrabackup_copy_logfile())
|
||||
goto fail_before_log_copying_thread_start;
|
||||
|
|
|
@ -125,13 +125,13 @@ WHERE engine = 'innodb'
|
|||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||
COUNT(*)
|
||||
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
|
||||
SELECT COUNT(*) `1` FROM INFORMATION_SCHEMA.ENGINES WHERE engine='innodb'
|
||||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||
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_logfile0
|
||||
ib_logfile1
|
||||
|
|
|
@ -125,7 +125,7 @@ WHERE engine = 'innodb'
|
|||
AND support IN ('YES', 'DEFAULT', 'ENABLED');
|
||||
COUNT(*)
|
||||
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
|
||||
SELECT * FROM INFORMATION_SCHEMA.ENGINES
|
||||
WHERE engine = 'innodb'
|
||||
|
|
|
@ -113,7 +113,6 @@ SET(INNOBASE_SOURCES
|
|||
row/row0purge.cc
|
||||
row/row0row.cc
|
||||
row/row0sel.cc
|
||||
row/row0trunc.cc
|
||||
row/row0uins.cc
|
||||
row/row0umod.cc
|
||||
row/row0undo.cc
|
||||
|
@ -179,7 +178,6 @@ IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
|||
mtr/mtr0mtr.cc
|
||||
row/row0merge.cc
|
||||
row/row0mysql.cc
|
||||
row/row0trunc.cc
|
||||
srv/srv0srv.cc
|
||||
COMPILE_FLAGS "-O0"
|
||||
)
|
||||
|
|
|
@ -438,7 +438,7 @@ btr_page_create(
|
|||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
if (page_zip) {
|
||||
page_create_zip(block, index, level, 0, NULL, mtr);
|
||||
page_create_zip(block, index, level, 0, mtr);
|
||||
} else {
|
||||
page_create(block, mtr, dict_table_is_comp(index->table),
|
||||
dict_index_is_spatial(index));
|
||||
|
@ -1179,21 +1179,18 @@ btr_free_root_check(
|
|||
|
||||
/** Create the root node for a new index tree.
|
||||
@param[in] type type of the index
|
||||
@param[in,out] space tablespace where created
|
||||
@param[in] index_id index id
|
||||
@param[in] index index, or NULL when applying TRUNCATE
|
||||
log record during recovery
|
||||
@param[in] btr_redo_create_info used for applying TRUNCATE log
|
||||
@param[in] mtr mini-transaction handle
|
||||
record during recovery
|
||||
@return page number of the created root, FIL_NULL if did not succeed */
|
||||
@param[in,out] space tablespace where created
|
||||
@param[in] index index
|
||||
@param[in,out] mtr mini-transaction
|
||||
@return page number of the created root
|
||||
@retval FIL_NULL if did not succeed */
|
||||
ulint
|
||||
btr_create(
|
||||
ulint type,
|
||||
fil_space_t* space,
|
||||
index_id_t index_id,
|
||||
dict_index_t* index,
|
||||
const btr_create_t* btr_redo_create_info,
|
||||
mtr_t* mtr)
|
||||
{
|
||||
buf_block_t* block;
|
||||
|
@ -1208,7 +1205,7 @@ btr_create(
|
|||
(for an ibuf tree, not in the root, but on a separate ibuf header
|
||||
page) */
|
||||
|
||||
if (type & DICT_IBUF) {
|
||||
if (UNIV_UNLIKELY(type & DICT_IBUF)) {
|
||||
/* Allocate first the ibuf header page */
|
||||
buf_block_t* ibuf_hdr_block = fseg_create(
|
||||
space, 0,
|
||||
|
@ -1273,44 +1270,11 @@ btr_create(
|
|||
page_zip = buf_block_get_page_zip(block);
|
||||
|
||||
if (page_zip) {
|
||||
if (index != NULL) {
|
||||
page = page_create_zip(block, index, 0, 0, NULL, mtr);
|
||||
} 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);
|
||||
}
|
||||
page = page_create_zip(block, index, 0, 0, mtr);
|
||||
} else {
|
||||
if (index != NULL) {
|
||||
page = page_create(block, mtr,
|
||||
dict_table_is_comp(index->table),
|
||||
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);
|
||||
}
|
||||
page = page_create(block, mtr,
|
||||
dict_table_is_comp(index->table),
|
||||
dict_index_is_spatial(index));
|
||||
/* Set the level of the new index page */
|
||||
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_prev(page, page_zip, FIL_NULL, mtr);
|
||||
|
||||
/* We reset the free bits for the page to allow creation of several
|
||||
trees in the 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.
|
||||
/* We reset the free bits for the page in a separate
|
||||
mini-transaction to allow creation of several trees in the
|
||||
same mtr, otherwise the latch on a bitmap page would prevent
|
||||
it because of the latching order.
|
||||
|
||||
Note: Insert Buffering is disabled for temporary tables given that
|
||||
most temporary tables are smaller in size and short-lived. */
|
||||
if (!(type & DICT_CLUSTERED)
|
||||
&& (index == NULL || !index->table->is_temporary())) {
|
||||
|
||||
if (!(type & DICT_CLUSTERED) && !index->table->is_temporary()) {
|
||||
ibuf_reset_free_bits(block);
|
||||
}
|
||||
|
||||
|
@ -1675,7 +1635,7 @@ btr_page_reorganize_low(
|
|||
}
|
||||
|
||||
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. */
|
||||
#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
|
||||
|
@ -1924,7 +1884,7 @@ btr_page_empty(
|
|||
: 0;
|
||||
|
||||
if (page_zip) {
|
||||
page_create_zip(block, index, level, autoinc, NULL, mtr);
|
||||
page_create_zip(block, index, level, autoinc, mtr);
|
||||
} else {
|
||||
page_create(block, mtr, dict_table_is_comp(index->table),
|
||||
dict_index_is_spatial(index));
|
||||
|
|
|
@ -94,7 +94,7 @@ PageBulk::init()
|
|||
|
||||
if (new_page_zip) {
|
||||
page_create_zip(new_block, m_index, m_level, 0,
|
||||
NULL, &m_mtr);
|
||||
&m_mtr);
|
||||
memset(FIL_PAGE_PREV + new_page, 0xff, 8);
|
||||
page_zip_write_header(new_page_zip,
|
||||
FIL_PAGE_PREV + new_page,
|
||||
|
@ -374,7 +374,7 @@ PageBulk::compress()
|
|||
ut_ad(m_page_zip != NULL);
|
||||
|
||||
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
|
||||
|
|
|
@ -6248,7 +6248,6 @@ database_corrupted:
|
|||
&& !recv_no_ibuf_operations
|
||||
&& (bpage->id.space() == 0
|
||||
|| !is_predefined_tablespace(bpage->id.space()))
|
||||
&& !srv_is_tablespace_truncated(bpage->id.space())
|
||||
&& fil_page_get_type(frame) == FIL_PAGE_INDEX
|
||||
&& page_is_leaf(frame)) {
|
||||
|
||||
|
|
|
@ -556,12 +556,9 @@ buf_dblwr_process()
|
|||
|
||||
if (page_no >= space->size) {
|
||||
|
||||
/* Do not report the warning if the tablespace
|
||||
is scheduled for truncation or was truncated
|
||||
and we have parsed an MLOG_TRUNCATE record. */
|
||||
if (!srv_is_tablespace_truncated(space_id)
|
||||
&& !srv_was_tablespace_truncated(space)
|
||||
&& !srv_is_undo_tablespace(space_id)) {
|
||||
/* Do not report the warning for undo
|
||||
tablespaces, because they can be truncated in place. */
|
||||
if (!srv_is_undo_tablespace(space_id)) {
|
||||
ib::warn() << "A copy of page " << page_id
|
||||
<< " in the doublewrite buffer slot "
|
||||
<< 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
|
||||
flag is cleared and the x-lock released by an i/o-handler thread.
|
||||
|
||||
@param[out] err DB_SUCCESS, DB_TABLESPACE_DELETED or
|
||||
DB_TABLESPACE_TRUNCATED if we are trying
|
||||
to read from a non-existent tablespace, a
|
||||
tablespace which is just now being dropped,
|
||||
or a tablespace which is truncated
|
||||
@param[out] err DB_SUCCESS or DB_TABLESPACE_DELETED
|
||||
if we are trying
|
||||
to read from a non-existent tablespace
|
||||
@param[in] sync true if synchronous aio is desired
|
||||
@param[in] type IO type, SIMULATED, IGNORE_MISSING
|
||||
@param[in] mode BUF_READ_IBUF_PAGES_ONLY, ...,
|
||||
|
@ -187,20 +185,8 @@ buf_read_page_low(
|
|||
}
|
||||
|
||||
if (*err != DB_SUCCESS) {
|
||||
if (*err == DB_TABLESPACE_TRUNCATED) {
|
||||
/* 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) {
|
||||
if (IORequest::ignore_missing(type)
|
||||
|| *err == DB_TABLESPACE_DELETED) {
|
||||
buf_read_page_handle_error(bpage);
|
||||
return(0);
|
||||
}
|
||||
|
@ -369,7 +355,6 @@ read_ahead:
|
|||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
case DB_TABLESPACE_TRUNCATED:
|
||||
case DB_ERROR:
|
||||
break;
|
||||
case DB_TABLESPACE_DELETED:
|
||||
|
@ -472,7 +457,6 @@ buf_read_page_background(
|
|||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
case DB_TABLESPACE_TRUNCATED:
|
||||
case DB_ERROR:
|
||||
break;
|
||||
case DB_TABLESPACE_DELETED:
|
||||
|
@ -755,7 +739,6 @@ buf_read_ahead_linear(
|
|||
|
||||
switch (err) {
|
||||
case DB_SUCCESS:
|
||||
case DB_TABLESPACE_TRUNCATED:
|
||||
case DB_TABLESPACE_DELETED:
|
||||
case DB_ERROR:
|
||||
break;
|
||||
|
@ -853,7 +836,6 @@ tablespace_deleted:
|
|||
|
||||
switch(err) {
|
||||
case DB_SUCCESS:
|
||||
case DB_TABLESPACE_TRUNCATED:
|
||||
case DB_ERROR:
|
||||
break;
|
||||
case DB_TABLESPACE_DELETED:
|
||||
|
|
|
@ -214,7 +214,7 @@ dict_hdr_create(
|
|||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
fil_system.sys_space, DICT_TABLES_ID,
|
||||
dict_ind_redundant, NULL, mtr);
|
||||
dict_ind_redundant, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
|
@ -225,7 +225,7 @@ dict_hdr_create(
|
|||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_UNIQUE,
|
||||
fil_system.sys_space, DICT_TABLE_IDS_ID,
|
||||
dict_ind_redundant, NULL, mtr);
|
||||
dict_ind_redundant, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
|
@ -236,7 +236,7 @@ dict_hdr_create(
|
|||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
fil_system.sys_space, DICT_COLUMNS_ID,
|
||||
dict_ind_redundant, NULL, mtr);
|
||||
dict_ind_redundant, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
|
@ -247,7 +247,7 @@ dict_hdr_create(
|
|||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
fil_system.sys_space, DICT_INDEXES_ID,
|
||||
dict_ind_redundant, NULL, mtr);
|
||||
dict_ind_redundant, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
|
@ -258,7 +258,7 @@ dict_hdr_create(
|
|||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
fil_system.sys_space, DICT_FIELDS_ID,
|
||||
dict_ind_redundant, NULL, mtr);
|
||||
dict_ind_redundant, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
|
|
|
@ -863,7 +863,7 @@ dict_create_index_tree_step(
|
|||
|
||||
node->page_no = btr_create(
|
||||
index->type, index->table->space,
|
||||
index->id, index, NULL, &mtr);
|
||||
index->id, index, &mtr);
|
||||
|
||||
if (node->page_no == FIL_NULL) {
|
||||
err = DB_OUT_OF_FILE_SPACE;
|
||||
|
@ -909,7 +909,7 @@ dict_create_index_tree_in_mem(
|
|||
ut_ad(!(index->table->flags2 & DICT_TF2_DISCARDED));
|
||||
|
||||
index->page = btr_create(index->type, index->table->space,
|
||||
index->id, index, NULL, &mtr);
|
||||
index->id, index, &mtr);
|
||||
mtr_commit(&mtr);
|
||||
|
||||
index->trx_id = trx->id;
|
||||
|
@ -975,13 +975,6 @@ dict_drop_index_tree(
|
|||
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,
|
||||
mach_read_from_8(ptr), mtr);
|
||||
|
||||
|
@ -1057,7 +1050,7 @@ dict_recreate_index_tree(
|
|||
ulint root_page_no = (index->type & DICT_FTS)
|
||||
? FIL_NULL
|
||||
: btr_create(type, table->space,
|
||||
index_id, index, NULL, mtr);
|
||||
index_id, index, mtr);
|
||||
index->page = unsigned(root_page_no);
|
||||
return root_page_no;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@ Created 10/25/1995 Heikki Tuuri
|
|||
#include "os0file.h"
|
||||
#include "page0zip.h"
|
||||
#include "row0mysql.h"
|
||||
#include "row0trunc.h"
|
||||
#include "srv0start.h"
|
||||
#include "trx0purge.h"
|
||||
#include "ut0new.h"
|
||||
|
@ -553,8 +552,7 @@ fil_node_open_file(
|
|||
if (first_time_open
|
||||
|| (space->purpose == FIL_TYPE_TABLESPACE
|
||||
&& node == UT_LIST_GET_FIRST(space->chain)
|
||||
&& srv_startup_is_before_trx_rollback_phase
|
||||
&& !undo::Truncate::was_tablespace_truncated(space->id))) {
|
||||
&& srv_startup_is_before_trx_rollback_phase)) {
|
||||
/* We do not know the size of the file yet. First we
|
||||
open the file in the normal mode, no async I/O here,
|
||||
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
|
||||
used, else ignored
|
||||
@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 */
|
||||
dberr_t
|
||||
fil_io(
|
||||
|
@ -4373,19 +4371,6 @@ fil_io(
|
|||
break;
|
||||
|
||||
} 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;
|
||||
|
||||
node = UT_LIST_GET_NEXT(chain, node);
|
||||
|
@ -5126,116 +5111,6 @@ fil_names_clear(
|
|||
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 */
|
||||
#ifdef UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH
|
||||
#define MF fil_make_filepath
|
||||
|
|
|
@ -624,8 +624,7 @@ fsp_space_modify_check(
|
|||
case MTR_LOG_NO_REDO:
|
||||
ut_ad(space->purpose == FIL_TYPE_TEMPORARY
|
||||
|| space->purpose == FIL_TYPE_IMPORT
|
||||
|| my_atomic_loadlint(&space->redo_skipped_count)
|
||||
|| srv_is_tablespace_truncated(space->id));
|
||||
|| my_atomic_loadlint(&space->redo_skipped_count));
|
||||
return;
|
||||
case MTR_LOG_ALL:
|
||||
/* We may only write redo log for a persistent tablespace. */
|
||||
|
@ -1065,13 +1064,6 @@ fsp_fill_free_list(
|
|||
mtr_start(&ibuf_mtr);
|
||||
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(
|
||||
space->id,
|
||||
i + FSP_IBUF_BITMAP_OFFSET);
|
||||
|
|
|
@ -914,7 +914,7 @@ rtr_split_page_move_rec_list(
|
|||
mtr_set_log_mode(mtr, log_mode);
|
||||
|
||||
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||
page_zip_level, NULL, mtr)) {
|
||||
page_zip_level, mtr)) {
|
||||
ulint ret_pos;
|
||||
|
||||
/* 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 "row0quiesce.h"
|
||||
#include "row0sel.h"
|
||||
#include "row0trunc.h"
|
||||
#include "row0upd.h"
|
||||
#include "fil0crypt.h"
|
||||
#include "ut0timer.h"
|
||||
|
|
|
@ -916,10 +916,7 @@ ibuf_set_free_bits_func(
|
|||
ut_ad(0);
|
||||
break;
|
||||
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 */
|
||||
case FIL_TYPE_TEMPORARY:
|
||||
case FIL_TYPE_IMPORT:
|
||||
|
|
|
@ -361,19 +361,16 @@ btr_node_ptr_get_child_page_no(
|
|||
@param[in] type type of the index
|
||||
@param[in,out] space tablespace where created
|
||||
@param[in] index_id index id
|
||||
@param[in] index index, or NULL when applying TRUNCATE
|
||||
log record during recovery
|
||||
@param[in] btr_redo_create_info used for applying TRUNCATE log
|
||||
@param[in] mtr mini-transaction handle
|
||||
record during recovery
|
||||
@return page number of the created root, FIL_NULL if did not succeed */
|
||||
@param[in] index index
|
||||
@param[in,out] mtr mini-transaction
|
||||
@return page number of the created root
|
||||
@retval FIL_NULL if did not succeed */
|
||||
ulint
|
||||
btr_create(
|
||||
ulint type,
|
||||
fil_space_t* space,
|
||||
index_id_t index_id,
|
||||
dict_index_t* index,
|
||||
const btr_create_t* btr_redo_create_info,
|
||||
mtr_t* mtr);
|
||||
|
||||
/** 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) 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
|
||||
|
@ -58,35 +59,4 @@ in the index record. */
|
|||
#define BTR_EXTERN_LOCAL_STORED_MAX_SIZE \
|
||||
(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
|
||||
|
|
|
@ -135,8 +135,6 @@ enum dberr_t {
|
|||
DB_FTS_TOO_MANY_WORDS_IN_PHRASE,
|
||||
/*< Too many words in a phrase */
|
||||
|
||||
DB_TABLESPACE_TRUNCATED, /*!< tablespace was truncated */
|
||||
|
||||
DB_DECRYPTION_FAILED, /* Tablespace encrypted and
|
||||
decrypt operation failed because
|
||||
of missing key management plugin,
|
||||
|
|
|
@ -40,7 +40,6 @@ extern my_bool srv_use_doublewrite_buf;
|
|||
extern struct buf_dblwr_t* buf_dblwr;
|
||||
struct trx_t;
|
||||
class page_id_t;
|
||||
class truncate_t;
|
||||
|
||||
/** Structure containing encryption specification */
|
||||
struct fil_space_crypt_t;
|
||||
|
@ -1086,7 +1085,7 @@ fil_space_extend(
|
|||
@param[in] message message for aio handler if non-sync aio
|
||||
used, else ignored
|
||||
@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 */
|
||||
dberr_t
|
||||
fil_io(
|
||||
|
|
|
@ -145,10 +145,6 @@ corresponding to MLOG_INDEX_LOAD.
|
|||
*/
|
||||
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.
|
||||
@param[in] space_id tablespace identifier
|
||||
@param[in] flags tablespace flags (NULL if not create)
|
||||
|
|
|
@ -216,7 +216,8 @@ enum mlog_id_t {
|
|||
/** initialize a file page */
|
||||
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,
|
||||
|
||||
/** 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
|
||||
the page */
|
||||
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
|
||||
handle */
|
||||
/**********************************************************//**
|
||||
|
|
|
@ -85,18 +85,6 @@ enum page_cur_mode_t {
|
|||
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 */
|
||||
struct page_zip_des_t
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
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
|
||||
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
|
||||
node */
|
||||
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,
|
||||
or NULL */
|
||||
|
||||
|
|
|
@ -414,7 +414,7 @@ page_zip_parse_compress_no_data(
|
|||
was successful. Crash in this case. */
|
||||
|
||||
if (page
|
||||
&& !page_zip_compress(page_zip, page, index, level, NULL, NULL)) {
|
||||
&& !page_zip_compress(page_zip, page, index, level, NULL)) {
|
||||
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. */
|
||||
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
|
||||
/** Disables master thread. It's used by:
|
||||
SET GLOBAL innodb_master_thread_disabled_debug = 1 (0).
|
||||
|
|
|
@ -133,202 +133,6 @@ private:
|
|||
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 */
|
||||
class purge_sys_t
|
||||
{
|
||||
|
@ -410,9 +214,14 @@ public:
|
|||
by the pq_mutex */
|
||||
PQMutex pq_mutex; /*!< Mutex protecting purge_queue */
|
||||
|
||||
undo::Truncate undo_trunc; /*!< Track UNDO tablespace marked
|
||||
for truncate. */
|
||||
|
||||
/** Undo tablespace file truncation (only accessed by the
|
||||
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.
|
||||
|
|
|
@ -54,7 +54,6 @@ Created 9/20/1997 Heikki Tuuri
|
|||
#include "fil0fil.h"
|
||||
#include "fsp0sysspace.h"
|
||||
#include "ut0new.h"
|
||||
#include "row0trunc.h"
|
||||
#include "buf0rea.h"
|
||||
#include "srv0srv.h"
|
||||
#include "srv0start.h"
|
||||
|
@ -203,10 +202,6 @@ corresponding to MLOG_INDEX_LOAD.
|
|||
*/
|
||||
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.
|
||||
@param[in] space_id tablespace identifier
|
||||
@param[in] flags tablespace flags (NULL if not create)
|
||||
|
@ -1205,14 +1200,10 @@ recv_parse_or_apply_log_rec_body(
|
|||
}
|
||||
return(ptr + 8);
|
||||
case MLOG_TRUNCATE:
|
||||
if (log_truncate) {
|
||||
ut_ad(srv_operation != SRV_OPERATION_NORMAL);
|
||||
log_truncate();
|
||||
recv_sys->found_corrupt_fs = true;
|
||||
return NULL;
|
||||
}
|
||||
return(truncate_t::parse_redo_entry(ptr, end_ptr, space_id));
|
||||
|
||||
ib::error() << "Cannot crash-upgrade from "
|
||||
"old-style TRUNCATE TABLE";
|
||||
recv_sys->found_corrupt_log = true;
|
||||
return NULL;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1795,13 +1786,10 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||
page_t* page;
|
||||
page_zip_des_t* page_zip;
|
||||
recv_addr_t* recv_addr;
|
||||
recv_t* recv;
|
||||
byte* buf;
|
||||
lsn_t start_lsn;
|
||||
lsn_t end_lsn;
|
||||
lsn_t page_lsn;
|
||||
lsn_t page_newest_lsn;
|
||||
ibool modification_to_page;
|
||||
mtr_t mtr;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
modification_to_page = FALSE;
|
||||
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());
|
||||
|
||||
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;
|
||||
|
||||
ut_ad(end_lsn <= log_sys.log.scanned_lsn);
|
||||
|
||||
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 = ((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;
|
||||
ut_ad(recv->start_lsn);
|
||||
if (recv->start_lsn >= page_lsn) {
|
||||
if (!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
|
||||
<< " 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->type, buf, buf + recv->len,
|
||||
block->page.id.space(),
|
||||
block->page.id.page_no(),
|
||||
true, block, &mtr);
|
||||
block->page.id.page_no(), 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(srv_page_size
|
||||
- FIL_PAGE_END_LSN_OLD_CHKSUM
|
||||
+ page, end_lsn);
|
||||
|
||||
if (page_zip) {
|
||||
mach_write_to_8(FIL_PAGE_LSN
|
||||
+ page_zip->data, end_lsn);
|
||||
mach_write_to_8(FIL_PAGE_LSN + page_zip->data,
|
||||
end_lsn);
|
||||
}
|
||||
|
||||
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
||||
ut_free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
if (recv->len > RECV_DATA_BLOCK_SIZE) {
|
||||
ut_free(buf);
|
||||
}
|
||||
|
||||
recv = UT_LIST_GET_NEXT(rec_list, recv);
|
||||
}
|
||||
|
||||
space->release();
|
||||
|
@ -1978,9 +1940,7 @@ recv_recover_page(bool just_read_in, buf_block_t* block)
|
|||
}
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
|
||||
if (modification_to_page) {
|
||||
ut_a(block);
|
||||
|
||||
if (start_lsn) {
|
||||
log_flush_order_mutex_enter();
|
||||
buf_flush_recv_note_modification(block, start_lsn, end_lsn);
|
||||
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);
|
||||
|
||||
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
|
||||
? "Starting final 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*>(
|
||||
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) {
|
||||
ut_a(recv_sys->n_addrs);
|
||||
recv_sys->n_addrs--;
|
||||
|
|
|
@ -32,7 +32,6 @@ Created 11/26/1995 Heikki Tuuri
|
|||
#include "page0types.h"
|
||||
#include "mtr0log.h"
|
||||
#include "log0log.h"
|
||||
#include "row0trunc.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
|
||||
|| space->purpose == FIL_TYPE_TEMPORARY
|
||||
|| space->purpose == FIL_TYPE_IMPORT
|
||||
|| my_atomic_loadlint(&space->redo_skipped_count) > 0
|
||||
|| srv_is_tablespace_truncated(space->id));
|
||||
|| my_atomic_loadlint(&space->redo_skipped_count) > 0);
|
||||
}
|
||||
|
||||
ut_ad(space);
|
||||
|
|
|
@ -1566,7 +1566,7 @@ page_cur_insert_rec_zip(
|
|||
get rid of the modification log. */
|
||||
page_create_zip(page_cur_get_block(cursor), index,
|
||||
page_header_get_field(page, PAGE_LEVEL),
|
||||
0, NULL, mtr);
|
||||
0, mtr);
|
||||
ut_ad(!page_header_get_ptr(page, PAGE_FREE));
|
||||
|
||||
if (page_zip_available(
|
||||
|
@ -1641,7 +1641,7 @@ page_cur_insert_rec_zip(
|
|||
if (!log_compressed) {
|
||||
if (page_zip_compress(
|
||||
page_zip, page, index,
|
||||
level, NULL, NULL)) {
|
||||
level, NULL)) {
|
||||
page_cur_insert_rec_write_log(
|
||||
insert_rec, rec_size,
|
||||
cursor->rec, index, mtr);
|
||||
|
|
|
@ -30,7 +30,6 @@ Created 2/2/1994 Heikki Tuuri
|
|||
#include "page0zip.h"
|
||||
#include "buf0buf.h"
|
||||
#include "btr0btr.h"
|
||||
#include "row0trunc.h"
|
||||
#include "srv0srv.h"
|
||||
#include "lock0lock.h"
|
||||
#include "fut0lst.h"
|
||||
|
@ -454,22 +453,15 @@ page_create_zip(
|
|||
ulint level, /*!< in: the B-tree level
|
||||
of the page */
|
||||
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
|
||||
handle */
|
||||
{
|
||||
page_t* page;
|
||||
page_zip_des_t* page_zip = buf_block_get_page_zip(block);
|
||||
bool is_spatial;
|
||||
|
||||
ut_ad(block);
|
||||
ut_ad(page_zip);
|
||||
ut_ad(index == NULL || dict_table_is_comp(index->table));
|
||||
is_spatial = index ? dict_index_is_spatial(index)
|
||||
: page_comp_info->type & DICT_SPATIAL;
|
||||
ut_ad(dict_table_is_comp(index->table));
|
||||
|
||||
/* PAGE_MAX_TRX_ID or PAGE_ROOT_AUTO_INC are always 0 for
|
||||
temporary tables. */
|
||||
|
@ -487,22 +479,11 @@ page_create_zip(
|
|||
|| !dict_index_is_sec_or_ibuf(index)
|
||||
|| 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_8(PAGE_HEADER + PAGE_MAX_TRX_ID + page, max_trx_id);
|
||||
|
||||
if (truncate_t::s_fix_up_active) {
|
||||
/* 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)) {
|
||||
if (!page_zip_compress(page_zip, page, index, page_zip_level, mtr)) {
|
||||
/* The compression of a newly created
|
||||
page should always succeed. */
|
||||
ut_error;
|
||||
|
@ -546,7 +527,7 @@ page_create_empty(
|
|||
ut_ad(!index->table->is_temporary());
|
||||
page_create_zip(block, index,
|
||||
page_header_get_field(page, PAGE_LEVEL),
|
||||
max_trx_id, NULL, mtr);
|
||||
max_trx_id, mtr);
|
||||
} else {
|
||||
page_create(block, mtr, page_is_comp(page),
|
||||
dict_index_is_spatial(index));
|
||||
|
@ -721,11 +702,8 @@ page_copy_rec_list_end(
|
|||
if (new_page_zip) {
|
||||
mtr_set_log_mode(mtr, log_mode);
|
||||
|
||||
if (!page_zip_compress(new_page_zip,
|
||||
new_page,
|
||||
index,
|
||||
page_zip_level,
|
||||
NULL, mtr)) {
|
||||
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||
page_zip_level, mtr)) {
|
||||
/* Before trying to reorganize the page,
|
||||
store the number of preceding records on the page. */
|
||||
ulint ret_pos
|
||||
|
@ -887,7 +865,7 @@ page_copy_rec_list_start(
|
|||
goto zip_reorganize;);
|
||||
|
||||
if (!page_zip_compress(new_page_zip, new_page, index,
|
||||
page_zip_level, NULL, mtr)) {
|
||||
page_zip_level, mtr)) {
|
||||
ulint ret_pos;
|
||||
#ifndef DBUG_OFF
|
||||
zip_reorganize:
|
||||
|
|
|
@ -46,7 +46,6 @@ const byte field_ref_zero[FIELD_REF_SIZE] = {
|
|||
#include "page0types.h"
|
||||
#include "log0recv.h"
|
||||
#include "row0row.h"
|
||||
#include "row0trunc.h"
|
||||
#include "zlib.h"
|
||||
#include "buf0buf.h"
|
||||
#include "buf0types.h"
|
||||
|
@ -1248,17 +1247,11 @@ page_zip_compress(
|
|||
dict_index_t* index, /*!< in: index of the B-tree
|
||||
node */
|
||||
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,
|
||||
or NULL */
|
||||
{
|
||||
z_stream c_stream;
|
||||
int err;
|
||||
ulint n_fields; /* number of index fields
|
||||
needed */
|
||||
byte* fields; /*!< index field information */
|
||||
byte* buf; /*!< compressed payload of the
|
||||
page */
|
||||
|
@ -1273,7 +1266,6 @@ page_zip_compress(
|
|||
ulint n_blobs = 0;
|
||||
byte* storage; /* storage of uncompressed
|
||||
columns */
|
||||
index_id_t ind_id;
|
||||
uintmax_t usec = ut_time_us(NULL);
|
||||
#ifdef PAGE_ZIP_COMPRESS_DBG
|
||||
FILE* logfile = NULL;
|
||||
|
@ -1288,10 +1280,8 @@ page_zip_compress(
|
|||
ut_a(fil_page_index_page_check(page));
|
||||
ut_ad(page_simple_validate_new((page_t*) page));
|
||||
ut_ad(page_zip_simple_validate(page_zip));
|
||||
ut_ad(!index
|
||||
|| (index
|
||||
&& dict_table_is_comp(index->table)
|
||||
&& !dict_index_is_ibuf(index)));
|
||||
ut_ad(dict_table_is_comp(index->table));
|
||||
ut_ad(!dict_index_is_ibuf(index));
|
||||
|
||||
UNIV_MEM_ASSERT_RW(page, srv_page_size);
|
||||
|
||||
|
@ -1311,18 +1301,10 @@ page_zip_compress(
|
|||
== PAGE_NEW_SUPREMUM);
|
||||
}
|
||||
|
||||
if (truncate_t::s_fix_up_active) {
|
||||
ut_ad(page_comp_info != NULL);
|
||||
n_fields = page_comp_info->n_fields;
|
||||
ind_id = page_comp_info->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;
|
||||
}
|
||||
const ulint n_fields = page_is_leaf(page)
|
||||
? dict_index_get_n_fields(index)
|
||||
: dict_index_get_n_unique_in_tree_nonleaf(index);
|
||||
index_id_t ind_id = index->id;
|
||||
|
||||
/* The dense directory excludes the infimum and supremum records. */
|
||||
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 */
|
||||
if (page_is_leaf(page)) {
|
||||
if ((index && 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(
|
||||
index, DATA_TRX_ID);
|
||||
ut_ad(trx_id_col > 0);
|
||||
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;
|
||||
}
|
||||
if (dict_index_is_clust(index)) {
|
||||
trx_id_col = dict_index_get_sys_col_pos(
|
||||
index, DATA_TRX_ID);
|
||||
ut_ad(trx_id_col > 0);
|
||||
ut_ad(trx_id_col != ULINT_UNDEFINED);
|
||||
|
||||
slot_size = PAGE_ZIP_DIR_SLOT_SIZE
|
||||
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN;
|
||||
|
@ -1454,10 +1427,8 @@ page_zip_compress(
|
|||
} else {
|
||||
/* Signal the absence of trx_id
|
||||
in page_zip_fields_encode() */
|
||||
if (index) {
|
||||
ut_ad(dict_index_get_sys_col_pos(
|
||||
index, DATA_TRX_ID) == ULINT_UNDEFINED);
|
||||
}
|
||||
ut_ad(dict_index_get_sys_col_pos(
|
||||
index, DATA_TRX_ID) == ULINT_UNDEFINED);
|
||||
trx_id_col = 0;
|
||||
slot_size = PAGE_ZIP_DIR_SLOT_SIZE;
|
||||
}
|
||||
|
@ -1471,19 +1442,9 @@ page_zip_compress(
|
|||
goto zlib_error;
|
||||
}
|
||||
|
||||
c_stream.avail_out -= static_cast<uInt>(n_dense * slot_size);
|
||||
if (truncate_t::s_fix_up_active) {
|
||||
ut_ad(page_comp_info != NULL);
|
||||
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.avail_out -= uInt(n_dense * slot_size);
|
||||
c_stream.avail_in = uInt(page_zip_fields_encode(n_fields, index,
|
||||
trx_id_col, fields));
|
||||
c_stream.next_in = fields;
|
||||
|
||||
if (UNIV_LIKELY(!trx_id_col)) {
|
||||
|
@ -1637,7 +1598,7 @@ err_exit:
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -4807,9 +4768,7 @@ page_zip_reorganize(
|
|||
/* Restore logging. */
|
||||
mtr_set_log_mode(mtr, log_mode);
|
||||
|
||||
if (!page_zip_compress(page_zip, page, index,
|
||||
page_zip_level, NULL, mtr)) {
|
||||
|
||||
if (!page_zip_compress(page_zip, page, index, page_zip_level, mtr)) {
|
||||
buf_block_free(temp_block);
|
||||
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 "que0que.h"
|
||||
#include "row0mysql.h"
|
||||
#include "row0trunc.h"
|
||||
#include "row0log.h"
|
||||
#include "srv0mon.h"
|
||||
#include "srv0srv.h"
|
||||
|
@ -2585,16 +2584,10 @@ srv_do_purge(ulint* n_total_purged)
|
|||
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_use_threads,
|
||||
(++count % rseg_truncate_frequency) == 0);
|
||||
!(++count % srv_purge_rseg_truncate_frequency)
|
||||
|| purge_sys.truncate.current);
|
||||
|
||||
*n_total_purged += n_pages_purged;
|
||||
} while (n_pages_purged > 0 && !purge_sys.paused()
|
||||
|
@ -2729,11 +2722,6 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
|
|||
/* Note that we are shutting down. */
|
||||
rw_lock_x_lock(&purge_sys.latch);
|
||||
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. */
|
||||
os_event_set(purge_sys.event);
|
||||
|
||||
|
@ -2840,38 +2828,3 @@ void srv_purge_shutdown()
|
|||
srv_purge_wakeup();
|
||||
} 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 "btr0defragment.h"
|
||||
#include "fsp0sysspace.h"
|
||||
#include "row0trunc.h"
|
||||
#include "mysql/service_wsrep.h" /* wsrep_recovery */
|
||||
#include "trx0rseg.h"
|
||||
#include "os0proc.h"
|
||||
|
@ -100,7 +99,6 @@ Created 2/16/1996 Heikki Tuuri
|
|||
#include "row0upd.h"
|
||||
#include "row0row.h"
|
||||
#include "row0mysql.h"
|
||||
#include "row0trunc.h"
|
||||
#include "btr0pcur.h"
|
||||
#include "os0event.h"
|
||||
#include "zlib.h"
|
||||
|
@ -815,8 +813,6 @@ srv_check_undo_redo_logs_exists()
|
|||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
undo::undo_spaces_t undo::Truncate::s_fix_up_spaces;
|
||||
|
||||
/** Open the configured number of dedicated undo tablespaces.
|
||||
@param[in] create_new_db whether the database is being initialized
|
||||
@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;
|
||||
break;
|
||||
case SRV_OPERATION_NORMAL:
|
||||
if (create_new_db) {
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case SRV_OPERATION_RESTORE:
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -1943,7 +1843,7 @@ files_checked:
|
|||
|
||||
ulint ibuf_root = btr_create(
|
||||
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);
|
||||
|
||||
|
@ -1982,22 +1882,6 @@ files_checked:
|
|||
return(srv_init_abort(err));
|
||||
}
|
||||
} 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
|
||||
been shut down normally: this is the normal startup path */
|
||||
|
||||
|
@ -2276,14 +2160,6 @@ files_checked:
|
|||
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) {
|
||||
/* Open or Create SYS_TABLESPACES and SYS_DATAFILES
|
||||
so that tablespace names and other metadata can be
|
||||
|
@ -2321,10 +2197,6 @@ files_checked:
|
|||
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) {
|
||||
return(srv_init_abort(err));
|
||||
}
|
||||
|
|
|
@ -177,7 +177,8 @@ void purge_sys_t::create()
|
|||
hdr_offset= 0;
|
||||
rw_lock_create(trx_purge_latch_key, &latch, SYNC_PURGE_LATCH);
|
||||
mutex_create(LATCH_ID_PURGE_SYS_PQ, &pq_mutex);
|
||||
undo_trunc.create();
|
||||
truncate.current= NULL;
|
||||
truncate.last= NULL;
|
||||
}
|
||||
|
||||
/** Close the purge subsystem on shutdown. */
|
||||
|
@ -513,309 +514,22 @@ func_exit:
|
|||
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
|
||||
marked for truncate.
|
||||
@param[in,out] undo_trunc undo truncate tracker */
|
||||
static
|
||||
void
|
||||
trx_purge_cleanse_purge_queue(
|
||||
undo::Truncate* undo_trunc)
|
||||
@param[in] space undo tablespace being truncated */
|
||||
static void trx_purge_cleanse_purge_queue(const fil_space_t& space)
|
||||
{
|
||||
mutex_enter(&purge_sys.pq_mutex);
|
||||
typedef std::vector<TrxUndoRsegs> purge_elem_list_t;
|
||||
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
|
||||
truncate of corresponding UNDO truncate. */
|
||||
while (!purge_sys.purge_queue.empty()) {
|
||||
purge_elem_list.push_back(purge_sys.purge_queue.top());
|
||||
purge_sys.purge_queue.pop();
|
||||
}
|
||||
ut_ad(purge_sys.purge_queue.empty());
|
||||
|
||||
for (purge_elem_list_t::iterator it = purge_elem_list.begin();
|
||||
it != purge_elem_list.end();
|
||||
|
@ -824,9 +538,7 @@ trx_purge_cleanse_purge_queue(
|
|||
for (TrxUndoRsegs::iterator it2 = it->begin();
|
||||
it2 != it->end();
|
||||
++it2) {
|
||||
|
||||
if ((*it2)->space->id
|
||||
== undo_trunc->get_marked_space_id()) {
|
||||
if ((*it2)->space == &space) {
|
||||
it->erase(it2);
|
||||
break;
|
||||
}
|
||||
|
@ -836,251 +548,10 @@ trx_purge_cleanse_purge_queue(
|
|||
purge_sys.purge_queue.push(*it);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
can (greedy approach). This will ensure when the server is idle we
|
||||
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);
|
||||
trx_purge_initiate_truncate(head, &purge_sys.undo_trunc);
|
||||
if (srv_undo_tablespaces_active < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (srv_undo_log_truncate && srv_undo_logs >= 3) {
|
||||
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",
|
||||
"row0mysql",
|
||||
"row0sel",
|
||||
"row0trunc",
|
||||
"srv0conc",
|
||||
"srv0srv",
|
||||
"srv0start",
|
||||
|
|
|
@ -589,8 +589,6 @@ ut_strerr(
|
|||
return("Tablespace already exists");
|
||||
case DB_TABLESPACE_DELETED:
|
||||
return("Tablespace deleted or being deleted");
|
||||
case DB_TABLESPACE_TRUNCATED:
|
||||
return("Tablespace was truncated");
|
||||
case DB_TABLESPACE_NOT_FOUND:
|
||||
return("Tablespace not found");
|
||||
case DB_LOCK_TABLE_FULL:
|
||||
|
|
Loading…
Reference in a new issue