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 ...@@ -27,12 +27,7 @@ Created 10/4/1994 Heikki Tuuri
#ifndef page0cur_h #ifndef page0cur_h
#define page0cur_h #define page0cur_h
#include "buf0types.h"
#include "page0page.h" #include "page0page.h"
#include "rem0rec.h"
#include "data0data.h"
#include "mtr0mtr.h"
#include "gis0type.h"
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
/*********************************************************//** /*********************************************************//**
...@@ -240,7 +235,8 @@ page_cur_delete_rec( ...@@ -240,7 +235,8 @@ page_cur_delete_rec(
const dict_index_t* index, /*!< in: record descriptor */ const dict_index_t* index, /*!< in: record descriptor */
const ulint* offsets,/*!< in: rec_get_offsets( const ulint* offsets,/*!< in: rec_get_offsets(
cursor->rec, index) */ 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. /** Search the right position for a page cursor.
@param[in] block buffer block @param[in] block buffer block
...@@ -373,20 +369,9 @@ page_cur_parse_delete_rec( ...@@ -373,20 +369,9 @@ page_cur_parse_delete_rec(
const byte* end_ptr,/*!< in: buffer end */ const byte* end_ptr,/*!< in: buffer end */
buf_block_t* block, /*!< in: page or NULL */ buf_block_t* block, /*!< in: page or NULL */
dict_index_t* index, /*!< in: record descriptor */ 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 */
Removes the record from a leaf page. This function does not log MY_ATTRIBUTE((warn_unused_result, nonnull(1,2,4)));
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 */
/** Index page cursor */ /** Index page cursor */
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. 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 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 the terms of the GNU General Public License as published by the Free Software
...@@ -163,27 +164,5 @@ page_zip_rec_set_owned( ...@@ -163,27 +164,5 @@ page_zip_rec_set_owned(
const byte* rec, /*!< in: record on the uncompressed page */ const byte* rec, /*!< in: record on the uncompressed page */
ulint flag) /*!< in: the owned flag (nonzero=TRUE) */ ulint flag) /*!< in: the owned flag (nonzero=TRUE) */
MY_ATTRIBUTE((nonnull)); 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 /* !UNIV_INNOCHECKSUM */
#endif #endif
...@@ -2371,11 +2371,14 @@ page_cur_parse_delete_rec( ...@@ -2371,11 +2371,14 @@ page_cur_parse_delete_rec(
const byte* end_ptr,/*!< in: buffer end */ const byte* end_ptr,/*!< in: buffer end */
buf_block_t* block, /*!< in: page or NULL */ buf_block_t* block, /*!< in: page or NULL */
dict_index_t* index, /*!< in: record descriptor */ 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; ulint offset;
page_cur_t cursor; page_cur_t cursor;
ut_ad(!block == !mtr);
if (end_ptr < ptr + 2) { if (end_ptr < ptr + 2) {
return(NULL); return(NULL);
...@@ -2453,13 +2456,10 @@ page_cur_delete_rec( ...@@ -2453,13 +2456,10 @@ page_cur_delete_rec(
const dict_index_t* index, /*!< in: record descriptor */ const dict_index_t* index, /*!< in: record descriptor */
const ulint* offsets,/*!< in: rec_get_offsets( const ulint* offsets,/*!< in: rec_get_offsets(
cursor->rec, index) */ cursor->rec, index) */
mtr_t* mtr) /*!< in: mini-transaction handle mtr_t* mtr) /*!< in/out: mini-transaction */
or NULL */
{ {
page_dir_slot_t* cur_dir_slot; page_dir_slot_t* cur_dir_slot;
page_dir_slot_t* prev_slot; page_dir_slot_t* prev_slot;
page_t* page;
page_zip_des_t* page_zip;
rec_t* current_rec; rec_t* current_rec;
rec_t* prev_rec = NULL; rec_t* prev_rec = NULL;
rec_t* next_rec; rec_t* next_rec;
...@@ -2467,36 +2467,36 @@ page_cur_delete_rec( ...@@ -2467,36 +2467,36 @@ page_cur_delete_rec(
ulint cur_n_owned; ulint cur_n_owned;
rec_t* rec; rec_t* rec;
page = page_cur_get_page(cursor);
page_zip = page_cur_get_page_zip(cursor);
/* page_zip_validate() will fail here when /* page_zip_validate() will fail here when
btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark(). btr_cur_pessimistic_delete() invokes btr_set_min_rec_mark().
Then, both "page_zip" and "page" would have the min-rec-mark Then, both "page_zip" and "block->frame" would have the min-rec-mark
set on the smallest user record, but "page" would additionally set on the smallest user record, but "block->frame" would additionally
have it set on the smallest-but-one record. Because sloppy have it set on the smallest-but-one record. Because sloppy
page_zip_validate_low() only ignores min-rec-flag differences page_zip_validate_low() only ignores min-rec-flag differences
in the smallest user record, it cannot be used here either. */ in the smallest user record, it cannot be used here either. */
current_rec = cursor->rec; current_rec = cursor->rec;
buf_block_t* const block = cursor->block;
ut_ad(rec_offs_validate(current_rec, index, offsets)); ut_ad(rec_offs_validate(current_rec, index, offsets));
ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table)); ut_ad(!!page_is_comp(block->frame) == index->table->not_redundant());
ut_ad(fil_page_index_page_check(page)); ut_ad(fil_page_index_page_check(block->frame));
ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID) == index->id ut_ad(mach_read_from_8(PAGE_HEADER + PAGE_INDEX_ID + block->frame)
== index->id
|| index->is_dummy || index->is_dummy
|| (mtr ? mtr->is_inside_ibuf() : dict_index_is_ibuf(index))); || mtr->is_inside_ibuf());
ut_ad(!mtr || mtr->is_named_space(index->table->space)); ut_ad(mtr->is_named_space(index->table->space));
/* The record must not be the supremum or infimum record. */ /* The record must not be the supremum or infimum record. */
ut_ad(page_rec_is_user_rec(current_rec)); 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)) { && !rec_is_alter_metadata(current_rec, *index)) {
/* Empty the page, unless we are applying the redo log /* Empty the page, unless we are applying the redo log
during crash recovery. During normal operation, the during crash recovery. During normal operation, the
page_create_empty() gets logged as one of MLOG_PAGE_CREATE, page_create_empty() gets logged as one of MLOG_PAGE_CREATE,
MLOG_COMP_PAGE_CREATE, MLOG_ZIP_PAGE_COMPRESS. */ 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, /* Usually, this should be the root page,
and the whole index tree should become empty. and the whole index tree should become empty.
However, this could also be a call in However, this could also be a call in
...@@ -2512,21 +2512,21 @@ page_cur_delete_rec( ...@@ -2512,21 +2512,21 @@ page_cur_delete_rec(
/* Save to local variables some data associated with current_rec */ /* Save to local variables some data associated with current_rec */
cur_slot_no = page_dir_find_owner_slot(current_rec); cur_slot_no = page_dir_find_owner_slot(current_rec);
ut_ad(cur_slot_no > 0); 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); cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
/* 1. Reset the last insert info in the page header and increment /* 1. Reset the last insert info in the page header and increment
the modify clock for the frame */ 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 page_header_set_ptr(block->frame, page_zip, PAGE_LAST_INSERT, NULL);
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. */
if (mtr != 0) { /* The page gets invalid for optimistic searches: increment
buf_block_modify_clock_inc(page_cur_get_block(cursor)); 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); page_cur_delete_rec_write_log(current_rec, index, mtr);
} }
...@@ -2534,9 +2534,9 @@ page_cur_delete_rec( ...@@ -2534,9 +2534,9 @@ page_cur_delete_rec(
left at the next record. */ left at the next record. */
ut_ad(cur_slot_no > 0); 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 /* rec now points to the record of the previous directory slot. Look
for the immediate predecessor of current_rec in a loop. */ for the immediate predecessor of current_rec in a loop. */
...@@ -2570,14 +2570,14 @@ page_cur_delete_rec( ...@@ -2570,14 +2570,14 @@ page_cur_delete_rec(
page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1); page_dir_slot_set_n_owned(cur_dir_slot, page_zip, cur_n_owned - 1);
/* 6. Free the memory occupied by the record */ /* 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. /* 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 If the number drops below PAGE_DIR_SLOT_MIN_N_OWNED, we balance the
slots. */ slots. */
if (cur_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) { 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( ...@@ -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. /** Get the last non-delete-marked record on a page.
@param[in] page index tree leaf page @param[in] page index tree leaf page
@return the last record, not delete-marked @return the last record, not delete-marked
......
...@@ -227,6 +227,9 @@ class RecIterator { ...@@ -227,6 +227,9 @@ class RecIterator {
RecIterator() UNIV_NOTHROW RecIterator() UNIV_NOTHROW
{ {
memset(&m_cur, 0x0, sizeof(m_cur)); 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. */ /** Position the cursor on the first user record. */
...@@ -267,16 +270,40 @@ class RecIterator { ...@@ -267,16 +270,40 @@ class RecIterator {
page_zip_des_t* page_zip, page_zip_des_t* page_zip,
ulint* offsets) UNIV_NOTHROW 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. */ /* We can't end up with an empty page unless it is root. */
if (page_get_n_recs(m_cur.block->frame) <= 1) { if (page_get_n_recs(m_cur.block->frame) <= 1) {
return(false); 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: private:
page_cur_t m_cur; page_cur_t m_cur;
mtr_t m_mtr;
}; };
/** Class that purges delete marked reocords from indexes, both secondary /** 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