MDEV-36024 preparation: Shrink mtr_buf_t

mtr_t::get_log_size(): Remove.

mtr_t::crc32c(): New function: compute CRC-32C and determine the size,
including the sequence byte and the CRC-32C.

mtr_t::encrypt(): Return the size, similar to crc32c().

mtr_t::log_file_op(): Return the size written.

fil_name_write(): Remove. Let us invoke mtr_t::log_file_op() directly.

fil_names_clear(): Keep track of the available size without
invoking mtr_t::get_log_size().

mtr_buf_t::m_size: Remove.

mtr_buf_t::list_t: Use ilist instead of sized_ilist.

mtr_buf_t::for_each_block(): Remove. Let us allow iteration via
begin() and end(), without any lambda function objects.
This commit is contained in:
Marko Mäkelä 2025-09-02 13:21:36 +03:00
commit 1afc682932
5 changed files with 87 additions and 141 deletions

View file

@ -1423,12 +1423,15 @@ fil_space_t *fil_space_t::get(uint32_t id) noexcept
@param type file operation
@param first_page_no first page number in the file
@param path file path
@param new_path new file path for type=FILE_RENAME */
inline void mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
const char *path, const char *new_path)
@param new_path new file path for type=FILE_RENAME
@return number of bytes written */
inline size_t mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
const char *path, const char *new_path)
noexcept
{
ut_ad((new_path != nullptr) == (type == FILE_RENAME));
ut_ad(!(byte(type) & 15));
ut_ad(!is_predefined_tablespace(space_id));
/* fil_name_parse() requires that there be at least one path
separator and that the file path end with ".ibd". */
@ -1437,7 +1440,7 @@ inline void mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
m_modifications= true;
if (!is_logged())
return;
return 0;
m_last= nullptr;
const size_t len= strlen(path);
@ -1469,7 +1472,7 @@ inline void mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
m_log.close(end);
if (new_path)
if (new_len)
{
ut_ad(strchr(new_path, '/'));
m_log.push(reinterpret_cast<const byte*>(path), uint32_t(len + 1));
@ -1477,17 +1480,8 @@ inline void mtr_t::log_file_op(mfile_type_t type, uint32_t space_id,
}
else
m_log.push(reinterpret_cast<const byte*>(path), uint32_t(len));
}
/** Write FILE_MODIFY for a file.
@param[in] space_id tablespace id
@param[in] name tablespace file name
@param[in,out] mtr mini-transaction */
static void fil_name_write(uint32_t space_id, const char *name,
mtr_t *mtr)
{
ut_ad(!is_predefined_tablespace(space_id));
mtr->log_file_op(FILE_MODIFY, space_id, name);
return end - log_ptr + len + new_len;
}
fil_space_t *fil_space_t::drop(uint32_t id, pfs_os_file_t *detached_handle)
@ -2986,9 +2980,8 @@ ATTRIBUTE_NOINLINE ATTRIBUTE_COLD void mtr_t::name_write() noexcept
mtr_t mtr;
mtr.start();
fil_name_write(m_user_space->id,
UT_LIST_GET_FIRST(m_user_space->chain)->name,
&mtr);
mtr.log_file_op(FILE_MODIFY, m_user_space->id,
UT_LIST_GET_FIRST(m_user_space->chain)->name);
mtr.commit_files();
}
@ -3005,14 +2998,18 @@ ATTRIBUTE_COLD lsn_t fil_names_clear(lsn_t lsn) noexcept
ut_ad(log_sys.is_latest());
mtr.start();
constexpr size_t budget = recv_sys.MTR_SIZE_MAX - (3 + 5);
size_t budget_left = budget;
for (auto it = fil_system.named_spaces.begin();
it != fil_system.named_spaces.end(); ) {
if (mtr.get_log_size() + strlen(it->chain.start->name)
>= recv_sys.MTR_SIZE_MAX - (3 + 5)) {
const char* const name = it->chain.start->name;
if (strlen(name) >= budget_left) {
/* Prevent log parse buffer overflow */
mtr.commit_files();
mtr.start();
budget_left = budget;
}
auto next = std::next(it);
@ -3033,8 +3030,9 @@ ATTRIBUTE_COLD lsn_t fil_names_clear(lsn_t lsn) noexcept
where max_lsn turned nonzero), we could avoid the
fil_names_write() call if min_lsn > lsn. */
ut_ad(UT_LIST_GET_LEN((*it).chain) == 1);
fil_name_write((*it).id, UT_LIST_GET_FIRST((*it).chain)->name,
&mtr);
size_t s = mtr.log_file_op(FILE_MODIFY, (*it).id, name);
ut_ad(s <= budget_left);
budget_left -= s;
it = next;
}

