Commit a0030fcf authored by marko's avatar marko

branches/innodb+: Clean up the buffering of purges. Instead of

traversing the index B-tree twice (first in BTR_WATCH_LEAF mode and
then in BTR_DELETE mode), let BTR_DELETE take care of checking that
the record can be purged, and either buffering or performing the
purge.

row_purge_poss_sec(): New function, to check if it is possible to
purge a secondary index record.  Refactored from
row_purge_remove_sec_if_poss_low().

row_purge_remove_sec_if_poss_nonbuffered(): Rename to
row_purge_remove_sec_if_poss_tree().  Remove the parameter mode
(always use BTR_MODIFY_TREE).  Use row_purge_poss_sec().

row_purge_remove_sec_if_poss_low(): Rename to
row_purge_remove_sec_if_poss_leaf().  Remove the parameter mode
(always use BTR_MODIFY_LEAF). Let row_search_index_entry() do all the
hard work.

btr_cur_t: Add purge_node, which will be needed by
btr_cur_search_to_nth_level() for BTR_DELETE.  Replace the flag value
BTR_CUR_ABORTED with BTR_CUR_DELETE_REF and BTR_CUR_DELETE_FAILED.

enum row_search_result, row_search_index_entry(): Replace
ROW_NOT_IN_POOL with ROW_NOT_DELETED_REF and ROW_NOT_DELETED.

btr_cur_search_to_nth_level(): Remove BTR_WATCH_LEAF.  As a side
effect, the adaptive hash index can be used in purge as well.  If
BTR_DELETE cannot be buffered, attempt btr_cur_optimistic_delete().
Either way, check row_purge_poss_sec().  Move the code to set
cursor->ibuf_count to get rid of another if (height == 0)
check. Eliminate the label loop_end.  Do not call ibuf_should_try()
twice.

ibuf_should_try(): Now that the successful calls to this function will
be halved, halve the magic constant that ibuf_flush_count will be
compared to, accordingly.

The changes regarding ibuf_should_try() were merged from branches/zip
r3515.

