summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0purge.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row/row0purge.cc')
-rw-r--r--storage/innobase/row/row0purge.cc494
1 files changed, 255 insertions, 239 deletions
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 74bbc61df52..753b42332fc 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2017, 2022, MariaDB Corporation.
+Copyright (c) 2017, 2023, 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
@@ -25,8 +25,10 @@ Created 3/14/1997 Heikki Tuuri
*******************************************************/
#include "row0purge.h"
+#include "btr0cur.h"
#include "fsp0fsp.h"
#include "mach0data.h"
+#include "dict0crea.h"
#include "dict0stats.h"
#include "trx0rseg.h"
#include "trx0trx.h"
@@ -39,13 +41,13 @@ Created 3/14/1997 Heikki Tuuri
#include "row0upd.h"
#include "row0vers.h"
#include "row0mysql.h"
-#include "row0log.h"
#include "log0log.h"
#include "srv0mon.h"
#include "srv0start.h"
#include "handler.h"
#include "ha_innodb.h"
#include "fil0fil.h"
+#include <mysql/service_thd_mdl.h>
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@ -65,7 +67,7 @@ static
ibool
row_purge_reposition_pcur(
/*======================*/
- ulint mode, /*!< in: latching mode */
+ btr_latch_mode mode, /*!< in: latching mode */
purge_node_t* node, /*!< in: row purge node */
mtr_t* mtr) /*!< in: mtr */
{
@@ -73,7 +75,7 @@ row_purge_reposition_pcur(
ut_ad(node->validate_pcur());
node->found_clust =
- btr_pcur_restore_position(mode, &node->pcur, mtr) ==
+ node->pcur.restore_position(mode, mtr) ==
btr_pcur_t::SAME_ALL;
} else {
@@ -102,20 +104,93 @@ bool
row_purge_remove_clust_if_poss_low(
/*===============================*/
purge_node_t* node, /*!< in/out: row purge node */
- ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
+ btr_latch_mode mode) /*!< in: BTR_MODIFY_LEAF or BTR_PURGE_TREE */
{
dict_index_t* index = dict_table_get_first_index(node->table);
+ table_id_t table_id = 0;
+ index_id_t index_id = 0;
+ dict_table_t *table = nullptr;
+ pfs_os_file_t f = OS_FILE_CLOSED;
- log_free_check();
-
+ if (table_id) {
+retry:
+ purge_sys.check_stop_FTS();
+ dict_sys.lock(SRW_LOCK_CALL);
+ table = dict_sys.find_table(table_id);
+ if (!table) {
+ dict_sys.unlock();
+ } else if (table->n_rec_locks) {
+ for (dict_index_t* ind = UT_LIST_GET_FIRST(
+ table->indexes); ind;
+ ind = UT_LIST_GET_NEXT(indexes, ind)) {
+ if (ind->id == index_id) {
+ lock_discard_for_index(*ind);
+ }
+ }
+ }
+ }
mtr_t mtr;
mtr.start();
index->set_modified(mtr);
+ log_free_check();
+ bool success = true;
if (!row_purge_reposition_pcur(mode, node, &mtr)) {
/* The record was already removed. */
+removed:
mtr.commit();
- return true;
+close_and_exit:
+ if (table) {
+ dict_sys.unlock();
+ }
+ return success;
+ }
+
+ if (node->table->id == DICT_INDEXES_ID) {
+ /* If this is a record of the SYS_INDEXES table, then
+ we have to free the file segments of the index tree
+ associated with the index */
+ if (!table_id) {
+ const rec_t* rec = btr_pcur_get_rec(&node->pcur);
+
+ table_id = mach_read_from_8(rec);
+ index_id = mach_read_from_8(rec + 8);
+ if (table_id) {
+ mtr.commit();
+ goto retry;
+ }
+ ut_ad("corrupted SYS_INDEXES record" == 0);
+ }
+
+ if (const uint32_t space_id = dict_drop_index_tree(
+ &node->pcur, nullptr, &mtr)) {
+ if (table) {
+ if (table->get_ref_count() == 0) {
+ dict_sys.remove(table);
+ } else if (table->space_id == space_id) {
+ table->space = nullptr;
+ table->file_unreadable = true;
+ }
+ dict_sys.unlock();
+ table = nullptr;
+ }
+ f = fil_delete_tablespace(space_id);
+ }
+
+ mtr.commit();
+
+ if (table) {
+ dict_sys.unlock();
+ table = nullptr;
+ }
+
+ purge_sys.check_stop_SYS();
+ mtr.start();
+ index->set_modified(mtr);
+
+ if (!row_purge_reposition_pcur(mode, node, &mtr)) {
+ goto removed;
+ }
}
rec_t* rec = btr_pcur_get_rec(&node->pcur);
@@ -125,7 +200,6 @@ row_purge_remove_clust_if_poss_low(
rec_offs* offsets = rec_get_offsets(rec, index, offsets_,
index->n_core_fields,
ULINT_UNDEFINED, &heap);
- bool success = true;
if (node->roll_ptr != row_get_rec_roll_ptr(rec, index, offsets)) {
/* Someone else has modified the record later: do not remove */
@@ -138,24 +212,15 @@ row_purge_remove_clust_if_poss_low(
ut_ad(row_get_rec_trx_id(rec, index, offsets));
if (mode == BTR_MODIFY_LEAF) {
- success = btr_cur_optimistic_delete(
+ success = DB_FAIL != btr_cur_optimistic_delete(
btr_pcur_get_btr_cur(&node->pcur), 0, &mtr);
} else {
dberr_t err;
- ut_ad(mode == (BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE));
+ ut_ad(mode == BTR_PURGE_TREE);
btr_cur_pessimistic_delete(
&err, FALSE, btr_pcur_get_btr_cur(&node->pcur), 0,
false, &mtr);
-
- switch (err) {
- case DB_SUCCESS:
- break;
- case DB_OUT_OF_FILE_SPACE:
- success = false;
- break;
- default:
- ut_error;
- }
+ success = err == DB_SUCCESS;
}
func_exit:
@@ -170,7 +235,7 @@ func_exit:
mtr_commit(&mtr);
}
- return(success);
+ goto close_and_exit;
}
/***********************************************************//**
@@ -192,12 +257,11 @@ row_purge_remove_clust_if_poss(
for (ulint n_tries = 0;
n_tries < BTR_CUR_RETRY_DELETE_N_TIMES;
n_tries++) {
- if (row_purge_remove_clust_if_poss_low(
- node, BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE)) {
+ if (row_purge_remove_clust_if_poss_low(node, BTR_PURGE_TREE)) {
return(true);
}
- os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
+ std::this_thread::sleep_for(BTR_CUR_RETRY_SLEEP_TIME);
}
return(false);
@@ -278,39 +342,20 @@ row_purge_remove_sec_if_poss_tree(
ibool success = TRUE;
dberr_t err;
mtr_t mtr;
- enum row_search_result search_result;
log_free_check();
mtr.start();
index->set_modified(mtr);
+ pcur.btr_cur.page_cur.index = index;
- if (!index->is_committed()) {
- /* The index->online_status may change if the index is
- or was being created online, but not committed yet. It
- is protected by index->lock. */
- mtr_sx_lock_index(index, &mtr);
-
- if (dict_index_is_online_ddl(index)) {
- /* Online secondary index creation will not
- copy any delete-marked records. Therefore
- there is nothing to be purged. We must also
- skip the purge when a completed index is
- dropped by rollback_inplace_alter_table(). */
- goto func_exit_no_pcur;
+ if (index->is_spatial()) {
+ if (!rtr_search(entry, BTR_PURGE_TREE, &pcur, &mtr)) {
+ goto found;
}
- } else {
- /* For secondary indexes,
- index->online_status==ONLINE_INDEX_COMPLETE if
- index->is_committed(). */
- ut_ad(!dict_index_is_online_ddl(index));
+ goto func_exit;
}
- search_result = row_search_index_entry(
- index, entry,
- BTR_MODIFY_TREE | BTR_LATCH_FOR_DELETE,
- &pcur, &mtr);
-
- switch (search_result) {
+ switch (row_search_index_entry(entry, BTR_PURGE_TREE, &pcur, &mtr)) {
case ROW_NOT_FOUND:
/* Not found. This is a legitimate condition. In a
rollback, InnoDB will remove secondary recs that would
@@ -339,6 +384,7 @@ row_purge_remove_sec_if_poss_tree(
which cannot be purged yet, requires its existence. If some requires,
we should do nothing. */
+found:
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, true)) {
/* Remove the index record, which should have been
@@ -377,7 +423,6 @@ row_purge_remove_sec_if_poss_tree(
func_exit:
btr_pcur_close(&pcur); // FIXME: need this?
-func_exit_no_pcur:
mtr.commit();
return(success);
@@ -398,8 +443,6 @@ row_purge_remove_sec_if_poss_leaf(
{
mtr_t mtr;
btr_pcur_t pcur;
- enum btr_latch_mode mode;
- enum row_search_result search_result;
bool success = true;
log_free_check();
@@ -408,62 +451,27 @@ row_purge_remove_sec_if_poss_leaf(
mtr.start();
index->set_modified(mtr);
- if (!index->is_committed()) {
- /* For uncommitted spatial index, we also skip the purge. */
- if (dict_index_is_spatial(index)) {
- goto func_exit_no_pcur;
- }
-
- /* The index->online_status may change if the the
- index is or was being created online, but not
- committed yet. It is protected by index->lock. */
- mtr_s_lock_index(index, &mtr);
-
- if (dict_index_is_online_ddl(index)) {
- /* Online secondary index creation will not
- copy any delete-marked records. Therefore
- there is nothing to be purged. We must also
- skip the purge when a completed index is
- dropped by rollback_inplace_alter_table(). */
- goto func_exit_no_pcur;
- }
-
- mode = BTR_PURGE_LEAF_ALREADY_S_LATCHED;
- } else {
- /* For secondary indexes,
- index->online_status==ONLINE_INDEX_COMPLETE if
- index->is_committed(). */
- ut_ad(!dict_index_is_online_ddl(index));
-
- /* Change buffering is disabled for spatial index and
- virtual index. */
- mode = (dict_index_is_spatial(index)
- || dict_index_has_virtual(index))
- ? BTR_MODIFY_LEAF
- : BTR_PURGE_LEAF;
- }
+ pcur.btr_cur.page_cur.index = index;
/* Set the purge node for the call to row_purge_poss_sec(). */
pcur.btr_cur.purge_node = node;
- if (dict_index_is_spatial(index)) {
- rw_lock_sx_lock(dict_index_get_lock(index));
+ if (index->is_spatial()) {
pcur.btr_cur.thr = NULL;
- } else {
- /* Set the query thread, so that ibuf_insert_low() will be
- able to invoke thd_get_trx(). */
- pcur.btr_cur.thr = static_cast<que_thr_t*>(
- que_node_get_parent(node));
+ if (!rtr_search(entry, BTR_MODIFY_LEAF, &pcur, &mtr)) {
+ goto found;
+ }
+ goto func_exit;
}
- search_result = row_search_index_entry(
- index, entry, mode, &pcur, &mtr);
-
- if (dict_index_is_spatial(index)) {
- rw_lock_sx_unlock(dict_index_get_lock(index));
- }
+ /* Set the query thread, so that ibuf_insert_low() will be
+ able to invoke thd_get_trx(). */
+ pcur.btr_cur.thr = static_cast<que_thr_t*>(que_node_get_parent(node));
- switch (search_result) {
+ switch (row_search_index_entry(entry, index->has_virtual()
+ ? BTR_MODIFY_LEAF : BTR_PURGE_LEAF,
+ &pcur, &mtr)) {
case ROW_FOUND:
+found:
/* Before attempting to purge a record, check
if it is safe to do so. */
if (row_purge_poss_sec(node, index, entry, &pcur, &mtr, false)) {
@@ -483,11 +491,9 @@ row_purge_remove_sec_if_poss_leaf(
<< rec_index_print(
btr_cur_get_rec(btr_cur),
index);
- ut_ad(0);
-
- btr_pcur_close(&pcur);
-
- goto func_exit_no_pcur;
+ mtr.commit();
+ dict_set_corrupted(index, "purge");
+ goto cleanup;
}
if (index->is_spatial()) {
@@ -496,7 +502,7 @@ row_purge_remove_sec_if_poss_leaf(
if (block->page.id().page_no()
!= index->page
- && page_get_n_recs(block->frame) < 2
+ && page_get_n_recs(block->page.frame) < 2
&& !lock_test_prdt_page_lock(
btr_cur->rtr_info
&& btr_cur->rtr_info->thr
@@ -512,18 +518,12 @@ row_purge_remove_sec_if_poss_leaf(
"skip purging last"
" record on page "
<< block->page.id());
-
- btr_pcur_close(&pcur);
- mtr.commit();
- return(success);
+ goto func_exit;
}
}
- if (!btr_cur_optimistic_delete(btr_cur, 0, &mtr)) {
-
- /* The index entry could not be deleted. */
- success = false;
- }
+ success = btr_cur_optimistic_delete(btr_cur, 0, &mtr)
+ != DB_FAIL;
}
/* (The index entry is still needed,
@@ -535,9 +535,10 @@ row_purge_remove_sec_if_poss_leaf(
/* The deletion was buffered. */
case ROW_NOT_FOUND:
/* The index entry does not exist, nothing to do. */
- btr_pcur_close(&pcur); // FIXME: do we need these? when is btr_cur->rtr_info set?
-func_exit_no_pcur:
+func_exit:
mtr.commit();
+cleanup:
+ btr_pcur_close(&pcur); // FIXME: do we need these? when is btr_cur->rtr_info set?
return(success);
}
@@ -581,7 +582,7 @@ retry:
n_tries++;
- os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
+ std::this_thread::sleep_for(BTR_CUR_RETRY_SLEEP_TIME);
goto retry;
}
@@ -589,25 +590,6 @@ retry:
ut_a(success);
}
-/** Skip uncommitted virtual indexes on newly added virtual column.
-@param[in,out] index dict index object */
-static
-inline
-void
-row_purge_skip_uncommitted_virtual_index(
- dict_index_t*& index)
-{
- /* We need to skip virtual indexes which is not
- committed yet. It's safe because these indexes are
- newly created by alter table, and because we do
- not support LOCK=NONE when adding an index on newly
- added virtual column.*/
- while (index != NULL && dict_index_has_virtual(index)
- && !index->is_committed() && index->has_new_v_col()) {
- index = dict_table_get_next_index(index);
- }
-}
-
/***********************************************************//**
Purges a delete marking of a record.
@retval true if the row was not found, or it was successfully removed
@@ -619,34 +601,42 @@ row_purge_del_mark(
/*===============*/
purge_node_t* node) /*!< in/out: row purge node */
{
- mem_heap_t* heap;
-
- heap = mem_heap_create(1024);
-
- while (node->index != NULL) {
- /* skip corrupted secondary index */
- dict_table_skip_corrupt_index(node->index);
-
- row_purge_skip_uncommitted_virtual_index(node->index);
+ if (node->index)
+ {
+ mem_heap_t *heap= mem_heap_create(1024);
- if (!node->index) {
- break;
- }
+ do
+ {
+ const auto type= node->index->type;
+ if (type & (DICT_FTS | DICT_CORRUPT))
+ continue;
+ if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
+ node->index->has_new_v_col())
+ continue;
+ dtuple_t* entry= row_build_index_entry_low(node->row, nullptr,
+ node->index, heap,
+ ROW_BUILD_FOR_PURGE);
+ row_purge_remove_sec_if_poss(node, node->index, entry);
+ mem_heap_empty(heap);
+ }
+ while ((node->index= dict_table_get_next_index(node->index)));
- if (node->index->type != DICT_FTS) {
- dtuple_t* entry = row_build_index_entry_low(
- node->row, NULL, node->index,
- heap, ROW_BUILD_FOR_PURGE);
- row_purge_remove_sec_if_poss(node, node->index, entry);
- mem_heap_empty(heap);
- }
+ mem_heap_free(heap);
+ }
- node->index = dict_table_get_next_index(node->index);
- }
+ return row_purge_remove_clust_if_poss(node);
+}
- mem_heap_free(heap);
+void purge_sys_t::wait_SYS()
+{
+ while (must_wait_SYS())
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+}
- return(row_purge_remove_clust_if_poss(node));
+void purge_sys_t::wait_FTS()
+{
+ while (must_wait_FTS())
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
/** Reset DB_TRX_ID, DB_ROLL_PTR of a clustered index record
@@ -655,6 +645,7 @@ whose old history can no longer be observed.
@param[in,out] mtr mini-transaction (will be started and committed) */
static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
{
+retry:
/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
mtr->start();
@@ -690,6 +681,17 @@ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
ut_ad(!rec_get_deleted_flag(
rec, rec_offs_comp(offsets))
|| rec_is_alter_metadata(rec, *index));
+ switch (node->table->id) {
+ case DICT_TABLES_ID:
+ case DICT_COLUMNS_ID:
+ case DICT_INDEXES_ID:
+ if (purge_sys.must_wait_SYS()) {
+ mtr->commit();
+ purge_sys.check_stop_SYS();
+ goto retry;
+ }
+ }
+
DBUG_LOG("purge", "reset DB_TRX_ID="
<< ib::hex(row_get_rec_trx_id(
rec, index, offsets)));
@@ -709,9 +711,9 @@ static void row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
size_t offs = page_offset(ptr);
mtr->memset(block, offs, DATA_TRX_ID_LEN, 0);
offs += DATA_TRX_ID_LEN;
- mtr->write<1,mtr_t::MAYBE_NOP>(*block,
- block->frame
- + offs, 0x80U);
+ mtr->write<1,mtr_t::MAYBE_NOP>(
+ *block, block->page.frame + offs,
+ 0x80U);
mtr->memset(block, offs + 1,
DATA_ROLL_PTR_LEN - 1, 0);
}
@@ -739,20 +741,25 @@ row_purge_upd_exist_or_extern_func(
ut_ad(!node->table->skip_alter_undo);
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
- || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
+ || (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)
+ || !node->index) {
goto skip_secondaries;
}
heap = mem_heap_create(1024);
- while (node->index != NULL) {
- dict_table_skip_corrupt_index(node->index);
+ do {
+ const auto type = node->index->type;
- row_purge_skip_uncommitted_virtual_index(node->index);
+ if (type & (DICT_FTS | DICT_CORRUPT)) {
+ continue;
+ }
- if (!node->index) {
- break;
+ if (UNIV_UNLIKELY(DICT_VIRTUAL & type)
+ && !node->index->is_committed()
+ && node->index->has_new_v_col()) {
+ continue;
}
if (row_upd_changes_ord_field_binary(node->index, node->update,
@@ -767,9 +774,7 @@ row_purge_upd_exist_or_extern_func(
mem_heap_empty(heap);
}
-
- node->index = dict_table_get_next_index(node->index);
- }
+ } while ((node->index = dict_table_get_next_index(node->index)));
mem_heap_free(heap);
@@ -783,9 +788,6 @@ skip_secondaries:
= upd_get_nth_field(node->update, i);
if (dfield_is_ext(&ufield->new_val)) {
- trx_rseg_t* rseg;
- buf_block_t* block;
- byte* data_field;
bool is_insert;
ulint rseg_id;
uint32_t page_no;
@@ -808,11 +810,8 @@ skip_secondaries:
&is_insert, &rseg_id,
&page_no, &offset);
- rseg = trx_sys.rseg_array[rseg_id];
-
- ut_a(rseg != NULL);
- ut_ad(rseg->id == rseg_id);
- ut_ad(rseg->is_persistent());
+ const trx_rseg_t &rseg = trx_sys.rseg_array[rseg_id];
+ ut_ad(rseg.is_persistent());
mtr.start();
@@ -823,7 +822,7 @@ skip_secondaries:
index->set_modified(mtr);
- /* NOTE: we must also acquire an X-latch to the
+ /* NOTE: we must also acquire a U latch to the
root page of the tree. We will need it when we
free pages from the tree. If the tree is of height 1,
the tree X-latch does NOT protect the root page,
@@ -832,24 +831,26 @@ skip_secondaries:
latching order if we would only later latch the
root page of such a tree! */
- btr_root_get(index, &mtr);
-
- block = buf_page_get(
- page_id_t(rseg->space->id, page_no),
- 0, RW_X_LATCH, &mtr);
-
- buf_block_dbg_add_level(block, SYNC_TRX_UNDO_PAGE);
-
- data_field = buf_block_get_frame(block)
- + offset + internal_offset;
+ dberr_t err;
+ if (!btr_root_block_get(index, RW_SX_LATCH, &mtr,
+ &err)) {
+ } else if (buf_block_t* block =
+ buf_page_get(page_id_t(rseg.space->id,
+ page_no),
+ 0, RW_X_LATCH, &mtr)) {
+ byte* data_field = block->page.frame
+ + offset + internal_offset;
+
+ ut_a(dfield_get_len(&ufield->new_val)
+ >= BTR_EXTERN_FIELD_REF_SIZE);
+ btr_free_externally_stored_field(
+ index,
+ data_field
+ + dfield_get_len(&ufield->new_val)
+ - BTR_EXTERN_FIELD_REF_SIZE,
+ NULL, NULL, block, 0, false, &mtr);
+ }
- ut_a(dfield_get_len(&ufield->new_val)
- >= BTR_EXTERN_FIELD_REF_SIZE);
- btr_free_externally_stored_field(
- index,
- data_field + dfield_get_len(&ufield->new_val)
- - BTR_EXTERN_FIELD_REF_SIZE,
- NULL, NULL, block, 0, false, &mtr);
mtr.commit();
}
}
@@ -997,6 +998,7 @@ static byte *row_purge_get_partial(const byte *ptr, const dict_index_t &index,
return const_cast<byte*>(ptr);
}
+MY_ATTRIBUTE((nonnull,warn_unused_result))
/** Parses the row reference and other info in a modify undo log record.
@param[in] node row undo node
@param[in] undo_rec record to purge
@@ -1013,17 +1015,13 @@ row_purge_parse_undo_rec(
bool* updated_extern)
{
dict_index_t* clust_index;
- byte* ptr;
undo_no_t undo_no;
table_id_t table_id;
roll_ptr_t roll_ptr;
byte info_bits;
ulint type;
- ut_ad(node != NULL);
- ut_ad(thr != NULL);
-
- ptr = trx_undo_rec_get_pars(
+ const byte* ptr = trx_undo_rec_get_pars(
undo_rec, &type, &node->cmpl_info,
updated_extern, &undo_no, &table_id);
@@ -1032,6 +1030,7 @@ row_purge_parse_undo_rec(
switch (type) {
case TRX_UNDO_RENAME_TABLE:
return false;
+ case TRX_UNDO_EMPTY:
case TRX_UNDO_INSERT_METADATA:
case TRX_UNDO_INSERT_REC:
/* These records do not store any transaction identifier.
@@ -1065,10 +1064,17 @@ row_purge_parse_undo_rec(
}
try_again:
+ purge_sys.check_stop_FTS();
+
node->table = dict_table_open_on_id<true>(
table_id, false, DICT_TABLE_OP_NORMAL, node->purge_thd,
&node->mdl_ticket);
+ if (node->table == reinterpret_cast<dict_table_t*>(-1)) {
+ /* purge stop signal */
+ goto try_again;
+ }
+
if (!node->table) {
/* The table has been dropped: no need to do purge and
release mdl happened as a part of open process itself */
@@ -1094,7 +1100,7 @@ already_locked:
if (srv_shutdown_state > SRV_SHUTDOWN_NONE) {
return(false);
}
- os_thread_sleep(1000000);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
goto try_again;
}
}
@@ -1122,6 +1128,9 @@ err_exit:
if (type == TRX_UNDO_INSERT_METADATA) {
node->ref = &trx_undo_metadata;
return(true);
+ } else if (type == TRX_UNDO_EMPTY) {
+ node->ref = nullptr;
+ return true;
}
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
@@ -1164,18 +1173,18 @@ row_purge_record_func(
#endif /* UNIV_DEBUG || WITH_WSREP */
bool updated_extern)
{
- dict_index_t* clust_index;
- bool purged = true;
-
ut_ad(!node->found_clust);
ut_ad(!node->table->skip_alter_undo);
+ ut_ad(!trx_undo_roll_ptr_is_insert(node->roll_ptr));
- clust_index = dict_table_get_first_index(node->table);
+ node->index = dict_table_get_next_index(
+ dict_table_get_first_index(node->table));
- node->index = dict_table_get_next_index(clust_index);
- ut_ad(!trx_undo_roll_ptr_is_insert(node->roll_ptr));
+ bool purged = true;
switch (node->rec_type) {
+ case TRX_UNDO_EMPTY:
+ break;
case TRX_UNDO_DEL_MARK_REC:
purged = row_purge_del_mark(node);
if (purged) {
@@ -1205,8 +1214,8 @@ row_purge_record_func(
}
if (node->found_clust) {
+ node->found_clust = false;
btr_pcur_close(&node->pcur);
- node->found_clust = FALSE;
}
return(purged);
@@ -1232,7 +1241,7 @@ row_purge(
trx_undo_rec_t* undo_rec, /*!< in: record to purge */
que_thr_t* thr) /*!< in: query thread */
{
- if (undo_rec != &trx_purge_dummy_rec) {
+ if (undo_rec != reinterpret_cast<trx_undo_rec_t*>(-1)) {
bool updated_extern;
while (row_purge_parse_undo_rec(
@@ -1247,30 +1256,44 @@ row_purge(
}
/* Retry the purge in a second. */
- os_thread_sleep(1000000);
+ std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
}
-/***********************************************************//**
-Reset the purge query thread. */
-UNIV_INLINE
-void
-row_purge_end(
-/*==========*/
- que_thr_t* thr) /*!< in: query thread */
+inline void purge_node_t::start()
{
- ut_ad(thr);
-
- thr->run_node = static_cast<purge_node_t*>(thr->run_node)->end();
+ ut_ad(in_progress);
+ DBUG_ASSERT(common.type == QUE_NODE_PURGE);
+
+ row= nullptr;
+ ref= nullptr;
+ index= nullptr;
+ update= nullptr;
+ found_clust= FALSE;
+ rec_type= ULINT_UNDEFINED;
+ cmpl_info= ULINT_UNDEFINED;
+ if (!purge_thd)
+ purge_thd= current_thd;
+}
- ut_a(thr->run_node != NULL);
+/** Reset the state at end
+@return the query graph parent */
+inline que_node_t *purge_node_t::end()
+{
+ DBUG_ASSERT(common.type == QUE_NODE_PURGE);
+ close_table();
+ ut_ad(undo_recs.empty());
+ ut_d(in_progress= false);
+ purge_thd= nullptr;
+ mem_heap_empty(heap);
+ return common.parent;
}
+
/***********************************************************//**
-Does the purge operation for a single undo log record. This is a high-level
-function used in an SQL execution graph.
-@return query thread to run next or NULL */
+Does the purge operation.
+@return query thread to run next */
que_thr_t*
row_purge_step(
/*===========*/
@@ -1282,22 +1305,15 @@ row_purge_step(
node->start();
- if (!node->undo_recs.empty()) {
+ while (!node->undo_recs.empty()) {
trx_purge_rec_t purge_rec = node->undo_recs.front();
node->undo_recs.pop();
node->roll_ptr = purge_rec.roll_ptr;
row_purge(node, purge_rec.undo_rec, thr);
-
- if (node->undo_recs.empty()) {
- row_purge_end(thr);
- } else {
- thr->run_node = node;
- }
- } else {
- row_purge_end(thr);
}
+ thr->run_node = node->end();
return(thr);
}
@@ -1324,11 +1340,11 @@ purge_node_t::validate_pcur()
return(true);
}
- if (!pcur.old_stored) {
+ if (!pcur.old_rec) {
return(true);
}
- dict_index_t* clust_index = pcur.btr_cur.index;
+ dict_index_t* clust_index = pcur.index();
rec_offs* offsets = rec_get_offsets(
pcur.old_rec, clust_index, NULL, pcur.old_n_core_fields,