MDEV-12353 preparation: Clean up page_cur_delete_rec()
page_cur_delete_rec(): Do not tolerate mtr=NULL. page_delete_rec(): Merge with the only caller, RecIterator::remove(). RecIterator::m_mtr: New data member: a dummy mini-transaction.
This commit is contained in:
parent
1c282d4bc4
commit
befde6e97e
@ -27,12 +27,7 @@ Created 10/4/1994 Heikki Tuuri
|
||||
#ifndef page0cur_h
|
||||
#define page0cur_h
|
||||
|
||||
#include "buf0types.h"
|
||||
#include "page0page.h"
|
||||
#include "rem0rec.h"
|
||||
#include "data0data.h"
|
||||
#include "mtr0mtr.h"
|
||||
#include "gis0type.h"
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/*********************************************************//**
|
||||
@ -240,7 +235,8 @@ page_cur_delete_rec(
|
||||
const dict_index_t* index, /*!< in: record descriptor */
|
||||
const ulint* offsets,/*!< in: rec_get_offsets(
|
||||
cursor->rec, index) */
|
||||
mtr_t* mtr); /*!< in: mini-transaction handle */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
/** Search the right position for a page cursor.
|
||||
@param[in] block buffer block
|
||||
@ -373,20 +369,9 @@ page_cur_parse_delete_rec(
|
||||
const byte* end_ptr,/*!< in: buffer end */
|
||||
buf_block_t* block, /*!< in: page or NULL */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
mtr_t* mtr); /*!< in: mtr or NULL */
|
||||
/*******************************************************//**
|
||||
Removes the record from a leaf page. This function does not log
|
||||
any changes. It is used by the IMPORT tablespace functions.
|
||||
@return true if success, i.e., the page did not become too empty */
|
||||
bool
|
||||
page_delete_rec(
|
||||
/*============*/
|
||||
const dict_index_t* index, /*!< in: The index that the record
|
||||
belongs to */
|
||||
page_cur_t* pcur, /*!< in/out: page cursor on record
|
||||
to delete */
|
||||
page_zip_des_t* page_zip,/*!< in: compressed page descriptor */
|
||||
const ulint* offsets);/*!< in: offsets for record */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction,
|
||||
or NULL if block=NULL */
|
||||
MY_ATTRIBUTE((warn_unused_result, nonnull(1,2,4)));
|
||||
|
||||
/** Index page cursor */
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2019, 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
|
||||
@ -163,27 +164,5 @@ page_zip_rec_set_owned(
|
||||
const byte* rec, /*!< in: record on the uncompressed page */
|
||||
ulint flag) /*!< in: the owned flag (nonzero=TRUE) */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
|
||||
/**********************************************************************//**
|
||||
Shift the dense page directory when a record is deleted. */
|
||||
void
|
||||
page_zip_dir_delete(
|
||||
/*================*/
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page */
|
||||
byte* rec, /*!< in: deleted record */
|
||||
dict_index_t* index, /*!< in: index of rec */
|
||||
const ulint* offsets,/*!< in: rec_get_offsets(rec) */
|
||||
const byte* free) /*!< in: previous start of the free list */
|
||||
MY_ATTRIBUTE((nonnull(1,2,3,4)));
|
||||
|
||||
/**********************************************************************//**
|
||||
Add a slot to the dense page directory. */
|
||||
void
|
||||
page_zip_dir_add_slot(
|
||||
/*==================*/
|
||||
page_zip_des_t* page_zip, /*!< in/out: compressed page */
|
||||
ulint is_clustered) /*!< in: nonzero for clustered index,
|
||||
zero for others */
|
||||
MY_ATTRIBUTE((nonnull));
|
||||
#endif /* !UNIV_INNOCHECKSUM */
|
||||
#endif
|
||||
|
@ -2371,11 +2371,14 @@ page_cur_parse_delete_rec(
|
||||
const byte* end_ptr,/*!< in: buffer end */
|
||||
buf_block_t* block, /*!< in: page or NULL */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
mtr_t* mtr) /*!< in: mtr or NULL */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction,
|
||||
or NULL if block=NULL */
|
||||
{
|
||||
ulint offset;
|
||||
page_cur_t cursor;
|
||||
|
||||
ut_ad(!block == !mtr);
|
||||
|
||||
if (end_ptr < ptr + 2) {
|
||||
|
||||
return(NULL);
|
||||
@ -2453,13 +2456,10 @@ page_cur_delete_rec(
|
||||
const dict_index_t* index, /*!< in: record descriptor */
|
||||
const ulint* offsets,/*!< in: rec_get_offsets(
|
||||
cursor->rec, index) */
|
||||
mtr_t* mtr) /*!< in: mini-transaction handle
|
||||
or NULL */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
page_dir_slot_t* cur_dir_slot;
|
||||
page_dir_slot_t* prev_slot;
|
||||
page_t* page;
|
||||
page_zip_des_t* page_zip;
|
||||
rec_t* current_rec;
|
||||
rec_t* prev_rec = NULL;
|
||||
rec_t* next_rec;
|
||||
@ -2467,36 +2467,36 @@ page_cur_delete_rec(
|
||||
ulint cur_n_owned;
|
||||
rec_t* rec;
|
||||
|
||||
page = page_cur_get_page(cursor);
|
||||
page_zip = page_cur_get_page_zip(cursor);
|
||||
|
||||
/* page_zip_validate() will fail here when
|
||||
btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark().
|
||||
Then, both "page_zip" and "page" would have the min-rec-mark
|
||||
set on the smallest user record, but "page" would additionally
|
||||
Then, both "page_zip" and "block->frame" would have the min-rec-mark
|
||||
set on the smallest user record, but "block->frame" would additionally
|
||||
have it set on the smallest-but-one record. Because sloppy
|
||||
page_zip_validate_low() only ignores min-rec-flag differences
|
||||
in the smallest user record, it cannot be used here either. */
|
||||
|
||||
current_rec = cursor->rec;
|
||||
buf_block_t* const block = cursor->block;
|
||||
ut_ad(rec_offs_validate(current_rec, index, offsets));
|
||||
ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
|
||||
ut_ad(fil_page_index_page_check(page));
|
||||
ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) == index->id
|
||||
ut_ad(!!page_is_comp(block->frame) == index->table->not_redundant());
|
||||
ut_ad(fil_page_index_page_check(block->frame));
|
||||
ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + block->frame)
|
||||
== index->id
|
||||
|| index->is_dummy
|
||||
|| (mtr ? mtr->is_inside_ibuf() : dict_index_is_ibuf(index)));
|
||||
ut_ad(!mtr || mtr->is_named_space(index->table->space));
|
||||
|| mtr->is_inside_ibuf());
|
||||
ut_ad(mtr->is_named_space(index->table->space));
|
||||
|
||||
/* The record must not be the supremum or infimum record. */
|
||||
ut_ad(page_rec_is_user_rec(current_rec));
|
||||
|
||||
if (page_get_n_recs(page) == 1 && !recv_recovery_is_on()
|
||||
if (page_get_n_recs(block->frame) == 1
|
||||
&& !recv_recovery_is_on()
|
||||
&& !rec_is_alter_metadata(current_rec, *index)) {
|
||||
/* Empty the page, unless we are applying the redo log
|
||||
during crash recovery. During normal operation, the
|
||||
page_create_empty() gets logged as one of MLOG_PAGE_CREATE,
|
||||
MLOG_COMP_PAGE_CREATE, MLOG_ZIP_PAGE_COMPRESS. */
|
||||
ut_ad(page_is_leaf(page));
|
||||
ut_ad(page_is_leaf(block->frame));
|
||||
/* Usually, this should be the root page,
|
||||
and the whole index tree should become empty.
|
||||
However, this could also be a call in
|
||||
@ -2512,21 +2512,21 @@ page_cur_delete_rec(
|
||||
/* Save to local variables some data associated with current_rec */
|
||||
cur_slot_no = page_dir_find_owner_slot(current_rec);
|
||||
ut_ad(cur_slot_no > 0);
|
||||
cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
|
||||
cur_dir_slot = page_dir_get_nth_slot(block->frame, cur_slot_no);
|
||||
cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
|
||||
|
||||
/* 1. Reset the last insert info in the page header and increment
|
||||
the modify clock for the frame */
|
||||
|
||||
page_header_set_ptr(page, page_zip, PAGE_LAST_INSERT, NULL);
|
||||
page_zip_des_t* const page_zip = buf_block_get_page_zip(block);
|
||||
|
||||
/* The page gets invalid for optimistic searches: increment the
|
||||
frame modify clock only if there is an mini-transaction covering
|
||||
the change. During IMPORT we allocate local blocks that are not
|
||||
part of the buffer pool. */
|
||||
page_header_set_ptr(block->frame, page_zip, PAGE_LAST_INSERT, NULL);
|
||||
|
||||
if (mtr != 0) {
|
||||
buf_block_modify_clock_inc(page_cur_get_block(cursor));
|
||||
/* The page gets invalid for optimistic searches: increment
|
||||
the frame modify clock. Avoid this during IMPORT; the block is
|
||||
not actually in the buffer pool. */
|
||||
if (mtr->get_log_mode() != MTR_LOG_NONE) {
|
||||
buf_block_modify_clock_inc(block);
|
||||
page_cur_delete_rec_write_log(current_rec, index, mtr);
|
||||
}
|
||||
|
||||
@ -2534,9 +2534,9 @@ page_cur_delete_rec(
|
||||
left at the next record. */
|
||||
|
||||
ut_ad(cur_slot_no > 0);
|
||||
prev_slot = page_dir_get_nth_slot(page, cur_slot_no - 1);
|
||||
prev_slot = page_dir_get_nth_slot(block->frame, cur_slot_no - 1);
|
||||
|
||||
rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
|
||||
rec = const_cast<rec_t*>(page_dir_slot_get_rec(prev_slot));
|
||||
|
||||
/* rec now points to the record of the previous directory slot. Look
|
||||
for the immediate predecessor of current_rec in a loop. */
|
||||
@ -2570,14 +2570,14 @@ page_cur_delete_rec(
|
||||
page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
|
||||
|
||||
/* 6. Free the memory occupied by the record */
|
||||
page_mem_free(page, page_zip, current_rec, index, offsets);
|
||||
page_mem_free(block->frame, page_zip, current_rec, index, offsets);
|
||||
|
||||
/* 7. Now we have decremented the number of owned records of the slot.
|
||||
If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
|
||||
slots. */
|
||||
|
||||
if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) {
|
||||
page_dir_balance_slot(page, page_zip, cur_slot_no);
|
||||
page_dir_balance_slot(block->frame, page_zip, cur_slot_no);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2549,62 +2549,6 @@ page_find_rec_with_heap_no(
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************//**
|
||||
Removes the record from a leaf page. This function does not log
|
||||
any changes. It is used by the IMPORT tablespace functions.
|
||||
The cursor is moved to the next record after the deleted one.
|
||||
@return true if success, i.e., the page did not become too empty */
|
||||
bool
|
||||
page_delete_rec(
|
||||
/*============*/
|
||||
const dict_index_t* index, /*!< in: The index that the record
|
||||
belongs to */
|
||||
page_cur_t* pcur, /*!< in/out: page cursor on record
|
||||
to delete */
|
||||
page_zip_des_t*
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
page_zip/*!< in: compressed page descriptor */
|
||||
#endif
|
||||
,
|
||||
const ulint* offsets)/*!< in: offsets for record */
|
||||
{
|
||||
bool no_compress_needed;
|
||||
buf_block_t* block = pcur->block;
|
||||
page_t* page = buf_block_get_frame(block);
|
||||
|
||||
ut_ad(page_is_leaf(page));
|
||||
|
||||
if (!rec_offs_any_extern(offsets)
|
||||
&& (!page_has_siblings(page)
|
||||
|| (page_get_n_recs(page) < 2)
|
||||
|| page_get_data_size(page) - rec_offs_size(offsets)
|
||||
< BTR_CUR_PAGE_COMPRESS_LIMIT(index))) {
|
||||
|
||||
/* The page fillfactor will drop below a predefined
|
||||
minimum value, OR the level in the B-tree contains just
|
||||
one page, OR the page will become empty: we recommend
|
||||
compression if this is not the root page. */
|
||||
|
||||
no_compress_needed = block->page.id.page_no() == index->page;
|
||||
} else {
|
||||
no_compress_needed = true;
|
||||
}
|
||||
|
||||
if (no_compress_needed) {
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
|
||||
page_cur_delete_rec(pcur, index, offsets, 0);
|
||||
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(!page_zip || page_zip_validate(page_zip, page, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
}
|
||||
|
||||
return(no_compress_needed);
|
||||
}
|
||||
|
||||
/** Get the last non-delete-marked record on a page.
|
||||
@param[in] page index tree leaf page
|
||||
@return the last record, not delete-marked
|
||||
|
@ -227,6 +227,9 @@ public:
|
||||
RecIterator() UNIV_NOTHROW
|
||||
{
|
||||
memset(&m_cur, 0x0, sizeof(m_cur));
|
||||
/* Make page_cur_delete_rec() happy. */
|
||||
m_mtr.start();
|
||||
m_mtr.set_log_mode(MTR_LOG_NONE);
|
||||
}
|
||||
|
||||
/** Position the cursor on the first user record. */
|
||||
@ -267,16 +270,40 @@ public:
|
||||
page_zip_des_t* page_zip,
|
||||
ulint* offsets) UNIV_NOTHROW
|
||||
{
|
||||
ut_ad(page_is_leaf(m_cur.block->frame));
|
||||
/* We can't end up with an empty page unless it is root. */
|
||||
if (page_get_n_recs(m_cur.block->frame) <= 1) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
return(page_delete_rec(index, &m_cur, page_zip, offsets));
|
||||
if (!rec_offs_any_extern(offsets)
|
||||
&& m_cur.block->page.id.page_no() != index->page
|
||||
&& ((page_get_data_size(m_cur.block->frame)
|
||||
- rec_offs_size(offsets)
|
||||
< BTR_CUR_PAGE_COMPRESS_LIMIT(index))
|
||||
|| !page_has_siblings(m_cur.block->frame)
|
||||
|| (page_get_n_recs(m_cur.block->frame) < 2))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(!page_zip || page_zip_validate(
|
||||
page_zip, m_cur.block->frame, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
|
||||
page_cur_delete_rec(&m_cur, index, offsets, &m_mtr);
|
||||
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(!page_zip || page_zip_validate(
|
||||
page_zip, m_cur.block->frame, index));
|
||||
#endif /* UNIV_ZIP_DEBUG */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
page_cur_t m_cur;
|
||||
mtr_t m_mtr;
|
||||
};
|
||||
|
||||
/** Class that purges delete marked reocords from indexes, both secondary
|
||||
|
Loading…
x
Reference in New Issue
Block a user