View file

@ -155,13 +155,12 @@ public:
friend class mtr_buf_t;
};
typedef sized_ilist<block_t> list_t;
typedef ilist<block_t> list_t;
/** Default constructor */
mtr_buf_t()
:
m_heap(),
m_size()
m_heap()
{
push_back(&m_first_block);
}
@ -183,11 +182,10 @@ public:
m_list.clear();
m_list.push_back(m_first_block);
} else {
ut_ad(front() == &m_first_block);
ut_ad(back() == &m_first_block);
m_first_block.init();
ut_ad(m_list.size() == 1);
}
m_size = 0;
}
/**
@ -217,13 +215,7 @@ public:
void close(const byte* ptr)
{
ut_ad(!m_list.empty());
block_t* block = back();
m_size -= block->used();
block->close(ptr);
m_size += block->used();
back()->close(ptr);
}
/**
@ -241,8 +233,6 @@ public:
block = has_space(size) ? back() : add_block();
m_size += size;
/* See ISO C++03 14.2/4 for why "template" is required. */
return(block->template push<Type>(size));
@ -264,41 +254,8 @@ public:
}
}
/**
Returns the size of the total stored data.
@return data size in bytes */
ulint size() const
MY_ATTRIBUTE((warn_unused_result))
{
#ifdef UNIV_DEBUG
ulint total_size = 0;
for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
total_size += it->used();
}
ut_ad(total_size == m_size);
#endif /* UNIV_DEBUG */
return(m_size);
}
/**
Iterate over each block and call the functor.
@return false if iteration was terminated. */
template <typename Functor>
bool for_each_block(const Functor& functor) const
{
for (list_t::iterator it = m_list.begin(), end = m_list.end();
it != end; ++it) {
if (!functor(&*it)) {
return false;
}
}
return(true);
}
list_t::const_iterator begin() const { return m_list.begin(); }
list_t::const_iterator end() const { return m_list.end(); }
/**
@return the first block */
@ -377,9 +334,6 @@ private:
/** Allocated blocks */
list_t m_list;
/** Total size used by all blocks */
ulint m_size;
/** The default block, should always be the first element. This
is for backwards compatibility and to avoid an extra heap allocation
for small REDO log records */

View file

