Commit befde6e9 authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent 1c282d4b
......@@ -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 */
......
/*****************************************************************************
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 @@ class RecIterator {
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 @@ class RecIterator {
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
......
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