mirror of
https://github.com/MariaDB/server.git
synced 2025-07-25 04:34:58 +02:00

- With the help of MDEV-14795, InnoDB implemented a way to shrink the InnoDB system tablespace after undo tablespaces have been moved to separate files (MDEV-29986). There is no way to defragment any pages of InnoDB system tables. By doing that, shrinking of system tablespace can be more effective. This patch deals with defragment of system tables inside ibdata1. Following steps are done to do the defragmentation of system tablespace: 1) Make sure that there is no user tables exist in ibdata1 2) Iterate through all extent descriptor pages in system tablespace and note their states. 3) Find the free earlier extent to replace the lastly used extents in the system tablespace. 4) Iterate through all indexes of system tablespace and defragment the tree level by level. 5) Iterate the level from left page to right page and find out the page comes under the extent to be replaced. If it is then do step (6) else step(4) 6) Prepare the allocation of new extent by latching necessary pages. If any error happens then there is no modification of page happened till step (5). 7) Allocate the new page from the new extent 8) Prepare the associated pages for the block to be modified 9) Prepare the step of freeing of page 10) If any error happens during preparing of associated pages, freeing of page then restore the page which was modified during new page allocation 11) Copy the old page content to new page 12) Change the associative pages like left, right and parent page 13) Complete the freeing of old page Allocation of page from new extent, changing of relative pages, freeing of page are done by 2 steps. one is prepare which latches the to be modified pages and checks their validation. Other is complete(), Do the operation fseg_validate(): Validate the list exist in inode segment Defragmentation is enabled only when :autoextend exist in innodb_data_file_path variable.
464 lines
18 KiB
C++
464 lines
18 KiB
C++
/*****************************************************************************
|
|
|
|
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
|
Copyright (c) 2019, 2022, 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
|
|
Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
|
this program; if not, write to the Free Software Foundation, Inc.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
|
|
|
*****************************************************************************/
|
|
|
|
/******************************************************************//**
|
|
@file fut/fut0lst.cc
|
|
File-based list utilities
|
|
|
|
Created 11/28/1995 Heikki Tuuri
|
|
***********************************************************************/
|
|
|
|
#include "fut0lst.h"
|
|
#include "buf0buf.h"
|
|
#include "page0page.h"
|
|
|
|
|
|
/** Write a file address.
|
|
@param[in] block file page
|
|
@param[in,out] faddr file address location
|
|
@param[in] page page number
|
|
@param[in] boffset byte offset
|
|
@param[in,out] mtr mini-transaction */
|
|
void flst_write_addr(const buf_block_t &block, byte *faddr,
|
|
uint32_t page, uint16_t boffset, mtr_t *mtr)
|
|
{
|
|
ut_ad(mtr->memo_contains_page_flagged(faddr, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_a(page == FIL_NULL || boffset >= FIL_PAGE_DATA);
|
|
ut_a(ut_align_offset(faddr, srv_page_size) >= FIL_PAGE_DATA);
|
|
|
|
static_assert(FIL_ADDR_PAGE == 0, "compatibility");
|
|
static_assert(FIL_ADDR_BYTE == 4, "compatibility");
|
|
static_assert(FIL_ADDR_SIZE == 6, "compatibility");
|
|
|
|
if (!mtr->is_logged())
|
|
{
|
|
mach_write_to_4(faddr + FIL_ADDR_PAGE, page);
|
|
mach_write_to_2(faddr + FIL_ADDR_BYTE, boffset);
|
|
mtr->set_modified(block);
|
|
return;
|
|
}
|
|
|
|
const bool same_page= mach_read_from_4(faddr + FIL_ADDR_PAGE) == page;
|
|
const bool same_offset= mach_read_from_2(faddr + FIL_ADDR_BYTE) == boffset;
|
|
if (same_page)
|
|
{
|
|
if (!same_offset)
|
|
mtr->write<2>(block, faddr + FIL_ADDR_BYTE, boffset);
|
|
return;
|
|
}
|
|
if (same_offset)
|
|
mtr->write<4>(block, faddr + FIL_ADDR_PAGE, page);
|
|
else
|
|
{
|
|
alignas(4) byte fil_addr[6];
|
|
mach_write_to_4(fil_addr + FIL_ADDR_PAGE, page);
|
|
mach_write_to_2(fil_addr + FIL_ADDR_BYTE, boffset);
|
|
mtr->memcpy(block, faddr + FIL_ADDR_PAGE, fil_addr, 6);
|
|
}
|
|
}
|
|
|
|
/** Write 2 null file addresses.
|
|
@param[in] b file page
|
|
@param[in,out] addr file address to be zeroed out
|
|
@param[in,out] mtr mini-transaction */
|
|
static void flst_zero_both(const buf_block_t& b, byte *addr, mtr_t *mtr)
|
|
{
|
|
const ulint boffset= ulint(addr - b.page.frame);
|
|
if (mach_read_from_4(addr + FIL_ADDR_PAGE) != FIL_NULL)
|
|
mtr->memset(&b, boffset + FIL_ADDR_PAGE, 4, 0xff);
|
|
mtr->write<2,mtr_t::MAYBE_NOP>(b, addr + FIL_ADDR_BYTE, 0U);
|
|
/* Initialize the other address by (MEMMOVE|0x80,offset,FIL_ADDR_SIZE,source)
|
|
which is 4 bytes, or less than FIL_ADDR_SIZE. */
|
|
memcpy(addr + FIL_ADDR_SIZE, addr, FIL_ADDR_SIZE);
|
|
mtr->memmove(b, boffset + FIL_ADDR_SIZE, boffset, FIL_ADDR_SIZE);
|
|
}
|
|
|
|
/** Add a node to an empty list. */
|
|
static void flst_add_to_empty(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *add, uint16_t aoffset, mtr_t *mtr)
|
|
{
|
|
ut_ad(base != add || boffset != aoffset);
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(aoffset < add->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
ut_ad(!mach_read_from_4(base->page.frame + boffset + FLST_LEN));
|
|
mtr->write<1>(*base, base->page.frame + boffset + (FLST_LEN + 3), 1U);
|
|
/* Update first and last fields of base node */
|
|
flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
memcpy(base->page.frame + boffset + FLST_LAST,
|
|
base->page.frame + boffset + FLST_FIRST,
|
|
FIL_ADDR_SIZE);
|
|
/* Initialize FLST_LAST by (MEMMOVE|0x80,offset,FIL_ADDR_SIZE,source)
|
|
which is 4 bytes, or less than FIL_ADDR_SIZE. */
|
|
mtr->memmove(*base, boffset + FLST_LAST, boffset + FLST_FIRST,
|
|
FIL_ADDR_SIZE);
|
|
|
|
/* Set prev and next fields of node to add */
|
|
static_assert(FLST_NEXT == FLST_PREV + FIL_ADDR_SIZE, "compatibility");
|
|
flst_zero_both(*add, add->page.frame + aoffset + FLST_PREV, mtr);
|
|
}
|
|
|
|
/** Insert a node after another one.
|
|
@param base base node block
|
|
@param boffset byte offset of the base node
|
|
@param cur insert position block
|
|
@param coffset byte offset of the insert position
|
|
@param add block to be added
|
|
@param aoffset byte offset of the block to be added
|
|
@param limit fil_space_t::free_limit
|
|
@param mtr mini-transaction */
|
|
static dberr_t flst_insert_after(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *cur, uint16_t coffset,
|
|
buf_block_t *add, uint16_t aoffset,
|
|
uint32_t limit, mtr_t *mtr)
|
|
{
|
|
ut_ad(base != cur || boffset != coffset);
|
|
ut_ad(base != add || boffset != aoffset);
|
|
ut_ad(cur != add || coffset != aoffset);
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(coffset < cur->physical_size());
|
|
ut_ad(aoffset < add->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset);
|
|
if (next_addr.page >= limit)
|
|
{
|
|
if (UNIV_UNLIKELY(next_addr.page != FIL_NULL))
|
|
return DB_CORRUPTION;
|
|
}
|
|
else if (UNIV_UNLIKELY(next_addr.boffset < FIL_PAGE_DATA ||
|
|
next_addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
|
|
flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV,
|
|
cur->page.id().page_no(), coffset, mtr);
|
|
flst_write_addr(*add, add->page.frame + aoffset + FLST_NEXT,
|
|
next_addr.page, next_addr.boffset, mtr);
|
|
|
|
dberr_t err= DB_SUCCESS;
|
|
|
|
if (next_addr.page == FIL_NULL)
|
|
flst_write_addr(*base, base->page.frame + boffset + FLST_LAST,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
else if (buf_block_t *block=
|
|
buf_page_get_gen(page_id_t{add->page.id().space(), next_addr.page},
|
|
add->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err))
|
|
flst_write_addr(*block, block->page.frame +
|
|
next_addr.boffset + FLST_PREV,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
|
|
flst_write_addr(*cur, cur->page.frame + coffset + FLST_NEXT,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
|
|
byte *len= &base->page.frame[boffset + FLST_LEN];
|
|
mtr->write<4>(*base, len, mach_read_from_4(len) + 1);
|
|
return err;
|
|
}
|
|
|
|
/** Insert a node before another one.
|
|
@param base base node block
|
|
@param boffset byte offset of the base node
|
|
@param cur insert position block
|
|
@param coffset byte offset of the insert position
|
|
@param add block to be added
|
|
@param aoffset byte offset of the block to be added
|
|
@param limit fil_space_t::free_limit
|
|
@param mtr mini-transaction
|
|
@return error code */
|
|
static dberr_t flst_insert_before(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *cur, uint16_t coffset,
|
|
buf_block_t *add, uint16_t aoffset,
|
|
uint32_t limit, mtr_t *mtr)
|
|
{
|
|
ut_ad(base != cur || boffset != coffset);
|
|
ut_ad(base != add || boffset != aoffset);
|
|
ut_ad(cur != add || coffset != aoffset);
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(coffset < cur->physical_size());
|
|
ut_ad(aoffset < add->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
fil_addr_t prev_addr= flst_get_prev_addr(cur->page.frame + coffset);
|
|
if (prev_addr.page >= limit)
|
|
{
|
|
if (UNIV_UNLIKELY(prev_addr.page != FIL_NULL))
|
|
return DB_CORRUPTION;
|
|
}
|
|
else if (UNIV_UNLIKELY(prev_addr.boffset < FIL_PAGE_DATA ||
|
|
prev_addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
|
|
flst_write_addr(*add, add->page.frame + aoffset + FLST_PREV,
|
|
prev_addr.page, prev_addr.boffset, mtr);
|
|
flst_write_addr(*add, add->page.frame + aoffset + FLST_NEXT,
|
|
cur->page.id().page_no(), coffset, mtr);
|
|
|
|
dberr_t err= DB_SUCCESS;
|
|
|
|
if (prev_addr.page == FIL_NULL)
|
|
flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
else if (buf_block_t *block=
|
|
buf_page_get_gen(page_id_t{add->page.id().space(), prev_addr.page},
|
|
add->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err))
|
|
flst_write_addr(*block, block->page.frame +
|
|
prev_addr.boffset + FLST_NEXT,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
|
|
flst_write_addr(*cur, cur->page.frame + coffset + FLST_PREV,
|
|
add->page.id().page_no(), aoffset, mtr);
|
|
|
|
byte *len= &base->page.frame[boffset + FLST_LEN];
|
|
mtr->write<4>(*base, len, mach_read_from_4(len) + 1);
|
|
return err;
|
|
}
|
|
|
|
/** Initialize a list base node.
|
|
@param[in] block file page
|
|
@param[in,out] base base node
|
|
@param[in,out] mtr mini-transaction */
|
|
void flst_init(const buf_block_t& block, byte *base, mtr_t *mtr)
|
|
{
|
|
ut_ad(mtr->memo_contains_page_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
mtr->write<4,mtr_t::MAYBE_NOP>(block, base + FLST_LEN, 0U);
|
|
static_assert(FLST_LAST == FLST_FIRST + FIL_ADDR_SIZE, "compatibility");
|
|
flst_zero_both(block, base + FLST_FIRST, mtr);
|
|
}
|
|
|
|
dberr_t flst_add_last(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *add, uint16_t aoffset,
|
|
uint32_t limit, mtr_t *mtr)
|
|
{
|
|
ut_ad(base != add || boffset != aoffset);
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(aoffset < add->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
if (!flst_get_len(base->page.frame + boffset))
|
|
{
|
|
flst_add_to_empty(base, boffset, add, aoffset, mtr);
|
|
return DB_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
fil_addr_t addr= flst_get_last(base->page.frame + boffset);
|
|
if (UNIV_UNLIKELY(addr.page >= limit))
|
|
return DB_CORRUPTION;
|
|
else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA ||
|
|
addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
|
|
buf_block_t *cur= add;
|
|
dberr_t err;
|
|
if (addr.page != add->page.id().page_no() &&
|
|
!(cur= buf_page_get_gen(page_id_t{add->page.id().space(), addr.page},
|
|
add->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err)))
|
|
return err;
|
|
return flst_insert_after(base, boffset, cur, addr.boffset,
|
|
add, aoffset, limit, mtr);
|
|
}
|
|
}
|
|
|
|
dberr_t flst_add_first(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *add, uint16_t aoffset,
|
|
uint32_t limit, mtr_t *mtr)
|
|
{
|
|
ut_ad(base != add || boffset != aoffset);
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(aoffset < add->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(add, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
if (!flst_get_len(base->page.frame + boffset))
|
|
{
|
|
flst_add_to_empty(base, boffset, add, aoffset, mtr);
|
|
return DB_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
fil_addr_t addr= flst_get_first(base->page.frame + boffset);
|
|
if (UNIV_UNLIKELY(addr.page >= limit))
|
|
return DB_CORRUPTION;
|
|
else if (UNIV_UNLIKELY(addr.boffset < FIL_PAGE_DATA ||
|
|
addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
buf_block_t *cur= add;
|
|
dberr_t err;
|
|
if (addr.page != add->page.id().page_no() &&
|
|
!(cur= buf_page_get_gen(page_id_t{add->page.id().space(), addr.page},
|
|
add->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err)))
|
|
return err;
|
|
return flst_insert_before(base, boffset, cur, addr.boffset,
|
|
add, aoffset, limit, mtr);
|
|
}
|
|
}
|
|
|
|
dberr_t flst_remove(buf_block_t *base, uint16_t boffset,
|
|
buf_block_t *cur, uint16_t coffset,
|
|
uint32_t limit, mtr_t *mtr)
|
|
{
|
|
ut_ad(boffset < base->physical_size());
|
|
ut_ad(coffset < cur->physical_size());
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
ut_ad(mtr->memo_contains_flagged(cur, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
const fil_addr_t prev_addr= flst_get_prev_addr(cur->page.frame + coffset);
|
|
const fil_addr_t next_addr= flst_get_next_addr(cur->page.frame + coffset);
|
|
dberr_t err= DB_SUCCESS;
|
|
|
|
if (next_addr.page >= limit)
|
|
{
|
|
if (next_addr.page != FIL_NULL)
|
|
return DB_CORRUPTION;
|
|
}
|
|
else if (UNIV_UNLIKELY(next_addr.boffset < FIL_PAGE_DATA ||
|
|
next_addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
|
|
if (prev_addr.page >= limit)
|
|
{
|
|
if (prev_addr.page != FIL_NULL)
|
|
return DB_CORRUPTION;
|
|
flst_write_addr(*base, base->page.frame + boffset + FLST_FIRST,
|
|
next_addr.page, next_addr.boffset, mtr);
|
|
}
|
|
else if (UNIV_UNLIKELY(prev_addr.boffset < FIL_PAGE_DATA ||
|
|
prev_addr.boffset >= base->physical_size() -
|
|
FIL_PAGE_DATA_END))
|
|
return DB_CORRUPTION;
|
|
else
|
|
{
|
|
buf_block_t *b= cur;
|
|
if (prev_addr.page == b->page.id().page_no() ||
|
|
(b= buf_page_get_gen(page_id_t(b->page.id().space(), prev_addr.page),
|
|
b->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err)))
|
|
flst_write_addr(*b, b->page.frame + prev_addr.boffset + FLST_NEXT,
|
|
next_addr.page, next_addr.boffset, mtr);
|
|
}
|
|
|
|
if (next_addr.page == FIL_NULL)
|
|
flst_write_addr(*base, base->page.frame + boffset + FLST_LAST,
|
|
prev_addr.page, prev_addr.boffset, mtr);
|
|
else
|
|
{
|
|
dberr_t err2;
|
|
if (next_addr.page == cur->page.id().page_no() ||
|
|
(cur= buf_page_get_gen(page_id_t(cur->page.id().space(),
|
|
next_addr.page),
|
|
cur->zip_size(), RW_SX_LATCH, nullptr,
|
|
BUF_GET_POSSIBLY_FREED, mtr, &err2)))
|
|
flst_write_addr(*cur, cur->page.frame + next_addr.boffset + FLST_PREV,
|
|
prev_addr.page, prev_addr.boffset, mtr);
|
|
else if (err == DB_SUCCESS)
|
|
err= err2;
|
|
}
|
|
|
|
byte *len= &base->page.frame[boffset + FLST_LEN];
|
|
if (UNIV_UNLIKELY(!mach_read_from_4(len)))
|
|
return DB_CORRUPTION;
|
|
mtr->write<4>(*base, len, mach_read_from_4(len) - 1);
|
|
return err;
|
|
}
|
|
|
|
/** Validate a file-based list. */
|
|
dberr_t flst_validate(const buf_block_t *base, uint16_t boffset,
|
|
mtr_t *mtr) noexcept
|
|
{
|
|
if (boffset >= base->physical_size())
|
|
return DB_CORRUPTION;
|
|
|
|
ut_ad(mtr->memo_contains_flagged(base, MTR_MEMO_PAGE_X_FIX |
|
|
MTR_MEMO_PAGE_SX_FIX));
|
|
|
|
const uint32_t len= flst_get_len(base->page.frame + boffset);
|
|
fil_addr_t addr= flst_get_first(base->page.frame + boffset);
|
|
dberr_t err= DB_SUCCESS;
|
|
|
|
for (uint32_t i= len; i--; )
|
|
{
|
|
if (addr.boffset < FIL_PAGE_DATA ||
|
|
addr.boffset >= base->physical_size() - FIL_PAGE_DATA_END)
|
|
return DB_CORRUPTION;
|
|
const buf_block_t *b=
|
|
buf_page_get_gen(page_id_t(base->page.id().space(), addr.page),
|
|
base->zip_size(), RW_SX_LATCH, nullptr, BUF_GET, mtr,
|
|
&err);
|
|
if (!b)
|
|
return err;
|
|
addr= flst_get_next_addr(b->page.frame + addr.boffset);
|
|
mtr->release_last_page();
|
|
}
|
|
|
|
if (addr.page != FIL_NULL)
|
|
return DB_CORRUPTION;
|
|
|
|
addr= flst_get_last(base->page.frame + boffset);
|
|
|
|
for (uint32_t i= len; i--; )
|
|
{
|
|
if (addr.boffset < FIL_PAGE_DATA ||
|
|
addr.boffset >= base->physical_size() - FIL_PAGE_DATA_END)
|
|
return DB_CORRUPTION;
|
|
const buf_block_t *b=
|
|
buf_page_get_gen(page_id_t(base->page.id().space(), addr.page),
|
|
base->zip_size(), RW_SX_LATCH, nullptr, BUF_GET, mtr,
|
|
&err);
|
|
if (!b)
|
|
return err;
|
|
addr= flst_get_prev_addr(b->page.frame + addr.boffset);
|
|
mtr->release_last_page();
|
|
}
|
|
|
|
if (addr.page != FIL_NULL)
|
|
return DB_CORRUPTION;
|
|
return err;
|
|
}
|