@ -435,10 +435,8 @@ public:
m_memo.emplace_back(mtr_memo_slot_t{object, type});
}
/** @return the size of the log is empty */
size_t get_log_size() const { return m_log.size(); }
/** @return whether the log and memo are empty */
bool is_empty() const { return !get_savepoint() && !get_log_size(); }
bool is_empty() const { return !get_savepoint() && m_log.empty(); }
/** Write an OPT_PAGE_CHECKSUM record. */
inline void page_checksum(const buf_page_t &bpage);
@ -618,10 +616,11 @@ public:
@param type file operation
@param space_id tablespace identifier
@param path file path
@param new_path new file path for type=FILE_RENAME */
inline void log_file_op(mfile_type_t type, uint32_t space_id,
const char *path,
const char *new_path= nullptr);
@param new_path new file path for type=FILE_RENAME
@return number of bytes written */
inline size_t log_file_op(mfile_type_t type, uint32_t space_id,
const char *path,
const char *new_path= nullptr) noexcept;
/** Add freed page numbers to freed_pages */
void add_freed_offset(fil_space_t *space, uint32_t page)
@ -692,8 +691,13 @@ private:
tablespace was modified for the first time since fil_names_clear(). */
ATTRIBUTE_NOINLINE ATTRIBUTE_COLD void name_write() noexcept;
/** Encrypt the log */
ATTRIBUTE_NOINLINE void encrypt();
/** Encrypt the log
@return the total size in bytes, excluding the 8-byte nonce */
ATTRIBUTE_NOINLINE size_t encrypt() noexcept;
/** Calculate m_crc of m_log.
@return the total size in bytes, including the 5-byte trailer and CRC-32C */
ATTRIBUTE_NOINLINE size_t crc32c() noexcept;
/** Commit the mini-transaction log.
@tparam pmem log_sys.is_mmap()

View file

@ -558,11 +558,10 @@ static size_t log_encrypt_buf(byte iv[MY_AES_BLOCK_SIZE],
return 0;
}
/** Encrypt the log */
ATTRIBUTE_NOINLINE void mtr_t::encrypt()
ATTRIBUTE_NOINLINE size_t mtr_t::encrypt() noexcept
{
ut_ad(log_sys.format == log_t::FORMAT_ENC_10_8);
ut_ad(m_log.size());
ut_ad(!m_log.empty());
alignas(8) byte iv[MY_AES_BLOCK_SIZE];
@ -572,18 +571,19 @@ ATTRIBUTE_NOINLINE void mtr_t::encrypt()
byte *dst= static_cast<byte*>(alloca(srv_page_size));
mach_write_to_8(iv, m_commit_lsn);
mtr_buf_t::block_t *start= nullptr;
size_t size= 0, start_size= 0;
size_t size= 0, start_size= 0, log_size= 5;
m_crc= 0;
m_log.for_each_block([&](mtr_buf_t::block_t *b)
for (mtr_buf_t::block_t &b : m_log)
{
ut_ad(t - tmp + size <= srv_page_size);
byte *buf= b->begin();
log_size+= b.used();
byte *buf= b.begin();
if (!start)
{
parse:
ut_ad(t == tmp);
size= log_encrypt_buf(iv, t, buf, b->end());
size= log_encrypt_buf(iv, t, buf, b.end());
if (!size)
{
ut_ad(t == tmp);
@ -591,16 +591,16 @@ ATTRIBUTE_NOINLINE void mtr_t::encrypt()
}
else
{
start= b;
start= &b;
start_size= t - tmp;
}
m_crc= my_crc32c(m_crc, buf, b->end() - buf - start_size);
m_crc= my_crc32c(m_crc, buf, b.end() - buf - start_size);
}
else if (size > b->used())
else if (size > b.used())
{
::memcpy(t, buf, b->used());
t+= b->used();
size-= b->used();
::memcpy(t, buf, b.used());
t+= b.used();
size-= b.used();
}
else
{
@ -620,22 +620,22 @@ ATTRIBUTE_NOINLINE void mtr_t::encrypt()
/* Copy the encrypted data back to the log snippets. */
::memcpy(start->end() - start_size, dst, start_size);
t= dst + start_size;
for (ilist<mtr_buf_t::block_t>::iterator i(start); &*++i != b;)
for (ilist<mtr_buf_t::block_t>::iterator i(start); &*++i != &b;)
{
const size_t l{i->used()};
::memcpy(i->begin(), t, l);
t+= l;
}
::memcpy(b->begin(), t, size);
::memcpy(b.begin(), t, size);
ut_ad(t + size == dst + len);
t= tmp;
start= nullptr;
goto parse;
}
return true;
});
}
ut_ad(t == tmp);
ut_ad(!start);
ut_ad(!size);
return log_size;
}

View file

@ -274,7 +274,7 @@ static void insert_imported(buf_block_t *block)
void mtr_t::release_unlogged()
{
ut_ad(m_log_mode == MTR_LOG_NO_REDO);
ut_ad(m_log.size() == 0);
ut_ad(m_log.empty());
process_freed_pages();
@ -658,13 +658,14 @@ bool mtr_t::commit_file(fil_space_t &space, const char *name)
ut_ad(!m_latch_ex);
m_latch_ex= true;
m_commit_lsn= 0;
size_t size{crc32c()};
log_write_and_flush_prepare();
log_sys.latch.wr_lock(SRW_LOCK_CALL);
size_t size= m_log.size() + 5;
if (log_sys.is_encrypted())
{
/* We will not encrypt any FILE_ records, but we will reserve
@ -672,12 +673,7 @@ bool mtr_t::commit_file(fil_space_t &space, const char *name)
size+= 8;
m_commit_lsn= log_sys.get_flushed_lsn();
}
else
m_commit_lsn= 0;
m_crc= 0;
m_log.for_each_block([this](const mtr_buf_t::block_t *b)
{ m_crc= my_crc32c(m_crc, b->begin(), b->used()); return true; });
finish_write(size);
if (!name && space.max_lsn)
@ -717,6 +713,18 @@ bool mtr_t::commit_file(fil_space_t &space, const char *name)
return success;
}
ATTRIBUTE_NOINLINE size_t mtr_t::crc32c() noexcept
{
m_crc= 0;
size_t len= 5;
for (const mtr_buf_t::block_t &b : m_log)
{
len+= b.used();
m_crc= my_crc32c(m_crc, b.begin(), b.used());
}
return len;
}
/** Commit a mini-transaction that did not modify any pages,
but generated some redo log on a higher level, such as
FILE_MODIFY records and an optional FILE_CHECKPOINT marker.
@ -739,6 +747,7 @@ ATTRIBUTE_COLD lsn_t mtr_t::commit_files(lsn_t checkpoint_lsn)
ut_ad(!m_latch_ex);
m_latch_ex= true;
m_commit_lsn= 0;
if (checkpoint_lsn)
{
@ -748,7 +757,7 @@ ATTRIBUTE_COLD lsn_t mtr_t::commit_files(lsn_t checkpoint_lsn)
mach_write_to_8(ptr + 3, checkpoint_lsn);
}
size_t size= m_log.size() + 5;
size_t size{crc32c()};
if (log_sys.is_encrypted())
{
@ -757,12 +766,7 @@ ATTRIBUTE_COLD lsn_t mtr_t::commit_files(lsn_t checkpoint_lsn)
size+= 8;
m_commit_lsn= log_sys.get_flushed_lsn();
}
else
m_commit_lsn= 0;
m_crc= 0;
m_log.for_each_block([this](const mtr_buf_t::block_t *b)
{ m_crc= my_crc32c(m_crc, b->begin(), b->used()); return true; });
finish_write(size);
release_resources();
@ -1051,10 +1055,11 @@ std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
{
ut_ad(!recv_no_log_write);
ut_ad(is_logged());
ut_ad(m_log.size());
ut_ad(!m_log.empty());
ut_ad(!m_latch_ex || log_sys.latch_have_wr());
ut_ad(!m_user_space ||
(m_user_space->id > 0 && m_user_space->id < SRV_SPACE_ID_UPPER_BOUND));
m_commit_lsn= 0;
#ifndef DBUG_OFF
do
@ -1072,22 +1077,7 @@ std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::do_write()
}
while (0);
#endif
size_t len= m_log.size() + 5;
ut_ad(len > 5);
if (log_sys.is_encrypted())
{
len+= 8;
encrypt();
}
else
{
m_crc= 0;
m_commit_lsn= 0;
m_log.for_each_block([this](const mtr_buf_t::block_t *b)
{ m_crc= my_crc32c(m_crc, b->begin(), b->used()); return true; });
}
const size_t len{log_sys.is_encrypted() ? 8 + encrypt() : crc32c()};
if (!m_latch_ex)
log_sys.latch.rd_lock(SRW_LOCK_CALL);
@ -1220,6 +1210,7 @@ mtr_t::finish_writer(mtr_t *mtr, size_t len)
ut_ad(!recv_no_log_write);
ut_ad(mtr->is_logged());
ut_ad(mtr->m_latch_ex ? log_sys.latch_have_wr() : log_sys.latch_have_rd());
ut_ad(len < recv_sys.MTR_SIZE_MAX);
const size_t size{mtr->m_commit_lsn ? 5U + 8U : 5U};
std::pair<lsn_t, byte*> start=
@ -1227,8 +1218,8 @@ mtr_t::finish_writer(mtr_t *mtr, size_t len)
if (!mmap)
{
mtr->m_log.for_each_block([&start](const mtr_buf_t::block_t *b)
{ log_sys.append(start.second, b->begin(), b->used()); return true; });
for (const mtr_buf_t::block_t &b : mtr->m_log)
log_sys.append(start.second, b.begin(), b.used());
write_trailer:
*start.second++= log_sys.get_sequence_bit(start.first + len - size);
@ -1245,15 +1236,15 @@ mtr_t::finish_writer(mtr_t *mtr, size_t len)
{
if (UNIV_LIKELY(start.second + len <= &log_sys.buf[log_sys.file_size]))
{
mtr->m_log.for_each_block([&start](const mtr_buf_t::block_t *b)
{ log_sys.append(start.second, b->begin(), b->used()); return true; });
for (const mtr_buf_t::block_t &b : mtr->m_log)
log_sys.append(start.second, b.begin(), b.used());
goto write_trailer;
}
mtr->m_log.for_each_block([&start](const mtr_buf_t::block_t *b)
for (const mtr_buf_t::block_t &b : mtr->m_log)
{
size_t size{b->used()};
size_t size{b.used()};
const size_t size_left(&log_sys.buf[log_sys.file_size] - start.second);
const byte *src= b->begin();
const byte *src= b.begin();
if (size > size_left)
{
::memcpy(start.second, src, size_left);
@ -1263,8 +1254,7 @@ mtr_t::finish_writer(mtr_t *mtr, size_t len)
}
::memcpy(start.second, src, size);
start.second+= size;
return true;
});
}
const size_t size_left(&log_sys.buf[log_sys.file_size] - start.second);
if (size_left > size)
goto write_trailer;