rb://60 approved by Heikki over IM
parent f784ab22
...@@ -30,6 +30,7 @@ Created 10/16/1994 Heikki Tuuri ...@@ -30,6 +30,7 @@ Created 10/16/1994 Heikki Tuuri
#include "buf0lru.h" #include "buf0lru.h"
#include "btr0btr.h" #include "btr0btr.h"
#include "btr0sea.h" #include "btr0sea.h"
#include "row0purge.h"
#include "row0upd.h" #include "row0upd.h"
#include "trx0rec.h" #include "trx0rec.h"
#include "trx0roll.h" /* trx_is_recv() */ #include "trx0roll.h" /* trx_is_recv() */
...@@ -331,7 +332,6 @@ btr_cur_search_to_nth_level( ...@@ -331,7 +332,6 @@ btr_cur_search_to_nth_level(
ulint buf_mode; ulint buf_mode;
ulint estimate; ulint estimate;
ulint zip_size; ulint zip_size;
ulint watch_leaf;
page_cur_t* page_cursor; page_cur_t* page_cursor;
ulint ignore_sec_unique; ulint ignore_sec_unique;
btr_op_t btr_op = BTR_NO_OP; btr_op_t btr_op = BTR_NO_OP;
...@@ -370,6 +370,7 @@ btr_cur_search_to_nth_level( ...@@ -370,6 +370,7 @@ btr_cur_search_to_nth_level(
break; break;
case BTR_DELETE: case BTR_DELETE:
btr_op = BTR_DELETE_OP; btr_op = BTR_DELETE_OP;
ut_a(cursor->purge_node);
break; break;
case BTR_DELETE_MARK: case BTR_DELETE_MARK:
btr_op = BTR_DELMARK_OP; btr_op = BTR_DELMARK_OP;
...@@ -385,19 +386,15 @@ btr_cur_search_to_nth_level( ...@@ -385,19 +386,15 @@ btr_cur_search_to_nth_level(
/* Operations on the clustered index cannot be buffered. */ /* Operations on the clustered index cannot be buffered. */
ut_ad(btr_op == BTR_NO_OP || !dict_index_is_clust(index)); ut_ad(btr_op == BTR_NO_OP || !dict_index_is_clust(index));
watch_leaf = latch_mode & BTR_WATCH_LEAF;
estimate = latch_mode & BTR_ESTIMATE; estimate = latch_mode & BTR_ESTIMATE;
ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE; ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE;
/* Turn the flags unrelated to the latch mode off. */ /* Turn the flags unrelated to the latch mode off. */
latch_mode &= ~( latch_mode &= ~(BTR_INSERT
BTR_INSERT | BTR_DELETE_MARK
| BTR_DELETE_MARK | BTR_DELETE
| BTR_DELETE | BTR_ESTIMATE
| BTR_ESTIMATE | BTR_IGNORE_SEC_UNIQUE);
| BTR_IGNORE_SEC_UNIQUE
| BTR_WATCH_LEAF);
cursor->flag = BTR_CUR_BINARY; cursor->flag = BTR_CUR_BINARY;
cursor->index = index; cursor->index = index;
...@@ -417,16 +414,12 @@ btr_cur_search_to_nth_level( ...@@ -417,16 +414,12 @@ btr_cur_search_to_nth_level(
info->n_searches++; info->n_searches++;
#endif #endif
/* TODO: investigate if there is any real reason for forbidding
adaptive hash usage when watch_leaf is true.*/
/* Ibuf does not use adaptive hash; this is prevented by the /* Ibuf does not use adaptive hash; this is prevented by the
latch_mode check below. */ latch_mode check below. */
if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED if (btr_search_latch.writer == RW_LOCK_NOT_LOCKED
&& latch_mode <= BTR_MODIFY_LEAF && latch_mode <= BTR_MODIFY_LEAF
&& info->last_hash_succ && info->last_hash_succ
&& !estimate && !estimate
&& !watch_leaf
#ifdef PAGE_CUR_LE_OR_EXTENDS #ifdef PAGE_CUR_LE_OR_EXTENDS
&& mode != PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS
#endif /* PAGE_CUR_LE_OR_EXTENDS */ #endif /* PAGE_CUR_LE_OR_EXTENDS */
...@@ -486,8 +479,6 @@ btr_cur_search_to_nth_level( ...@@ -486,8 +479,6 @@ btr_cur_search_to_nth_level(
low_bytes = 0; low_bytes = 0;
height = ULINT_UNDEFINED; height = ULINT_UNDEFINED;
rw_latch = RW_NO_LATCH;
buf_mode = BUF_GET;
/* We use these modified search modes on non-leaf levels of the /* We use these modified search modes on non-leaf levels of the
B-tree. These let us end up in the right B-tree leaf. In that leaf B-tree. These let us end up in the right B-tree leaf. In that leaf
...@@ -514,94 +505,111 @@ btr_cur_search_to_nth_level( ...@@ -514,94 +505,111 @@ btr_cur_search_to_nth_level(
/* Loop and search until we arrive at the desired level */ /* Loop and search until we arrive at the desired level */
search_loop: search_loop:
buf_mode = BUF_GET;
rw_latch = RW_NO_LATCH;
if (height == 0) { if (height != 0) {
/* We are about to fetch the root or a non-leaf page. */
} else if (dict_index_is_ibuf(index)) {
/* We're doing a search on an ibuf tree and we're one
level above the leaf page. */
if (watch_leaf) { ulint is_min_rec;
buf_mode = BUF_GET_IF_IN_POOL;
} else if (latch_mode <= BTR_MODIFY_LEAF) { ut_ad(level == 0);
rw_latch = latch_mode;
if (btr_op != BTR_NO_OP is_min_rec = rec_get_info_bits(node_ptr, 0)
&& ibuf_should_try(index, ignore_sec_unique)) { & REC_INFO_MIN_REC_FLAG;
/* Try insert/delete mark/delete to the if (!is_min_rec) {
insert/delete buffer if the page is not in cursor->ibuf_cnt = ibuf_rec_get_counter(node_ptr);
the buffer pool */
buf_mode = BUF_GET_IF_IN_POOL; ut_a(cursor->ibuf_cnt <= 0xFFFF
} || cursor->ibuf_cnt == ULINT_UNDEFINED);
} }
} } else if (latch_mode <= BTR_MODIFY_LEAF) {
rw_latch = latch_mode;
retry_page_get: if (btr_op != BTR_NO_OP
zip_size = dict_table_zip_size(index->table); && ibuf_should_try(index, ignore_sec_unique)) {
if (watch_leaf && height == 0) { /* Try to buffer the operation if the leaf
ut_a(buf_mode == BUF_GET_IF_IN_POOL); page is not in the buffer pool. */
buf_mode = BUF_GET_IF_IN_POOL_OR_WATCH; buf_mode = btr_op == BTR_DELETE_OP
? BUF_GET_IF_IN_POOL_OR_WATCH
: BUF_GET_IF_IN_POOL;
}
} }
zip_size = dict_table_zip_size(index->table);
retry_page_get:
block = buf_page_get_gen( block = buf_page_get_gen(
space, zip_size, page_no, rw_latch, guess, buf_mode, space, zip_size, page_no, rw_latch, guess, buf_mode,
__FILE__, __LINE__, mtr); __FILE__, __LINE__, mtr);
if (block == NULL) { if (block == NULL) {
if (watch_leaf && height == 0) {
/* We didn't find a page but we set a watch on it. */
cursor->flag = BTR_CUR_ABORTED;
goto func_exit;
}
/* This must be a search to perform an insert/delete /* This must be a search to perform an insert/delete
mark/ delete; try using the insert/delete buffer */ mark/ delete; try using the insert/delete buffer */
ut_ad(buf_mode == BUF_GET_IF_IN_POOL); ut_ad(height == 0);
ut_ad(cursor->thr); ut_ad(cursor->thr);
if (ibuf_should_try(index, ignore_sec_unique)) { switch (btr_op) {
case BTR_INSERT_OP:
ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
switch (btr_op) { if (ibuf_insert(IBUF_OP_INSERT, tuple, index,
case BTR_INSERT_OP: space, zip_size, page_no,
if (ibuf_insert(IBUF_OP_INSERT, tuple, index, cursor->thr)) {
space, zip_size, page_no,
cursor->thr)) {
cursor->flag = BTR_CUR_INSERT_TO_IBUF; cursor->flag = BTR_CUR_INSERT_TO_IBUF;
goto func_exit; goto func_exit;
} }
break; break;
case BTR_DELMARK_OP: case BTR_DELMARK_OP:
if (ibuf_insert(IBUF_OP_DELETE_MARK, tuple, ut_ad(buf_mode == BUF_GET_IF_IN_POOL);
index, space, zip_size,
page_no, cursor->thr)) {
cursor->flag = BTR_CUR_DEL_MARK_IBUF; if (ibuf_insert(IBUF_OP_DELETE_MARK, tuple,
index, space, zip_size,
page_no, cursor->thr)) {
goto func_exit; cursor->flag = BTR_CUR_DEL_MARK_IBUF;
}
break; goto func_exit;
}
case BTR_DELETE_OP: break;
if (ibuf_insert(IBUF_OP_DELETE, tuple, index,
space, zip_size, page_no,
cursor->thr)) {
cursor->flag = BTR_CUR_DELETE_IBUF; case BTR_DELETE_OP:
ut_ad(buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH);
goto func_exit; if (!row_purge_poss_sec(cursor->purge_node,
} index, tuple)) {
/* The record cannot be purged yet. */
cursor->flag = BTR_CUR_DELETE_REF;
} else if (ibuf_insert(IBUF_OP_DELETE, tuple,
index, space, zip_size,
page_no,
cursor->thr)) {
/* The purge was buffered. */
cursor->flag = BTR_CUR_DELETE_IBUF;
} else {
/* The purge could not be buffered. */
buf_pool_watch_clear();
break; break;
default:
ut_error;
} }
buf_pool_watch_clear();
goto func_exit;
default:
ut_error;
} }
/* Insert to the insert/delete buffer did not succeed, we /* Insert to the insert/delete buffer did not succeed, we
...@@ -678,46 +686,24 @@ btr_cur_search_to_nth_level( ...@@ -678,46 +686,24 @@ btr_cur_search_to_nth_level(
ut_ad(height == btr_page_get_level(page_cur_get_page(page_cursor), ut_ad(height == btr_page_get_level(page_cur_get_page(page_cursor),
mtr)); mtr));
if (level == height) { if (level != height) {
goto loop_end;
}
ut_ad(height > 0); ut_ad(height > 0);
height--;
guess = NULL;
node_ptr = page_cur_get_rec(page_cursor);
if (height == 0 && dict_index_is_ibuf(index)) {
/* We're doing a search on an ibuf tree and we're one level
above the leaf page. */
ulint is_min_rec; height--;
guess = NULL;
ut_ad(level == 0); node_ptr = page_cur_get_rec(page_cursor);
is_min_rec = rec_get_info_bits(node_ptr, 0) offsets = rec_get_offsets(
& REC_INFO_MIN_REC_FLAG; node_ptr, index, offsets, ULINT_UNDEFINED, &heap);
if (!is_min_rec) { /* Go to the child node */
cursor->ibuf_cnt = ibuf_rec_get_counter(node_ptr); page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
ut_a(cursor->ibuf_cnt <= 0xFFFF goto search_loop;
|| cursor->ibuf_cnt == ULINT_UNDEFINED);
}
} }
offsets = rec_get_offsets(
node_ptr, index, offsets, ULINT_UNDEFINED, &heap);
/* Go to the child node */
page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets);
goto search_loop;
loop_end:
if (level != 0) { if (level != 0) {
/* x-latch the page */ /* x-latch the page */
page = btr_page_get( page = btr_page_get(
...@@ -743,6 +729,35 @@ btr_cur_search_to_nth_level( ...@@ -743,6 +729,35 @@ btr_cur_search_to_nth_level(
|| mode != PAGE_CUR_LE); || mode != PAGE_CUR_LE);
ut_ad(cursor->low_match != ULINT_UNDEFINED ut_ad(cursor->low_match != ULINT_UNDEFINED
|| mode != PAGE_CUR_LE); || mode != PAGE_CUR_LE);
/* If this was a delete operation, the leaf page was
in the buffer pool, and a matching record was found in
the leaf page, attempt to delete it. If the deletion
fails, set the cursor flag accordingly. */
if (UNIV_UNLIKELY(btr_op == BTR_DELETE_OP)
&& low_match == dtuple_get_n_fields(tuple)
&& !page_cur_is_before_first(page_cursor)) {
/* Before attempting to purge a record, check
if it is safe to do so. */
if (!row_purge_poss_sec(cursor->purge_node,
index, tuple)) {
cursor->flag = BTR_CUR_DELETE_REF;
} else {
/* Only delete-marked records should
be purged. */
ut_ad(REC_INFO_DELETED_FLAG
& rec_get_info_bits(
btr_cur_get_rec(cursor),
page_is_comp(page)));
if (!btr_cur_optimistic_delete(cursor, mtr)) {
cursor->flag = BTR_CUR_DELETE_FAILED;
}
}
}
} }
func_exit: func_exit:
......
...@@ -65,11 +65,6 @@ insert/delete buffer. */ ...@@ -65,11 +65,6 @@ insert/delete buffer. */
buffer. */ buffer. */
#define BTR_DELETE 8192 #define BTR_DELETE 8192
/* If the leaf page is not in the buffer pool: don't read it in, set
cursor->flag = BTR_CUR_ABORTED, and set buf_pool_t::watch_* that
watches for the page to get read in. */
#define BTR_WATCH_LEAF 16384
/****************************************************************** /******************************************************************
Gets the root node of a tree and x-latches it. */ Gets the root node of a tree and x-latches it. */
UNIV_INTERN UNIV_INTERN
......
...@@ -601,6 +601,7 @@ to know struct size! */ ...@@ -601,6 +601,7 @@ to know struct size! */
struct btr_cur_struct { struct btr_cur_struct {
dict_index_t* index; /* index where positioned */ dict_index_t* index; /* index where positioned */
page_cur_t page_cur; /* page cursor */ page_cur_t page_cur; /* page cursor */
purge_node_t* purge_node; /* purge node, for BTR_DELETE */
buf_block_t* left_block; /* this field is used to store buf_block_t* left_block; /* this field is used to store
a pointer to the left neighbor a pointer to the left neighbor
page, in the cases page, in the cases
...@@ -696,9 +697,9 @@ struct btr_cur_struct { ...@@ -696,9 +697,9 @@ struct btr_cur_struct {
mark in the insert/delete buffer */ mark in the insert/delete buffer */
#define BTR_CUR_DELETE_IBUF 6 /* performed the intended delete in #define BTR_CUR_DELETE_IBUF 6 /* performed the intended delete in
the insert/delete buffer */ the insert/delete buffer */
#define BTR_CUR_ABORTED 7 /* search with BTR_CHECK_LEAF #define BTR_CUR_DELETE_REF 7 /* row_purge_poss_sec() failed */
aborted due to leaf page not being #define BTR_CUR_DELETE_FAILED 8 /* an optimistic delete could not
in buffer pool */ be performed */
/* If pessimistic delete fails because of lack of file space, /* If pessimistic delete fails because of lack of file space,
there is still a good change of success a little later: try this many times, there is still a good change of success a little later: try this many times,
......
...@@ -89,7 +89,7 @@ ibuf_should_try( ...@@ -89,7 +89,7 @@ ibuf_should_try(
ibuf_flush_count++; ibuf_flush_count++;
if (ibuf_flush_count % 8 == 0) { if (ibuf_flush_count % 4 == 0) {
buf_LRU_try_free_flushed_blocks(); buf_LRU_try_free_flushed_blocks();
} }
......
...@@ -28,6 +28,29 @@ row_purge_node_create( ...@@ -28,6 +28,29 @@ row_purge_node_create(
que_thr_t* parent, /* in: parent node, i.e., a thr node */ que_thr_t* parent, /* in: parent node, i.e., a thr node */
mem_heap_t* heap); /* in: memory heap where created */ mem_heap_t* heap); /* in: memory heap where created */
/*************************************************************** /***************************************************************
Determines if it is possible to remove a secondary index entry.
Removal is possible if the secondary index entry does not refer to any
not delete marked version of a clustered index record where DB_TRX_ID
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
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. */
UNIV_INTERN
ibool
row_purge_poss_sec(
/*===============*/
/* out: TRUE if the secondary index
record can be purged */
purge_node_t* node, /* in/out: row purge node */
dict_index_t* index, /* in: secondary index */
const dtuple_t* entry); /* in: secondary index entry */
/***************************************************************
Does the purge operation for a single undo log record. This is a high-level Does the purge operation for a single undo log record. This is a high-level
function used in an SQL execution graph. */ function used in an SQL execution graph. */
UNIV_INTERN UNIV_INTERN
......
...@@ -271,8 +271,10 @@ enum row_search_result { ...@@ -271,8 +271,10 @@ enum row_search_result {
secondary index leaf page was not in secondary index leaf page was not in
the buffer pool, and the operation was the buffer pool, and the operation was
enqueued in the insert/delete buffer */ enqueued in the insert/delete buffer */
ROW_NOT_IN_POOL /* BTR_WATCH_LEAF was specified and the ROW_NOT_DELETED_REF, /* BTR_DELETE was specified, and
record was not in the buffer pool */ row_purge_poss_sec() failed */
ROW_NOT_DELETED, /* BTR_DELETE was specified, and the
optimistic delete failed */
}; };
/******************************************************************* /*******************************************************************
......
...@@ -198,34 +198,68 @@ row_purge_remove_clust_if_poss( ...@@ -198,34 +198,68 @@ row_purge_remove_clust_if_poss(
} }
/*************************************************************** /***************************************************************
Removes a secondary index entry if possible, without trying to use the Determines if it is possible to remove a secondary index entry.
insert/delete buffer. */ Removal is possible if the secondary index entry does not refer to any
not delete marked version of a clustered index record where DB_TRX_ID
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
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. */
UNIV_INTERN
ibool
row_purge_poss_sec(
/*===============*/
/* out: TRUE if the secondary index
record can be purged */
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;
mtr_t mtr;
ut_ad(!dict_index_is_clust(index));
mtr_start(&mtr);
can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)
|| !row_vers_old_has_index_entry(TRUE,
btr_pcur_get_rec(&node->pcur),
&mtr, index, entry);
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
return(can_delete);
}
/***************************************************************
Removes a secondary index entry if possible, by modifying the
index tree. Does not try to buffer the delete. */
static static
ibool ibool
row_purge_remove_sec_if_poss_low_nonbuffered( row_purge_remove_sec_if_poss_tree(
/*=========================================*/ /*==============================*/
/* out: TRUE if success or if not found */ /* out: TRUE if success or if not found */
purge_node_t* node, /* in: row purge node */ purge_node_t* node, /* in: row purge node */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
const dtuple_t* entry, /* in: index entry */ const dtuple_t* entry) /* in: index entry */
ulint mode) /* in: latch mode BTR_MODIFY_LEAF or
BTR_MODIFY_TREE */
{ {
btr_pcur_t pcur; btr_pcur_t pcur;
btr_cur_t* btr_cur; btr_cur_t* btr_cur;
ibool success; ibool success = TRUE;
ibool old_has = FALSE;
ulint err; ulint err;
mtr_t mtr; mtr_t mtr;
mtr_t mtr_vers;
enum row_search_result search_result; enum row_search_result search_result;
log_free_check(); log_free_check();
mtr_start(&mtr); mtr_start(&mtr);
ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE,
search_result = row_search_index_entry(index, entry, mode,
&pcur, &mtr); &pcur, &mtr);
switch (search_result) { switch (search_result) {
...@@ -242,17 +276,15 @@ row_purge_remove_sec_if_poss_low_nonbuffered( ...@@ -242,17 +276,15 @@ row_purge_remove_sec_if_poss_low_nonbuffered(
/* fputs("PURGE:........sec entry not found\n", stderr); */ /* fputs("PURGE:........sec entry not found\n", stderr); */
/* dtuple_print(stderr, entry); */ /* dtuple_print(stderr, entry); */
success = TRUE;
goto func_exit; goto func_exit;
case ROW_FOUND: case ROW_FOUND:
break; break;
case ROW_BUFFERED: case ROW_BUFFERED:
case ROW_NOT_IN_POOL: case ROW_NOT_DELETED_REF:
case ROW_NOT_DELETED:
/* These are invalid outcomes, because the mode passed /* These are invalid outcomes, because the mode passed
to row_search_index_entry() did not include any of the to row_search_index_entry() did not include any of the
flags BTR_INSERT, BTR_DELETE, BTR_DELETE_MARK, or flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
BTR_WATCH_LEAF. */
ut_error; ut_error;
} }
...@@ -262,33 +294,23 @@ row_purge_remove_sec_if_poss_low_nonbuffered( ...@@ -262,33 +294,23 @@ row_purge_remove_sec_if_poss_low_nonbuffered(
which cannot be purged yet, requires its existence. If some requires, which cannot be purged yet, requires its existence. If some requires,
we should do nothing. */ we should do nothing. */
mtr_start(&mtr_vers); if (row_purge_poss_sec(node, index, entry)) {
success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr_vers);
if (success) {
old_has = row_vers_old_has_index_entry(
TRUE, btr_pcur_get_rec(&(node->pcur)),
&mtr_vers, index, entry);
}
btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers);
if (!old_has) {
/* Remove the index record, which should have been /* Remove the index record, which should have been
marked for deletion. */ marked for deletion. */
ut_ad(REC_INFO_DELETED_FLAG ut_ad(REC_INFO_DELETED_FLAG
& rec_get_info_bits(btr_cur_get_rec(btr_cur), & rec_get_info_bits(btr_cur_get_rec(btr_cur),
dict_table_is_comp(index->table))); dict_table_is_comp(index->table)));
if (mode == BTR_MODIFY_LEAF) { btr_cur_pessimistic_delete(&err, FALSE, btr_cur,
success = btr_cur_optimistic_delete(btr_cur, &mtr); RB_NONE, &mtr);
} else { switch (UNIV_EXPECT(err, DB_SUCCESS)) {
ut_ad(mode == BTR_MODIFY_TREE); case DB_SUCCESS:
btr_cur_pessimistic_delete(&err, FALSE, btr_cur, break;
RB_NONE, &mtr); case DB_OUT_OF_FILE_SPACE:
success = err == DB_SUCCESS; success = FALSE;
ut_a(success || err == DB_OUT_OF_FILE_SPACE); break;
default:
ut_error;
} }
} }
...@@ -300,88 +322,30 @@ row_purge_remove_sec_if_poss_low_nonbuffered( ...@@ -300,88 +322,30 @@ row_purge_remove_sec_if_poss_low_nonbuffered(
} }
/*************************************************************** /***************************************************************
Removes a secondary index entry if possible. */ Removes a secondary index entry without modifying the index tree,
if possible. */
static static
ibool ibool
row_purge_remove_sec_if_poss_low( row_purge_remove_sec_if_poss_leaf(
/*=============================*/ /*==============================*/
/* out: TRUE if success or if not found */ /* out: TRUE if success or if not found */
purge_node_t* node, /* in: row purge node */ purge_node_t* node, /* in: row purge node */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
const dtuple_t* entry, /* in: index entry */ const dtuple_t* entry) /* in: index entry */
ulint mode) /* in: latch mode BTR_MODIFY_LEAF or
BTR_MODIFY_TREE */
{ {
mtr_t mtr; mtr_t mtr;
btr_pcur_t pcur; btr_pcur_t pcur;
ibool old_has = FALSE;
enum row_search_result search_result; enum row_search_result search_result;
if (mode == BTR_MODIFY_TREE) {
/* Can't use the insert/delete buffer if we potentially
need to split pages. */
goto unbuffered;
}
ut_ad(mode == BTR_MODIFY_LEAF);
log_free_check(); log_free_check();
mtr_start(&mtr); mtr_start(&mtr);
search_result = row_search_index_entry( /* Set the purge node for the call to row_purge_poss_sec(). */
index, entry, BTR_SEARCH_LEAF | BTR_WATCH_LEAF, &pcur, &mtr); pcur.btr_cur.purge_node = node;
btr_pcur_close(&pcur);
mtr_commit(&mtr);
switch (search_result) {
case ROW_NOT_FOUND:
/* Index entry does not exist, nothing to do. */
return(TRUE);
case ROW_FOUND:
/* The index entry exists and is in the buffer pool;
no need to use the insert/delete buffer. */
goto unbuffered;
case ROW_BUFFERED:
/* We did not pass any BTR_INSERT, BTR_DELETE, or
BTR_DELETE_MARK flag. Therefore, the operation must
not have been buffered yet. */
ut_error;
case ROW_NOT_IN_POOL:
break;
}
/* We should remove the index record if no later version of
the row, which cannot be purged yet, requires its existence.
If some requires, we should do nothing. */
mtr_start(&mtr);
if (row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr)) {
old_has = row_vers_old_has_index_entry(
TRUE, btr_pcur_get_rec(&node->pcur),
&mtr, index, entry);
}
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
if (old_has) {
/* Can't remove the index record yet. */
buf_pool_watch_clear();
return(TRUE);
}
mtr_start(&mtr);
/* Set the query thread, so that ibuf_insert_low() will be /* Set the query thread, so that ibuf_insert_low() will be
able to invoke thd_get_trx(). */ able to invoke thd_get_trx(). */
btr_pcur_get_btr_cur(&pcur)->thr = que_node_get_parent(node); pcur.btr_cur.thr = que_node_get_parent(node);
search_result = row_search_index_entry( search_result = row_search_index_entry(
index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr); index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr);
...@@ -389,31 +353,25 @@ row_purge_remove_sec_if_poss_low( ...@@ -389,31 +353,25 @@ row_purge_remove_sec_if_poss_low(
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
buf_pool_watch_clear();
switch (search_result) { switch (search_result) {
case ROW_NOT_DELETED:
/* The index entry could not be deleted. */
return(FALSE);
case ROW_NOT_DELETED_REF:
/* The index entry is still needed. */
case ROW_NOT_FOUND: case ROW_NOT_FOUND:
/* Index entry does not exist, nothing to do. */ /* The index entry does not exist, nothing to do. */
return(TRUE);
case ROW_FOUND: case ROW_FOUND:
/* The index entry exists and is in the buffer pool; /* The index entry existed in the buffer pool
no need to use the insert/delete buffer. */ and was deleted because of the BTR_DELETE. */
break;
case ROW_BUFFERED: case ROW_BUFFERED:
/* The deletion was buffered. */
return(TRUE); return(TRUE);
case ROW_NOT_IN_POOL:
/* BTR_WATCH_LEAF was not specified,
so this should not occur! */
ut_error;
} }
/* Page read into buffer pool or delete-buffering failed. */ ut_error;
return(FALSE);
unbuffered:
return(row_purge_remove_sec_if_poss_low_nonbuffered(node, index,
entry, mode));
} }
/*************************************************************** /***************************************************************
...@@ -431,15 +389,12 @@ row_purge_remove_sec_if_poss( ...@@ -431,15 +389,12 @@ row_purge_remove_sec_if_poss(
/* fputs("Purge: Removing secondary record\n", stderr); */ /* fputs("Purge: Removing secondary record\n", stderr); */
success = row_purge_remove_sec_if_poss_low(node, index, entry, if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) {
BTR_MODIFY_LEAF);
if (success) {
return; return;
} }
retry: retry:
success = row_purge_remove_sec_if_poss_low(node, index, entry, success = row_purge_remove_sec_if_poss_tree(node, index, entry);
BTR_MODIFY_TREE);
/* The delete operation may fail if we have little /* The delete operation may fail if we have little
file space left: TODO: easiest to crash the database file space left: TODO: easiest to crash the database
and restart with more file space */ and restart with more file space */
......
...@@ -802,11 +802,13 @@ row_search_index_entry( ...@@ -802,11 +802,13 @@ row_search_index_entry(
btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr); btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr);
switch (btr_pcur_get_btr_cur(pcur)->flag) { switch (btr_pcur_get_btr_cur(pcur)->flag) {
case BTR_CUR_ABORTED: case BTR_CUR_DELETE_REF:
/* We did not read in the leaf page, thus we can't have ut_a(mode & BTR_DELETE);
found anything. */ return(ROW_NOT_DELETED_REF);
ut_a(mode & BTR_WATCH_LEAF);
return(ROW_NOT_IN_POOL); case BTR_CUR_DELETE_FAILED:
ut_a(mode & BTR_DELETE);
return(ROW_NOT_DELETED);
case BTR_CUR_DEL_MARK_IBUF: case BTR_CUR_DEL_MARK_IBUF:
case BTR_CUR_DELETE_IBUF: case BTR_CUR_DELETE_IBUF:
......
...@@ -152,11 +152,11 @@ row_undo_ins_remove_sec_low( ...@@ -152,11 +152,11 @@ row_undo_ins_remove_sec_low(
case ROW_FOUND: case ROW_FOUND:
break; break;
case ROW_BUFFERED: case ROW_BUFFERED:
case ROW_NOT_IN_POOL: case ROW_NOT_DELETED:
case ROW_NOT_DELETED_REF:
/* These are invalid outcomes, because the mode passed /* These are invalid outcomes, because the mode passed
to row_search_index_entry() did not include any of the to row_search_index_entry() did not include any of the
flags BTR_INSERT, BTR_DELETE, BTR_DELETE_MARK, or flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
BTR_WATCH_LEAF. */
ut_error; ut_error;
} }
......
...@@ -331,11 +331,11 @@ row_undo_mod_del_mark_or_remove_sec_low( ...@@ -331,11 +331,11 @@ row_undo_mod_del_mark_or_remove_sec_low(
case ROW_FOUND: case ROW_FOUND:
break; break;
case ROW_BUFFERED: case ROW_BUFFERED:
case ROW_NOT_IN_POOL: case ROW_NOT_DELETED:
case ROW_NOT_DELETED_REF:
/* These are invalid outcomes, because the mode passed /* These are invalid outcomes, because the mode passed
to row_search_index_entry() did not include any of the to row_search_index_entry() did not include any of the
flags BTR_INSERT, BTR_DELETE, BTR_DELETE_MARK, or flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
BTR_WATCH_LEAF. */
ut_error; ut_error;
} }
...@@ -468,11 +468,11 @@ row_undo_mod_del_unmark_sec_and_undo_update( ...@@ -468,11 +468,11 @@ row_undo_mod_del_unmark_sec_and_undo_update(
switch (search_result) { switch (search_result) {
case ROW_BUFFERED: case ROW_BUFFERED:
case ROW_NOT_IN_POOL: case ROW_NOT_DELETED:
case ROW_NOT_DELETED_REF:
/* These are invalid outcomes, because the mode passed /* These are invalid outcomes, because the mode passed
to row_search_index_entry() did not include any of the to row_search_index_entry() did not include any of the
flags BTR_INSERT, BTR_DELETE, BTR_DELETE_MARK, or flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */
BTR_WATCH_LEAF. */
ut_error; ut_error;
case ROW_NOT_FOUND: case ROW_NOT_FOUND:
fputs("InnoDB: error in sec index entry del undo in\n" fputs("InnoDB: error in sec index entry del undo in\n"
......
...@@ -1454,8 +1454,8 @@ row_upd_sec_index_entry( ...@@ -1454,8 +1454,8 @@ row_upd_sec_index_entry(
rec = btr_cur_get_rec(btr_cur); rec = btr_cur_get_rec(btr_cur);
switch (search_result) { switch (search_result) {
case ROW_NOT_IN_POOL: case ROW_NOT_DELETED: /* should only occur for BTR_DELETE */
/* This should only occur for BTR_WATCH_LEAF. */ case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */
ut_error; ut_error;
break; break;
case ROW_BUFFERED: case ROW_BUFFERED:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment