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.cc443
1 files changed, 276 insertions, 167 deletions
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index ab28b396920..ee603be453a 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -42,8 +42,10 @@ 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"
/*************************************************************************
IMPORTANT NOTE: Any operation that generates redo MUST check that there
@@ -110,119 +112,134 @@ row_purge_reposition_pcur(
return(node->found_clust);
}
+/** Status of row_purge_remove_clust() */
+enum row_purge_status {
+ ROW_PURGE_DONE, /*!< The row has been removed. */
+ ROW_PURGE_FAIL, /*!< The purge was not successful. */
+ ROW_PURGE_SUSPEND/*!< Cannot purge now, due to online rebuild. */
+};
+
/***********************************************************//**
Removes a delete marked clustered index record if possible.
-@return TRUE if success, or if not found, or if modified after the
-delete marking */
-static
-ibool
+@retval ROW_PURGE_DONE if the row was not found, or it was successfully removed
+@retval ROW_PURGE_FAIL if the row was modified after the delete marking
+@retval ROW_PURGE_SUSPEND if the row refers to an off-page column and
+an online ALTER TABLE (table rebuild) is in progress. */
+static __attribute__((nonnull, warn_unused_result))
+enum row_purge_status
row_purge_remove_clust_if_poss_low(
/*===============================*/
- purge_node_t* node, /*!< in: row purge node */
+ purge_node_t* node, /*!< in/out: row purge node */
ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */
{
- dict_index_t* index;
- btr_pcur_t* pcur;
- btr_cur_t* btr_cur;
- ibool success;
- ulint err;
- mtr_t mtr;
- rec_t* rec;
- mem_heap_t* heap = NULL;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ dict_index_t* index;
+ enum row_purge_status status = ROW_PURGE_DONE;
+ mtr_t mtr;
+ rec_t* rec;
+ mem_heap_t* heap = NULL;
+ ulint* offsets;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
rec_offs_init(offsets_);
- index = dict_table_get_first_index(node->table);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
- pcur = &node->pcur;
- btr_cur = btr_pcur_get_btr_cur(pcur);
+ index = dict_table_get_first_index(node->table);
log_free_check();
mtr_start(&mtr);
- success = row_purge_reposition_pcur(mode, node, &mtr);
-
- if (!success) {
- /* The record is already removed */
-
- btr_pcur_commit_specify_mtr(pcur, &mtr);
-
- return(TRUE);
+ if (!row_purge_reposition_pcur(mode, node, &mtr)) {
+ /* The record was already removed. */
+ goto func_exit;
}
- rec = btr_pcur_get_rec(pcur);
+ rec = btr_pcur_get_rec(&node->pcur);
- if (node->roll_ptr != row_get_rec_roll_ptr(
- rec, index, rec_get_offsets(rec, index, offsets_,
- ULINT_UNDEFINED, &heap))) {
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
- }
- /* Someone else has modified the record later: do not remove */
- btr_pcur_commit_specify_mtr(pcur, &mtr);
+ offsets = rec_get_offsets(
+ rec, index, offsets_, ULINT_UNDEFINED, &heap);
- return(TRUE);
+ if (node->roll_ptr != row_get_rec_roll_ptr(rec, index, offsets)) {
+ /* Someone else has modified the record later: do not remove */
+ goto func_exit;
}
- if (UNIV_LIKELY_NULL(heap)) {
- mem_heap_free(heap);
+ if (dict_index_get_online_status(index) == ONLINE_INDEX_CREATION
+ && rec_offs_any_extern(offsets)) {
+ status = ROW_PURGE_SUSPEND;
+ goto func_exit;
}
if (mode == BTR_MODIFY_LEAF) {
- success = btr_cur_optimistic_delete(btr_cur, &mtr);
+ status = btr_cur_optimistic_delete(
+ btr_pcur_get_btr_cur(&node->pcur), 0, &mtr)
+ ? ROW_PURGE_DONE : ROW_PURGE_FAIL;
} else {
+ dberr_t err;
ut_ad(mode == BTR_MODIFY_TREE);
- btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
- RB_NONE, &mtr);
+ btr_cur_pessimistic_delete(
+ &err, FALSE, btr_pcur_get_btr_cur(&node->pcur), 0,
+ RB_NONE, &mtr);
- if (err == DB_SUCCESS) {
- success = TRUE;
- } else if (err == DB_OUT_OF_FILE_SPACE) {
- success = FALSE;
- } else {
+ switch (err) {
+ case DB_SUCCESS:
+ break;
+ case DB_OUT_OF_FILE_SPACE:
+ status = ROW_PURGE_FAIL;
+ break;
+ default:
ut_error;
}
}
- btr_pcur_commit_specify_mtr(pcur, &mtr);
+func_exit:
+ if (heap) {
+ mem_heap_free(heap);
+ }
- return(success);
+ btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
+
+ return(status);
}
/***********************************************************//**
Removes a clustered index record if it has not been modified after the delete
-marking. */
-static
-void
+marking.
+@retval true if the row was not found, or it was successfully removed
+@retval false the purge needs to be suspended, either because of
+running out of file space or because the row refers to an off-page
+column and an online ALTER TABLE (table rebuild) is in progress. */
+static __attribute__((nonnull, warn_unused_result))
+bool
row_purge_remove_clust_if_poss(
/*===========================*/
- purge_node_t* node) /*!< in: row purge node */
+ purge_node_t* node) /*!< in/out: row purge node */
{
- ibool success;
- ulint n_tries = 0;
-
- /* fputs("Purge: Removing clustered record\n", stderr); */
-
- success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF);
- if (success) {
-
- return;
+ switch (row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_LEAF)) {
+ case ROW_PURGE_DONE:
+ return(true);
+ case ROW_PURGE_SUSPEND:
+ return(false);
+ case ROW_PURGE_FAIL:
+ break;
}
-retry:
- success = row_purge_remove_clust_if_poss_low(node, BTR_MODIFY_TREE);
- /* The delete operation may fail if we have little
- file space left: TODO: easiest to crash the database
- and restart with more file space */
- if (!success && n_tries < BTR_CUR_RETRY_DELETE_N_TIMES) {
- n_tries++;
-
- os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
-
- goto retry;
+ for (ulint n_tries = 0;
+ n_tries < BTR_CUR_RETRY_DELETE_N_TIMES;
+ n_tries++) {
+ switch (row_purge_remove_clust_if_poss_low(
+ node, BTR_MODIFY_TREE)) {
+ case ROW_PURGE_DONE:
+ return(true);
+ case ROW_PURGE_SUSPEND:
+ return(false);
+ case ROW_PURGE_FAIL:
+ os_thread_sleep(BTR_CUR_RETRY_SLEEP_TIME);
+ }
}
- ut_a(success);
+ return(false);
}
/***********************************************************//**
@@ -234,21 +251,21 @@ is newer than the purge view.
NOTE: This function should only be called by the purge thread, only
while holding a latch on the leaf page of the secondary index entry
(or keeping the buffer pool watch on the page). It is possible that
-this function first returns TRUE and then FALSE, if a user transaction
+this function first returns true and then false, if a user transaction
inserts a record that the secondary index entry would refer to.
However, in that case, the user transaction would also re-insert the
secondary index entry after purge has removed it and released the leaf
page latch.
-@return TRUE if the secondary index record can be purged */
+@return true if the secondary index record can be purged */
UNIV_INTERN
-ibool
+bool
row_purge_poss_sec(
/*===============*/
purge_node_t* node, /*!< in/out: row purge node */
dict_index_t* index, /*!< in: secondary index */
const dtuple_t* entry) /*!< in: secondary index entry */
{
- ibool can_delete;
+ bool can_delete;
mtr_t mtr;
ut_ad(!dict_index_is_clust(index));
@@ -268,7 +285,7 @@ row_purge_poss_sec(
Removes a secondary index entry if possible, by modifying the
index tree. Does not try to buffer the delete.
@return TRUE if success or if not found */
-static
+static __attribute__((nonnull, warn_unused_result))
ibool
row_purge_remove_sec_if_poss_tree(
/*==============================*/
@@ -279,13 +296,35 @@ row_purge_remove_sec_if_poss_tree(
btr_pcur_t pcur;
btr_cur_t* btr_cur;
ibool success = TRUE;
- ulint err;
+ dberr_t err;
mtr_t mtr;
enum row_search_result search_result;
log_free_check();
mtr_start(&mtr);
+ if (*index->name == TEMP_INDEX_PREFIX) {
+ /* The index->online_status may change if the
+ index->name starts with TEMP_INDEX_PREFIX (meaning
+ that the index is or was being created online). It is
+ protected by index->lock. */
+ mtr_x_lock(dict_index_get_lock(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;
+ }
+ } else {
+ /* For secondary indexes,
+ index->online_status==ONLINE_INDEX_CREATION unless
+ index->name starts with TEMP_INDEX_PREFIX. */
+ ut_ad(!dict_index_is_online_ddl(index));
+ }
+
search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
&pcur, &mtr);
@@ -327,7 +366,7 @@ row_purge_remove_sec_if_poss_tree(
& rec_get_info_bits(btr_cur_get_rec(btr_cur),
dict_table_is_comp(index->table)));
- btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
+ btr_cur_pessimistic_delete(&err, FALSE, btr_cur, 0,
RB_NONE, &mtr);
switch (UNIV_EXPECT(err, DB_SUCCESS)) {
case DB_SUCCESS:
@@ -342,6 +381,7 @@ row_purge_remove_sec_if_poss_tree(
func_exit:
btr_pcur_close(&pcur);
+func_exit_no_pcur:
mtr_commit(&mtr);
return(success);
@@ -350,9 +390,10 @@ func_exit:
/***************************************************************
Removes a secondary index entry without modifying the index tree,
if possible.
-@return TRUE if success or if not found */
-static
-ibool
+@retval true if success or if not found
+@retval false if row_purge_remove_sec_if_poss_tree() should be invoked */
+static __attribute__((nonnull, warn_unused_result))
+bool
row_purge_remove_sec_if_poss_leaf(
/*==============================*/
purge_node_t* node, /*!< in: row purge node */
@@ -361,12 +402,40 @@ row_purge_remove_sec_if_poss_leaf(
{
mtr_t mtr;
btr_pcur_t pcur;
+ ulint mode;
enum row_search_result search_result;
+ bool success = true;
log_free_check();
mtr_start(&mtr);
+ if (*index->name == TEMP_INDEX_PREFIX) {
+ /* The index->online_status may change if the
+ index->name starts with TEMP_INDEX_PREFIX (meaning
+ that the index is or was being created online). It is
+ protected by index->lock. */
+ mtr_s_lock(dict_index_get_lock(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_MODIFY_LEAF | BTR_ALREADY_S_LATCHED | BTR_DELETE;
+ } else {
+ /* For secondary indexes,
+ index->online_status==ONLINE_INDEX_CREATION unless
+ index->name starts with TEMP_INDEX_PREFIX. */
+ ut_ad(!dict_index_is_online_ddl(index));
+
+ mode = BTR_MODIFY_LEAF | BTR_DELETE;
+ }
+
/* Set the purge node for the call to row_purge_poss_sec(). */
pcur.btr_cur.purge_node = node;
/* Set the query thread, so that ibuf_insert_low() will be
@@ -374,10 +443,9 @@ row_purge_remove_sec_if_poss_leaf(
pcur.btr_cur.thr = static_cast<que_thr_t*>(que_node_get_parent(node));
search_result = row_search_index_entry(
- index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
+ index, entry, mode, &pcur, &mtr);
switch (search_result) {
- ibool success;
case ROW_FOUND:
/* Before attempting to purge a record, check
if it is safe to do so. */
@@ -390,11 +458,10 @@ row_purge_remove_sec_if_poss_leaf(
btr_cur_get_rec(btr_cur),
dict_table_is_comp(index->table)));
- if (!btr_cur_optimistic_delete(btr_cur, &mtr)) {
+ if (!btr_cur_optimistic_delete(btr_cur, 0, &mtr)) {
/* The index entry could not be deleted. */
- success = FALSE;
- goto func_exit;
+ success = false;
}
}
/* fall through (the index entry is still needed,
@@ -405,9 +472,8 @@ row_purge_remove_sec_if_poss_leaf(
/* The deletion was buffered. */
case ROW_NOT_FOUND:
/* The index entry does not exist, nothing to do. */
- success = TRUE;
- func_exit:
btr_pcur_close(&pcur);
+ func_exit_no_pcur:
mtr_commit(&mtr);
return(success);
}
@@ -418,19 +484,26 @@ row_purge_remove_sec_if_poss_leaf(
/***********************************************************//**
Removes a secondary index entry if possible. */
-UNIV_INLINE
+UNIV_INLINE __attribute__((nonnull(1,2)))
void
row_purge_remove_sec_if_poss(
/*=========================*/
purge_node_t* node, /*!< in: row purge node */
dict_index_t* index, /*!< in: index */
- dtuple_t* entry) /*!< in: index entry */
+ const dtuple_t* entry) /*!< in: index entry */
{
ibool success;
ulint n_tries = 0;
/* fputs("Purge: Removing secondary record\n", stderr); */
+ if (!entry) {
+ /* The node->row must have lacked some fields of this
+ index. This is possible when the undo log record was
+ written before this index was created. */
+ return;
+ }
+
if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
return;
@@ -454,18 +527,18 @@ retry:
}
/***********************************************************//**
-Purges a delete marking of a record. */
-static
-void
+Purges a delete marking of a record.
+@retval true if the row was not found, or it was successfully removed
+@retval false the purge needs to be suspended, either because of
+running out of file space or because the row refers to an off-page
+column and an online ALTER TABLE (table rebuild) is in progress. */
+static __attribute__((nonnull, warn_unused_result))
+bool
row_purge_del_mark(
/*===============*/
- purge_node_t* node) /*!< in: row purge node */
+ purge_node_t* node) /*!< in/out: row purge node */
{
mem_heap_t* heap;
- dtuple_t* entry;
- dict_index_t* index;
-
- ut_ad(node);
heap = mem_heap_create(1024);
@@ -477,13 +550,11 @@ row_purge_del_mark(
break;
}
- index = node->index;
-
if (node->index->type != DICT_FTS) {
- /* Build the index entry */
- entry = row_build_index_entry(node->row, NULL, index, heap);
- ut_a(entry);
- row_purge_remove_sec_if_poss(node, index, entry);
+ dtuple_t* entry = row_build_index_entry_low(
+ node->row, NULL, node->index, heap);
+ row_purge_remove_sec_if_poss(node, node->index, entry);
+ mem_heap_empty(heap);
}
node->index = dict_table_get_next_index(node->index);
@@ -491,14 +562,15 @@ row_purge_del_mark(
mem_heap_free(heap);
- row_purge_remove_clust_if_poss(node);
+ return(row_purge_remove_clust_if_poss(node));
}
/***********************************************************//**
Purges an update of an existing record. Also purges an update of a delete
-marked record if that record contained an externally stored field. */
-static
-void
+marked record if that record contained an externally stored field.
+@return true if purged, false if skipped */
+static __attribute__((nonnull, warn_unused_result))
+bool
row_purge_upd_exist_or_extern_func(
/*===============================*/
#ifdef UNIV_DEBUG
@@ -508,16 +580,24 @@ row_purge_upd_exist_or_extern_func(
trx_undo_rec_t* undo_rec) /*!< in: record to purge */
{
mem_heap_t* heap;
- dtuple_t* entry;
- dict_index_t* index;
- ibool is_insert;
- ulint rseg_id;
- ulint page_no;
- ulint offset;
- ulint i;
- mtr_t mtr;
- ut_ad(node);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED));
+#endif /* UNIV_SYNC_DEBUG */
+
+ if (dict_index_get_online_status(dict_table_get_first_index(
+ node->table))
+ == ONLINE_INDEX_CREATION) {
+ for (ulint i = 0; i < upd_get_n_fields(node->update); i++) {
+
+ const upd_field_t* ufield
+ = upd_get_nth_field(node->update, i);
+
+ if (dfield_is_ext(&ufield->new_val)) {
+ return(false);
+ }
+ }
+ }
if (node->rec_type == TRX_UNDO_UPD_DEL_REC
|| (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
@@ -534,15 +614,13 @@ row_purge_upd_exist_or_extern_func(
break;
}
- index = node->index;
-
if (row_upd_changes_ord_field_binary(node->index, node->update,
thr, NULL, NULL)) {
/* Build the older version of the index entry */
- entry = row_build_index_entry(node->row, NULL,
- index, heap);
- ut_a(entry);
- row_purge_remove_sec_if_poss(node, index, entry);
+ dtuple_t* entry = row_build_index_entry_low(
+ node->row, NULL, node->index, heap);
+ row_purge_remove_sec_if_poss(node, node->index, entry);
+ mem_heap_empty(heap);
}
node->index = dict_table_get_next_index(node->index);
@@ -552,7 +630,7 @@ row_purge_upd_exist_or_extern_func(
skip_secondaries:
/* Free possible externally stored fields */
- for (i = 0; i < upd_get_n_fields(node->update); i++) {
+ for (ulint i = 0; i < upd_get_n_fields(node->update); i++) {
const upd_field_t* ufield
= upd_get_nth_field(node->update, i);
@@ -562,6 +640,12 @@ skip_secondaries:
buf_block_t* block;
ulint internal_offset;
byte* data_field;
+ dict_index_t* index;
+ ibool is_insert;
+ ulint rseg_id;
+ ulint page_no;
+ ulint offset;
+ mtr_t mtr;
/* We use the fact that new_val points to
undo_rec and get thus the offset of
@@ -590,9 +674,17 @@ skip_secondaries:
index tree */
index = dict_table_get_first_index(node->table);
-
mtr_x_lock(dict_index_get_lock(index), &mtr);
-
+#ifdef UNIV_DEBUG
+ switch (dict_index_get_online_status(index)) {
+ case ONLINE_INDEX_CREATION:
+ case ONLINE_INDEX_ABORTED_DROPPED:
+ ut_ad(0);
+ case ONLINE_INDEX_COMPLETE:
+ case ONLINE_INDEX_ABORTED:
+ break;
+ }
+#endif /* UNIV_DEBUG */
/* NOTE: we must also acquire an X-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,
@@ -622,6 +714,8 @@ skip_secondaries:
mtr_commit(&mtr);
}
}
+
+ return(true);
}
#ifdef UNIV_DEBUG
@@ -634,14 +728,14 @@ skip_secondaries:
/***********************************************************//**
Parses the row reference and other info in a modify undo log record.
-@return TRUE if purge operation required */
+@return true if purge operation required */
static
-ibool
+bool
row_purge_parse_undo_rec(
/*=====================*/
purge_node_t* node, /*!< in: row undo node */
trx_undo_rec_t* undo_rec, /*!< in: record to purge */
- ibool* updated_extern, /*!< out: TRUE if an externally
+ bool* updated_extern, /*!< out: true if an externally
stored field was updated */
que_thr_t* thr) /*!< in: query thread */
{
@@ -665,40 +759,29 @@ row_purge_parse_undo_rec(
if (type == TRX_UNDO_UPD_DEL_REC && !*updated_extern) {
- return(FALSE);
+ return(false);
}
ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
&info_bits);
node->table = NULL;
- if (type == TRX_UNDO_UPD_EXIST_REC
- && node->cmpl_info & UPD_NODE_NO_ORD_CHANGE
- && !(*updated_extern)) {
-
- /* Purge requires no changes to indexes: we may return */
-
- return(FALSE);
- }
-
/* Prevent DROP TABLE etc. from running when we are doing the purge
for this row */
- rw_lock_s_lock_func(&dict_operation_lock, 0, __FILE__, __LINE__);
+ rw_lock_s_lock_inline(&dict_operation_lock, 0, __FILE__, __LINE__);
- node->table = dict_table_open_on_id(table_id, FALSE);
+ node->table = dict_table_open_on_id(table_id, FALSE, FALSE);
if (node->table == NULL) {
-err_exit:
/* The table has been dropped: no need to do purge */
- rw_lock_s_unlock_gen(&dict_operation_lock, 0);
- return(FALSE);
+ goto err_exit;
}
if (node->table->ibd_file_missing) {
/* We skip purge of missing .ibd files */
- dict_table_close(node->table, FALSE);
+ dict_table_close(node->table, FALSE, FALSE);
node->table = NULL;
@@ -708,12 +791,22 @@ err_exit:
clust_index = dict_table_get_first_index(node->table);
if (clust_index == NULL) {
+ /* The table was corrupt in the data dictionary.
+ dict_set_corrupted() works on an index, and
+ we do not have an index to call it with. */
+close_exit:
+ dict_table_close(node->table, FALSE, FALSE);
+err_exit:
+ rw_lock_s_unlock(&dict_operation_lock);
+ return(false);
+ }
- dict_table_close(node->table, FALSE);
-
- /* The table was corrupt in the data dictionary */
+ if (type == TRX_UNDO_UPD_EXIST_REC
+ && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)
+ && !*updated_extern) {
- goto err_exit;
+ /* Purge requires no changes to indexes: we may return */
+ goto close_exit;
}
ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
@@ -734,13 +827,14 @@ err_exit:
node->heap);
}
- return(TRUE);
+ return(true);
}
/***********************************************************//**
-Purges the parsed record. */
-static
-void
+Purges the parsed record.
+@return true if purged, false if skipped */
+static __attribute__((nonnull, warn_unused_result))
+bool
row_purge_record_func(
/*==================*/
purge_node_t* node, /*!< in: row purge node */
@@ -748,10 +842,11 @@ row_purge_record_func(
#ifdef UNIV_DEBUG
const que_thr_t*thr, /*!< in: query thread */
#endif /* UNIV_DEBUG */
- ibool updated_extern) /*!< in: TRUE if external columns
+ bool updated_extern) /*!< in: whether external columns
were updated */
{
dict_index_t* clust_index;
+ bool purged = true;
clust_index = dict_table_get_first_index(node->table);
@@ -759,7 +854,10 @@ row_purge_record_func(
switch (node->rec_type) {
case TRX_UNDO_DEL_MARK_REC:
- row_purge_del_mark(node);
+ purged = row_purge_del_mark(node);
+ if (!purged) {
+ break;
+ }
MONITOR_INC(MONITOR_N_DEL_ROW_PURGE);
break;
default:
@@ -768,20 +866,25 @@ row_purge_record_func(
}
/* fall through */
case TRX_UNDO_UPD_EXIST_REC:
- row_purge_upd_exist_or_extern(thr, node, undo_rec);
+ purged = row_purge_upd_exist_or_extern(thr, node, undo_rec);
+ if (!purged) {
+ break;
+ }
MONITOR_INC(MONITOR_N_UPD_EXIST_EXTERN);
break;
}
if (node->found_clust) {
btr_pcur_close(&node->pcur);
+ node->found_clust = FALSE;
}
if (node->table != NULL) {
- dict_table_close(node->table, FALSE);
+ dict_table_close(node->table, FALSE, FALSE);
node->table = NULL;
}
+ return(purged);
}
#ifdef UNIV_DEBUG
@@ -804,18 +907,24 @@ row_purge(
trx_undo_rec_t* undo_rec, /*!< in: record to purge */
que_thr_t* thr) /*!< in: query thread */
{
- ut_ad(node);
- ut_ad(thr);
-
if (undo_rec != &trx_purge_dummy_rec) {
- ibool updated_extern;
+ bool updated_extern;
- if (row_purge_parse_undo_rec(
- node, undo_rec, &updated_extern, thr)) {
+ while (row_purge_parse_undo_rec(
+ node, undo_rec, &updated_extern, thr)) {
- row_purge_record(node, undo_rec, thr, updated_extern);
+ bool purged = row_purge_record(
+ node, undo_rec, thr, updated_extern);
+
+ rw_lock_s_unlock(&dict_operation_lock);
+
+ if (purged
+ || srv_shutdown_state != SRV_SHUTDOWN_NONE) {
+ return;
+ }
- rw_lock_s_unlock_gen(&dict_operation_lock, 0);
+ /* Retry the purge in a second. */
+ os_thread_sleep(1000000);
}
}
}