Commit 71e856e1 authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-12353 preparation: Clean up page directory operations

page_mem_free(): Define in the same file with the only caller
page_cur_delete_rec().

page_dir_slot_set_rec(): Add const qualifier to a parameter.

page_dir_delete_slot(): Merge with the only caller page_dir_balance_slot().

page_dir_add_slot(): Merge with the only caller page_dir_split_slot().

page_dir_split_slot(), page_dir_balance_slot(): Define in the
same compilation unit with the callers, and simplify the code.
parent 2eeac537
......@@ -679,8 +679,8 @@ UNIV_INLINE
void
page_dir_slot_set_rec(
/*==================*/
page_dir_slot_t* slot, /*!< in: directory slot */
rec_t* rec); /*!< in: record on the page */
page_dir_slot_t*slot, /*!< in: directory slot */
const rec_t* rec); /*!< in: record on the page */
/***************************************************************//**
Gets the number of records owned by a directory slot.
@return number of records */
......@@ -957,20 +957,6 @@ page_mem_alloc_heap(
ulint* heap_no);/*!< out: this contains the heap number
of the allocated record
if allocation succeeds */
/************************************************************//**
Puts a record to free list. */
UNIV_INLINE
void
page_mem_free(
/*==========*/
page_t* page, /*!< in/out: index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page,
or NULL */
rec_t* rec, /*!< in: pointer to the (origin of)
record */
const dict_index_t* index, /*!< in: index of rec */
const ulint* offsets);/*!< in: array returned by
rec_get_offsets() */
/** Read the PAGE_DIRECTION field from a byte.
@param[in] ptr pointer to PAGE_DIRECTION_B
......@@ -1164,28 +1150,6 @@ page_move_rec_list_start(
dict_index_t* index, /*!< in: record descriptor */
mtr_t* mtr) /*!< in: mtr */
MY_ATTRIBUTE((nonnull(1, 2, 4, 5)));
/****************************************************************//**
Splits a directory slot which owns too many records. */
void
page_dir_split_slot(
/*================*/
page_t* page, /*!< in: index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
uncompressed part will be written, or NULL */
ulint slot_no)/*!< in: the directory slot */
MY_ATTRIBUTE((nonnull(1)));
/*************************************************************//**
Tries to balance the given directory slot with too few records
with the upper neighbor, so that there are at least the minimum number
of records owned by the slot; this may result in the merging of
two slots. */
void
page_dir_balance_slot(
/*==================*/
page_t* page, /*!< in/out: index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
ulint slot_no)/*!< in: the directory slot */
MY_ATTRIBUTE((nonnull(1)));
/**********************************************************//**
Parses a log record of a record list end or start deletion.
@return end of log record or NULL */
......
......@@ -559,8 +559,8 @@ UNIV_INLINE
void
page_dir_slot_set_rec(
/*==================*/
page_dir_slot_t* slot, /*!< in: directory slot */
rec_t* rec) /*!< in: record on the page */
page_dir_slot_t*slot, /*!< in: directory slot */
const rec_t* rec) /*!< in: record on the page */
{
ut_ad(page_rec_check(rec));
......@@ -1001,48 +1001,6 @@ page_get_max_insert_size_after_reorganize(
return(free_space - occupied);
}
/************************************************************//**
Puts a record to free list. */
UNIV_INLINE
void
page_mem_free(
/*==========*/
page_t* page, /*!< in/out: index page */
page_zip_des_t* page_zip, /*!< in/out: compressed page,
or NULL */
rec_t* rec, /*!< in: pointer to the
(origin of) record */
const dict_index_t* index, /*!< in: index of rec */
const ulint* offsets) /*!< in: array returned by
rec_get_offsets() */
{
rec_t* free;
ulint garbage;
ut_ad(rec_offs_validate(rec, index, offsets));
free = page_header_get_ptr(page, PAGE_FREE);
if (srv_immediate_scrub_data_uncompressed) {
/* scrub record */
memset(rec, 0, rec_offs_data_size(offsets));
}
page_rec_set_next(rec, free);
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
garbage = page_header_get_field(page, PAGE_GARBAGE);
page_header_set_field(page, page_zip, PAGE_GARBAGE,
garbage + rec_offs_size(offsets));
if (page_zip) {
page_zip_dir_delete(page_zip, rec, index, offsets, free);
} else {
page_header_set_field(page, page_zip, PAGE_N_RECS,
ulint(page_get_n_recs(page)) - 1);
}
}
/** Read the PAGE_DIRECTION field from a byte.
@param[in] ptr pointer to PAGE_DIRECTION_B
@return the value of the PAGE_DIRECTION field */
......
......@@ -1243,6 +1243,118 @@ page_direction_increment(
1U + page_header_get_field(page, PAGE_N_DIRECTION));
}
/** Split a directory slot which owns too many records.
@param[in,out] page index page
@param[in,out] page_zip ROW_FORMAT=COMPRESSED page, or NULL
@param[in] s the slot that needs to be split */
static void page_dir_split_slot(page_t* page, page_zip_des_t* page_zip,
ulint s)
{
ut_ad(!page_zip || page_is_comp(page));
ut_ad(s);
page_dir_slot_t* slot = page_dir_get_nth_slot(page, s);
const ulint n_owned = PAGE_DIR_SLOT_MAX_N_OWNED + 1;
ut_ad(page_dir_slot_get_n_owned(slot) == n_owned);
compile_time_assert((PAGE_DIR_SLOT_MAX_N_OWNED + 1) / 2
>= PAGE_DIR_SLOT_MIN_N_OWNED);
/* 1. We loop to find a record approximately in the middle of the
records owned by the slot. */
const rec_t* rec = page_dir_slot_get_rec(slot + PAGE_DIR_SLOT_SIZE);
for (ulint i = n_owned / 2; i--; ) {
rec = page_rec_get_next_const(rec);
}
/* 2. Add a directory slot immediately below this one. */
const ulint n_slots = page_dir_get_n_slots(page);
page_dir_set_n_slots(page, page_zip, n_slots + 1);
page_dir_slot_t* last_slot = page_dir_get_nth_slot(page, n_slots);
memmove(last_slot, last_slot + PAGE_DIR_SLOT_SIZE, slot - last_slot);
/* 3. We store the appropriate values to the new slot. */
page_dir_slot_set_rec(slot, rec);
page_dir_slot_set_n_owned(slot, page_zip, n_owned / 2);
/* 4. Finally, we update the number of records field of the
original slot */
page_dir_slot_set_n_owned(slot - PAGE_DIR_SLOT_SIZE,
page_zip, n_owned - (n_owned / 2));
}
/** Try to balance an underfilled directory slot with an adjacent one,
so that there are at least the minimum number of records owned by the slot;
this may result in merging the two slots.
@param[in,out] page index page
@param[in,out] page_zip ROW_FORMAT=COMPRESSED page, or NULL
@param[in] s the slot to be balanced */
static void page_dir_balance_slot(page_t* page, page_zip_des_t* page_zip,
ulint s)
{
ut_ad(!page_zip || page_is_comp(page));
ut_ad(s > 0);
const ulint n_slots = page_dir_get_n_slots(page);
if (UNIV_UNLIKELY(s + 1 == n_slots)) {
/* The last directory slot cannot be balanced. */
return;
}
ut_ad(s < n_slots);
page_dir_slot_t* slot = page_dir_get_nth_slot(page, s);
page_dir_slot_t* up_slot = slot - PAGE_DIR_SLOT_SIZE;
const ulint up_n_owned = page_dir_slot_get_n_owned(up_slot);
ut_ad(page_dir_slot_get_n_owned(slot)
== PAGE_DIR_SLOT_MIN_N_OWNED - 1);
if (up_n_owned <= PAGE_DIR_SLOT_MIN_N_OWNED) {
compile_time_assert(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1
<= PAGE_DIR_SLOT_MAX_N_OWNED);
/* Merge the slots. */
ulint n_owned = page_dir_slot_get_n_owned(slot);
page_dir_slot_set_n_owned(slot, page_zip, 0);
page_dir_slot_set_n_owned(up_slot, page_zip,
n_owned
+ page_dir_slot_get_n_owned(up_slot));
/* Shift the slots */
page_dir_slot_t* last_slot = page_dir_get_nth_slot(
page, n_slots - 1);
memmove(last_slot + PAGE_DIR_SLOT_SIZE, last_slot,
slot - last_slot);
mach_write_to_2(last_slot, 0);
page_dir_set_n_slots(page, page_zip, n_slots - 1);
return;
}
/* Transfer one record to the underfilled slot */
rec_t* old_rec = const_cast<rec_t*>(page_dir_slot_get_rec(slot));
rec_t* new_rec;
if (page_is_comp(page)) {
new_rec = rec_get_next_ptr(old_rec, TRUE);
rec_set_n_owned_new(old_rec, page_zip, 0);
rec_set_n_owned_new(new_rec, page_zip,
PAGE_DIR_SLOT_MIN_N_OWNED);
} else {
new_rec = rec_get_next_ptr(old_rec, FALSE);
rec_set_n_owned_old(old_rec, 0);
rec_set_n_owned_old(new_rec, PAGE_DIR_SLOT_MIN_N_OWNED);
}
page_dir_slot_set_rec(slot, new_rec);
page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned - 1);
}
/***********************************************************//**
Inserts a record next to page cursor on an uncompressed page.
Returns pointer to inserted record if succeed, i.e., enough
......@@ -2280,6 +2392,36 @@ page_cur_parse_delete_rec(
return(ptr);
}
/** Prepend a record to the PAGE_FREE list.
@param[in,out] page index page
@param[in,out] page_zip ROW_FORMAT=COMPRESSED page, or NULL
@param[in,out] rec record being deleted
@param[in] index the index that the page belongs to
@param[in] offsets rec_get_offsets(rec, index) */
static void page_mem_free(page_t* page, page_zip_des_t* page_zip, rec_t* rec,
const dict_index_t* index, const ulint* offsets)
{
ut_ad(rec_offs_validate(rec, index, offsets));
const rec_t* free = page_header_get_ptr(page, PAGE_FREE);
if (srv_immediate_scrub_data_uncompressed) {
/* scrub record */
memset(rec, 0, rec_offs_data_size(offsets));
}
page_rec_set_next(rec, free);
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
page_header_set_field(page, page_zip, PAGE_GARBAGE,
rec_offs_size(offsets)
+ page_header_get_field(page, PAGE_GARBAGE));
if (page_zip) {
page_zip_dir_delete(page_zip, rec, index, offsets, free);
} else {
page_header_set_field(page, page_zip, PAGE_N_RECS,
ulint(page_get_n_recs(page)) - 1);
}
}
/***********************************************************//**
Deletes a record at the page cursor. The cursor is moved to the next
record after the deleted one. */
......@@ -2351,11 +2493,6 @@ page_cur_delete_rec(
cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
/* 0. Write the log record */
if (mtr != 0) {
page_cur_delete_rec_write_log(current_rec, index, mtr);
}
/* 1. Reset the last insert info in the page header and increment
the modify clock for the frame */
......@@ -2368,6 +2505,7 @@ page_cur_delete_rec(
if (mtr != 0) {
buf_block_modify_clock_inc(page_cur_get_block(cursor));
page_cur_delete_rec_write_log(current_rec, index, mtr);
}
/* 2. Find the next and the previous record. Note that the cursor is
......
......@@ -1386,212 +1386,6 @@ page_move_rec_list_start(
return(TRUE);
}
/**************************************************************//**
Used to delete n slots from the directory. This function updates
also n_owned fields in the records, so that the first slot after
the deleted ones inherits the records of the deleted slots. */
UNIV_INLINE
void
page_dir_delete_slot(
/*=================*/
page_t* page, /*!< in/out: the index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
ulint slot_no)/*!< in: slot to be deleted */
{
page_dir_slot_t* slot;
ulint n_owned;
ulint i;
ulint n_slots;
ut_ad(!page_zip || page_is_comp(page));
ut_ad(slot_no > 0);
ut_ad(slot_no + 1 < page_dir_get_n_slots(page));
n_slots = page_dir_get_n_slots(page);
/* 1. Reset the n_owned fields of the slots to be
deleted */
slot = page_dir_get_nth_slot(page, slot_no);
n_owned = page_dir_slot_get_n_owned(slot);
page_dir_slot_set_n_owned(slot, page_zip, 0);
/* 2. Update the n_owned value of the first non-deleted slot */
slot = page_dir_get_nth_slot(page, slot_no + 1);
page_dir_slot_set_n_owned(slot, page_zip,
n_owned + page_dir_slot_get_n_owned(slot));
/* 3. Destroy the slot by copying slots */
for (i = slot_no + 1; i < n_slots; i++) {
rec_t* rec = (rec_t*)
page_dir_slot_get_rec(page_dir_get_nth_slot(page, i));
page_dir_slot_set_rec(page_dir_get_nth_slot(page, i - 1), rec);
}
/* 4. Zero out the last slot, which will be removed */
mach_write_to_2(page_dir_get_nth_slot(page, n_slots - 1), 0);
/* 5. Update the page header */
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots - 1);
}
/**************************************************************//**
Used to add n slots to the directory. Does not set the record pointers
in the added slots or update n_owned values: this is the responsibility
of the caller. */
UNIV_INLINE
void
page_dir_add_slot(
/*==============*/
page_t* page, /*!< in/out: the index page */
page_zip_des_t* page_zip,/*!< in/out: comprssed page, or NULL */
ulint start) /*!< in: the slot above which the new slots
are added */
{
page_dir_slot_t* slot;
ulint n_slots;
n_slots = page_dir_get_n_slots(page);
ut_ad(start < n_slots - 1);
/* Update the page header */
page_dir_set_n_slots(page, page_zip, n_slots + 1);
/* Move slots up */
slot = page_dir_get_nth_slot(page, n_slots);
memmove(slot, slot + PAGE_DIR_SLOT_SIZE,
(n_slots - 1 - start) * PAGE_DIR_SLOT_SIZE);
}
/****************************************************************//**
Splits a directory slot which owns too many records. */
void
page_dir_split_slot(
/*================*/
page_t* page, /*!< in/out: index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page whose
uncompressed part will be written, or NULL */
ulint slot_no)/*!< in: the directory slot */
{
rec_t* rec;
page_dir_slot_t* new_slot;
page_dir_slot_t* prev_slot;
page_dir_slot_t* slot;
ulint i;
ulint n_owned;
ut_ad(!page_zip || page_is_comp(page));
ut_ad(slot_no > 0);
slot = page_dir_get_nth_slot(page, slot_no);
n_owned = page_dir_slot_get_n_owned(slot);
ut_ad(n_owned == PAGE_DIR_SLOT_MAX_N_OWNED + 1);
/* 1. We loop to find a record approximately in the middle of the
records owned by the slot. */
prev_slot = page_dir_get_nth_slot(page, slot_no - 1);
rec = (rec_t*) page_dir_slot_get_rec(prev_slot);
for (i = 0; i < n_owned / 2; i++) {
rec = page_rec_get_next(rec);
}
ut_ad(n_owned / 2 >= PAGE_DIR_SLOT_MIN_N_OWNED);
/* 2. We add one directory slot immediately below the slot to be
split. */
page_dir_add_slot(page, page_zip, slot_no - 1);
/* The added slot is now number slot_no, and the old slot is
now number slot_no + 1 */
new_slot = page_dir_get_nth_slot(page, slot_no);
slot = page_dir_get_nth_slot(page, slot_no + 1);
/* 3. We store the appropriate values to the new slot. */
page_dir_slot_set_rec(new_slot, rec);
page_dir_slot_set_n_owned(new_slot, page_zip, n_owned / 2);
/* 4. Finally, we update the number of records field of the
original slot */
page_dir_slot_set_n_owned(slot, page_zip, n_owned - (n_owned / 2));
}
/*************************************************************//**
Tries to balance the given directory slot with too few records with the upper
neighbor, so that there are at least the minimum number of records owned by
the slot; this may result in the merging of two slots. */
void
page_dir_balance_slot(
/*==================*/
page_t* page, /*!< in/out: index page */
page_zip_des_t* page_zip,/*!< in/out: compressed page, or NULL */
ulint slot_no)/*!< in: the directory slot */
{
page_dir_slot_t* slot;
page_dir_slot_t* up_slot;
ulint n_owned;
ulint up_n_owned;
rec_t* old_rec;
rec_t* new_rec;
ut_ad(!page_zip || page_is_comp(page));
ut_ad(slot_no > 0);
slot = page_dir_get_nth_slot(page, slot_no);
/* The last directory slot cannot be balanced with the upper
neighbor, as there is none. */
if (UNIV_UNLIKELY(slot_no + 1 == page_dir_get_n_slots(page))) {
return;
}
up_slot = page_dir_get_nth_slot(page, slot_no + 1);
n_owned = page_dir_slot_get_n_owned(slot);
up_n_owned = page_dir_slot_get_n_owned(up_slot);
ut_ad(n_owned == PAGE_DIR_SLOT_MIN_N_OWNED - 1);
/* If the upper slot has the minimum value of n_owned, we will merge
the two slots, therefore we assert: */
ut_ad(2 * PAGE_DIR_SLOT_MIN_N_OWNED - 1 <= PAGE_DIR_SLOT_MAX_N_OWNED);
if (up_n_owned > PAGE_DIR_SLOT_MIN_N_OWNED) {
/* In this case we can just transfer one record owned
by the upper slot to the property of the lower slot */
old_rec = (rec_t*) page_dir_slot_get_rec(slot);
if (page_is_comp(page)) {
new_rec = rec_get_next_ptr(old_rec, TRUE);
rec_set_n_owned_new(old_rec, page_zip, 0);
rec_set_n_owned_new(new_rec, page_zip, n_owned + 1);
} else {
new_rec = rec_get_next_ptr(old_rec, FALSE);
rec_set_n_owned_old(old_rec, 0);
rec_set_n_owned_old(new_rec, n_owned + 1);
}
page_dir_slot_set_rec(slot, new_rec);
page_dir_slot_set_n_owned(up_slot, page_zip, up_n_owned -1);
} else {
/* In this case we may merge the two slots */
page_dir_delete_slot(page, page_zip, slot_no);
}
}
/************************************************************//**
Returns the nth record of the record list.
This is the inverse function of page_rec_get_n_recs_before().
......
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