Merge 10.5 into 10.6

This commit is contained in:
Marko Mäkelä 2021-06-23 19:36:45 +03:00
commit 101da87228
22 changed files with 647 additions and 455 deletions

View file

@ -7090,7 +7090,7 @@ static void btr_blob_free(buf_block_t *block, bool all, mtr_t *mtr)
mysql_mutex_lock(&buf_pool.mutex);
if (buf_page_t *bpage= buf_pool.page_hash_get_low(page_id, fold))
if(!buf_LRU_free_page(bpage, all) && all && bpage->zip.data)
if (!buf_LRU_free_page(bpage, all) && all && bpage->zip.data)
/* Attempt to deallocate the redundant copy of the uncompressed page
if the whole ROW_FORMAT=COMPRESSED block cannot be deallocted. */
buf_LRU_free_page(bpage, false);

View file

@ -1108,13 +1108,15 @@ inline const buf_block_t *buf_pool_t::chunk_t::not_freed() const
break;
}
const lsn_t lsn= block->page.oldest_modification();
if (fsp_is_system_temporary(block->page.id().space()))
{
ut_ad(block->page.oldest_modification() <= 1);
ut_ad(lsn == 0 || lsn == 2);
break;
}
if (!block->page.ready_for_replace())
if (lsn > 1 || !block->page.can_relocate())
return block;
break;
@ -1269,9 +1271,9 @@ void buf_pool_t::close()
Only on aborted startup (with recovery) or with innodb_fast_shutdown=2
we may discard changes. */
ut_d(const lsn_t oldest= bpage->oldest_modification();)
ut_ad(!oldest || srv_is_being_started ||
srv_fast_shutdown == 2 ||
(oldest == 1 && fsp_is_system_temporary(bpage->id().space())));
ut_ad(fsp_is_system_temporary(bpage->id().space())
? (oldest == 0 || oldest == 2)
: oldest <= 1 || srv_is_being_started || srv_fast_shutdown == 2);
if (bpage->state() != BUF_BLOCK_FILE_PAGE)
buf_page_free_descriptor(bpage);
@ -1489,10 +1491,10 @@ inline bool buf_pool_t::withdraw_blocks()
/* reserve free_list length */
if (UT_LIST_GET_LEN(withdraw) < withdraw_target) {
buf_flush_lists(
buf_flush_LRU(
std::max<ulint>(withdraw_target
- UT_LIST_GET_LEN(withdraw),
srv_LRU_scan_depth), 0);
srv_LRU_scan_depth));
buf_flush_wait_batch_end_acquiring_mutex(true);
}
@ -2970,8 +2972,10 @@ re_evict:
fix_block->fix();
mysql_mutex_unlock(&buf_pool.mutex);
buf_flush_lists(ULINT_UNDEFINED, LSN_MAX);
buf_flush_list();
buf_flush_wait_batch_end_acquiring_mutex(false);
while (buf_flush_list_space(space));
os_aio_wait_until_no_pending_writes();
if (fix_block->page.buf_fix_count() == 1
&& !fix_block->page.oldest_modification()) {
@ -4066,8 +4070,8 @@ void buf_pool_t::print()
<< UT_LIST_GET_LEN(flush_list)
<< ", n pending decompressions=" << n_pend_unzip
<< ", n pending reads=" << n_pend_reads
<< ", n pending flush LRU=" << n_flush_LRU
<< " list=" << n_flush_list
<< ", n pending flush LRU=" << n_flush_LRU_
<< " list=" << n_flush_list_
<< ", pages made young=" << stat.n_pages_made_young
<< ", not young=" << stat.n_pages_not_made_young
<< ", pages read=" << stat.n_pages_read
@ -4166,7 +4170,6 @@ void buf_stats_get_pool_info(buf_pool_info_t *pool_info)
double time_elapsed;
mysql_mutex_lock(&buf_pool.mutex);
mysql_mutex_lock(&buf_pool.flush_list_mutex);
pool_info->pool_size = buf_pool.curr_size;
@ -4176,17 +4179,17 @@ void buf_stats_get_pool_info(buf_pool_info_t *pool_info)
pool_info->free_list_len = UT_LIST_GET_LEN(buf_pool.free);
mysql_mutex_lock(&buf_pool.flush_list_mutex);
pool_info->flush_list_len = UT_LIST_GET_LEN(buf_pool.flush_list);
pool_info->n_pend_unzip = UT_LIST_GET_LEN(buf_pool.unzip_LRU);
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
pool_info->n_pend_reads = buf_pool.n_pend_reads;
pool_info->n_pending_flush_lru = buf_pool.n_flush_LRU;
pool_info->n_pending_flush_lru = buf_pool.n_flush_LRU_;
pool_info->n_pending_flush_list = buf_pool.n_flush_list;
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
pool_info->n_pending_flush_list = buf_pool.n_flush_list_;
current_time = time(NULL);
time_elapsed = 0.001 + difftime(current_time,

View file

@ -669,6 +669,13 @@ void buf_dblwr_t::flush_buffered_writes_completed(const IORequest &request)
ut_d(buf_dblwr_check_page_lsn(*bpage, static_cast<const byte*>(frame)));
}
const lsn_t lsn= mach_read_from_8(my_assume_aligned<8>
(FIL_PAGE_LSN +
static_cast<const byte*>(frame)));
ut_ad(lsn);
ut_ad(lsn >= bpage->oldest_modification());
if (lsn > log_sys.get_flushed_lsn())
log_write_up_to(lsn, true);
e.request.node->space->io(e.request, bpage->physical_offset(), e_size,
frame, bpage);
}
@ -682,7 +689,6 @@ void buf_dblwr_t::flush_buffered_writes()
{
if (!is_initialised() || !srv_use_doublewrite_buf)
{
os_aio_wait_until_no_pending_writes();
fil_flush_file_spaces();
return;
}

File diff suppressed because it is too large Load diff

View file

@ -108,7 +108,7 @@ uint buf_LRU_old_threshold_ms;
/** Remove bpage from buf_pool.LRU and buf_pool.page_hash.
If bpage->state() == BUF_BLOCK_ZIP_PAGE && !bpage->oldest_modification(),
If bpage->state() == BUF_BLOCK_ZIP_PAGE && bpage->oldest_modification() <= 1,
the object will be freed.
@param bpage buffer block
@ -242,8 +242,8 @@ static bool buf_LRU_free_from_common_LRU_list(ulint limit)
buf_pool.lru_scan_itr.set(prev);
const auto accessed = bpage->is_accessed();
if (!bpage->oldest_modification()
&& buf_LRU_free_page(bpage, true)) {
if (buf_LRU_free_page(bpage, true)) {
if (!accessed) {
/* Keep track of pages that are evicted without
ever being accessed. This gives us a measure of
@ -449,8 +449,8 @@ retry:
#ifndef DBUG_OFF
not_found:
#endif
buf_flush_wait_batch_end(true);
mysql_mutex_unlock(&buf_pool.mutex);
buf_flush_wait_batch_end_acquiring_mutex(true);
if (n_iterations > 20 && !buf_lru_free_blocks_error_printed
&& srv_buf_pool_old_size == srv_buf_pool_size) {
@ -487,7 +487,7 @@ not_found:
involved (particularly in case of ROW_FORMAT=COMPRESSED pages). We
can do that in a separate patch sometime in future. */
if (!buf_flush_lists(innodb_lru_flush_size, 0)) {
if (!buf_flush_LRU(innodb_lru_flush_size)) {
MONITOR_INC(MONITOR_LRU_SINGLE_FLUSH_FAILURE_COUNT);
++flush_failures;
}
@ -801,20 +801,33 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
const ulint fold = id.fold();
page_hash_latch* hash_lock = buf_pool.page_hash.lock_get(fold);
hash_lock->write_lock();
lsn_t oldest_modification = bpage->oldest_modification();
if (UNIV_UNLIKELY(!bpage->can_relocate())) {
/* Do not free buffer fixed and I/O-fixed blocks. */
goto func_exit;
}
if (oldest_modification == 1) {
mysql_mutex_lock(&buf_pool.flush_list_mutex);
oldest_modification = bpage->oldest_modification();
if (oldest_modification) {
ut_ad(oldest_modification == 1);
buf_pool.delete_from_flush_list(bpage);
}
mysql_mutex_unlock(&buf_pool.flush_list_mutex);
ut_ad(!bpage->oldest_modification());
oldest_modification = 0;
}
if (zip || !bpage->zip.data) {
/* This would completely free the block. */
/* Do not completely free dirty blocks. */
if (bpage->oldest_modification()) {
if (oldest_modification) {
goto func_exit;
}
} else if (bpage->oldest_modification()
} else if (oldest_modification
&& bpage->state() != BUF_BLOCK_FILE_PAGE) {
func_exit:
hash_lock->write_unlock();

View file

@ -40,11 +40,6 @@ Created 1/8/1996 Heikki Tuuri
#include "sql_table.h"
#include <mysql/service_thd_mdl.h>
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
/** Flag to control insert buffer debugging. */
extern uint ibuf_debug;
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
#include "btr0btr.h"
#include "btr0cur.h"
#include "btr0sea.h"

View file

@ -1079,7 +1079,7 @@ func_exit:
mtr.commit();
/* 4 - sync tablespace before publishing crypt data */
while (buf_flush_dirty_pages(space->id));
while (buf_flush_list_space(space));
/* 5 - publish crypt data */
mysql_mutex_lock(&fil_crypt_threads_mutex);
@ -1820,7 +1820,7 @@ fil_crypt_rotate_page(
if (block->page.status == buf_page_t::FREED) {
/* Do not modify freed pages to avoid an assertion
failure on recovery.*/
} else if (block->page.oldest_modification()) {
} else if (block->page.oldest_modification() > 1) {
/* Do not unnecessarily touch pages that are
already dirty. */
} else if (space->is_stopping()) {
@ -1970,14 +1970,7 @@ fil_crypt_flush_space(
if (end_lsn > 0 && !space->is_stopping()) {
ulint sum_pages = 0;
const ulonglong start = my_interval_timer();
do {
ulint n_dirty= buf_flush_dirty_pages(state->space->id);
if (!n_dirty) {
break;
}
sum_pages += n_dirty;
} while (!space->is_stopping());
while (buf_flush_list_space(space, &sum_pages));
if (sum_pages) {
const ulonglong end = my_interval_timer();

View file

@ -1642,9 +1642,7 @@ void fil_close_tablespace(ulint id)
can no longer read more pages of this tablespace to buf_pool.
Thus we can clean the tablespace out of buf_pool
completely and permanently. */
while (buf_flush_dirty_pages(id));
/* Ensure that all asynchronous IO is completed. */
os_aio_wait_until_no_pending_writes();
while (buf_flush_list_space(space));
ut_ad(space->is_stopping());
/* If it is a delete then also delete any generated files, otherwise

View file

@ -987,9 +987,9 @@ static SHOW_VAR innodb_status_variables[]= {
SHOW_SIZE_T},
{"os_log_written", &export_vars.innodb_os_log_written, SHOW_SIZE_T},
{"page_size", &srv_page_size, SHOW_ULONG},
{"pages_created", &export_vars.innodb_pages_created, SHOW_SIZE_T},
{"pages_read", &export_vars.innodb_pages_read, SHOW_SIZE_T},
{"pages_written", &export_vars.innodb_pages_written, SHOW_SIZE_T},
{"pages_created", &buf_pool.stat.n_pages_created, SHOW_SIZE_T},
{"pages_read", &buf_pool.stat.n_pages_read, SHOW_SIZE_T},
{"pages_written", &buf_pool.stat.n_pages_written, SHOW_SIZE_T},
{"row_lock_current_waits", &export_vars.innodb_row_lock_current_waits,
SHOW_SIZE_T},
{"row_lock_time", &export_vars.innodb_row_lock_time, SHOW_LONGLONG},

View file

@ -672,6 +672,16 @@ private:
/** Count of how manyfold this block is currently bufferfixed. */
Atomic_counter<uint32_t> buf_fix_count_;
/** log sequence number of the START of the log entry written of the
oldest modification to this block which has not yet been written
to the data file;
0 if no modifications are pending;
1 if no modifications are pending, but the block is in buf_pool.flush_list;
2 if modifications are pending, but the block is not in buf_pool.flush_list
(because id().space() is the temporary tablespace). */
Atomic_counter<lsn_t> oldest_modification_;
/** type of pending I/O operation; protected by buf_pool.mutex
if in_LRU_list */
Atomic_relaxed<buf_io_fix> io_fix_;
@ -721,12 +731,6 @@ public:
or if state() is BUF_BLOCK_MEMORY or BUF_BLOCK_REMOVE_HASH. */
UT_LIST_NODE_T(buf_page_t) list;
private:
/** log sequence number of the START of the log entry written of the
oldest modification to this block which has not yet been written
to the data file; 0 if no modifications are pending. */
Atomic_counter<lsn_t> oldest_modification_;
public:
/** @name LRU replacement algorithm fields.
Protected by buf_pool.mutex. */
/* @{ */
@ -841,12 +845,19 @@ public:
inline void set_io_fix(buf_io_fix io_fix);
inline void set_corrupt_id();
/** @return the oldest modification */
/** @return the log sequence number of the oldest pending modification
@retval 0 if the block is not in buf_pool.flush_list
@retval 1 if the block is in buf_pool.flush_list but not modified
@retval 2 if the block belongs to the temporary tablespace and
has unwritten changes */
lsn_t oldest_modification() const { return oldest_modification_; }
/** Set oldest_modification when adding to buf_pool.flush_list */
inline void set_oldest_modification(lsn_t lsn);
/** Clear oldest_modification when removing from buf_pool.flush_list */
inline void clear_oldest_modification();
/** Note that a block is no longer dirty, while not removing
it from buf_pool.flush_list */
inline void clear_oldest_modification(bool temporary);
/** Notify that a page in a temporary tablespace has been modified. */
void set_temp_modified()
@ -854,7 +865,7 @@ public:
ut_ad(fsp_is_system_temporary(id().space()));
ut_ad(state() == BUF_BLOCK_FILE_PAGE);
ut_ad(!oldest_modification());
oldest_modification_= 1;
oldest_modification_= 2;
}
/** Prepare to release a file page to buf_pool.free. */
@ -1462,23 +1473,24 @@ public:
inline buf_block_t *block_from_ahi(const byte *ptr) const;
#endif /* BTR_CUR_HASH_ADAPT */
/** @return the block that was made dirty the longest time ago */
const buf_page_t *get_oldest_modified() const
{
mysql_mutex_assert_owner(&flush_list_mutex);
const buf_page_t *bpage= UT_LIST_GET_LAST(flush_list);
ut_ad(!bpage || !fsp_is_system_temporary(bpage->id().space()));
ut_ad(!bpage || bpage->oldest_modification());
return bpage;
}
/**
@return the smallest oldest_modification lsn for any page
@retval empty_lsn if all modified persistent pages have been flushed */
lsn_t get_oldest_modification(lsn_t empty_lsn) const
lsn_t get_oldest_modification(lsn_t empty_lsn)
{
const buf_page_t *bpage= get_oldest_modified();
return bpage ? bpage->oldest_modification() : empty_lsn;
mysql_mutex_assert_owner(&flush_list_mutex);
while (buf_page_t *bpage= UT_LIST_GET_LAST(flush_list))
{
ut_ad(!fsp_is_system_temporary(bpage->id().space()));
lsn_t lsn= bpage->oldest_modification();
if (lsn != 1)
{
ut_ad(lsn > 2);
return lsn;
}
delete_from_flush_list(bpage);
}
return empty_lsn;
}
/** Determine if a buffer block was created by chunk_t::create().
@ -1692,15 +1704,18 @@ public:
/** Buffer pool mutex */
MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex;
/** Number of pending LRU flush. */
Atomic_counter<ulint> n_flush_LRU;
/** Number of pending LRU flush; protected by mutex. */
ulint n_flush_LRU_;
/** broadcast when n_flush_LRU reaches 0; protected by mutex */
pthread_cond_t done_flush_LRU;
/** Number of pending flush_list flush. */
Atomic_counter<ulint> n_flush_list;
/** Number of pending flush_list flush; protected by mutex */
ulint n_flush_list_;
/** broadcast when n_flush_list reaches 0; protected by mutex */
pthread_cond_t done_flush_list;
TPOOL_SUPPRESS_TSAN ulint n_flush_LRU() const { return n_flush_LRU_; }
TPOOL_SUPPRESS_TSAN ulint n_flush_list() const { return n_flush_list_; }
/** @name General fields */
/* @{ */
ulint curr_pool_size; /*!< Current pool size in bytes */
@ -1875,8 +1890,8 @@ public:
last_activity_count= activity_count;
}
// n_flush_LRU + n_flush_list is approximately COUNT(io_fix()==BUF_IO_WRITE)
// in flush_list
// n_flush_LRU() + n_flush_list()
// is approximately COUNT(io_fix()==BUF_IO_WRITE) in flush_list
unsigned freed_page_clock;/*!< a sequence number used
to count the number of buffer
@ -1961,13 +1976,35 @@ public:
/** @return whether any I/O is pending */
bool any_io_pending() const
{
return n_pend_reads || n_flush_LRU || n_flush_list;
return n_pend_reads || n_flush_LRU() || n_flush_list();
}
/** @return total amount of pending I/O */
ulint io_pending() const
{
return n_pend_reads + n_flush_LRU + n_flush_list;
return n_pend_reads + n_flush_LRU() + n_flush_list();
}
private:
/** Remove a block from the flush list. */
inline void delete_from_flush_list_low(buf_page_t *bpage);
/** Remove a block from flush_list.
@param bpage buffer pool page
@param clear whether to invoke buf_page_t::clear_oldest_modification() */
void delete_from_flush_list(buf_page_t *bpage, bool clear);
public:
/** Remove a block from flush_list.
@param bpage buffer pool page */
void delete_from_flush_list(buf_page_t *bpage)
{ delete_from_flush_list(bpage, true); }
/** Insert a modified block into the flush list.
@param block modified block
@param lsn start LSN of the mini-transaction that modified the block */
void insert_into_flush_list(buf_block_t *block, lsn_t lsn);
/** Free a page whose underlying file page has been freed. */
inline void release_freed_page(buf_page_t *bpage);
private:
/** Temporary memory for page_compressed and encrypted I/O */
struct io_buf_t
@ -2080,7 +2117,7 @@ inline void buf_page_t::set_corrupt_id()
switch (oldest_modification()) {
case 0:
break;
case 1:
case 2:
ut_ad(fsp_is_system_temporary(id().space()));
ut_d(oldest_modification_= 0); /* for buf_LRU_block_free_non_file_page() */
break;
@ -2106,7 +2143,7 @@ inline void buf_page_t::set_corrupt_id()
inline void buf_page_t::set_oldest_modification(lsn_t lsn)
{
mysql_mutex_assert_owner(&buf_pool.flush_list_mutex);
ut_ad(!oldest_modification());
ut_ad(oldest_modification() <= 1);
oldest_modification_= lsn;
}
@ -2121,13 +2158,27 @@ inline void buf_page_t::clear_oldest_modification()
oldest_modification_= 0;
}
/** Note that a block is no longer dirty, while not removing
it from buf_pool.flush_list */
inline void buf_page_t::clear_oldest_modification(bool temporary)
{
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
ut_ad(temporary == fsp_is_system_temporary(id().space()));
ut_ad(io_fix_ == BUF_IO_WRITE);
ut_ad(temporary ? oldest_modification() == 2 : oldest_modification() > 2);
oldest_modification_= !temporary;
}
/** @return whether the block is modified and ready for flushing */
inline bool buf_page_t::ready_for_flush() const
{
mysql_mutex_assert_owner(&buf_pool.mutex);
ut_ad(in_LRU_list);
ut_a(in_file());
return oldest_modification() && io_fix_ == BUF_IO_NONE;
ut_ad(fsp_is_system_temporary(id().space())
? oldest_modification() == 2
: oldest_modification() > 2);
return io_fix_ == BUF_IO_NONE;
}
/** @return whether the block can be relocated in memory.
@ -2204,7 +2255,7 @@ MEMORY: is not in free list, LRU list, or flush list, nor page
hash table
FILE_PAGE: space and offset are defined, is in page hash table
if io_fix == BUF_IO_WRITE,
buf_pool.n_flush_LRU > 0 || buf_pool.n_flush_list > 0
buf_pool.n_flush_LRU() || buf_pool.n_flush_list()
(1) if buf_fix_count == 0, then
is in LRU list, not in free list

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2014, 2020, MariaDB Corporation.
Copyright (c) 2014, 2021, 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
@ -56,12 +56,6 @@ the list as they age towards the tail of the LRU.
@param id tablespace identifier */
void buf_flush_remove_pages(ulint id);
/** Try to flush all the dirty pages that belong to a given tablespace.
@param id tablespace identifier
@return number dirty pages that there were for this tablespace */
ulint buf_flush_dirty_pages(ulint id)
MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Relocates a buffer control block on the flush_list.
Note that it is assumed that the contents of bpage has already been
@ -95,10 +89,23 @@ buf_flush_init_for_writing(
/** Write out dirty blocks from buf_pool.flush_list.
@param max_n wished maximum mumber of blocks flushed
@param lsn buf_pool.get_oldest_modification(LSN_MAX) target (0=LRU flush)
@param lsn buf_pool.get_oldest_modification(LSN_MAX) target
@return the number of processed pages
@retval 0 if a batch of the same type (lsn==0 or lsn!=0) is already running */
ulint buf_flush_lists(ulint max_n, lsn_t lsn);
@retval 0 if a buf_pool.flush_list batch is already running */
ulint buf_flush_list(ulint max_n= ULINT_UNDEFINED, lsn_t lsn= LSN_MAX);
/** Try to flush dirty pages that belong to a given tablespace.
@param space tablespace
@param n_flushed number of pages written
@return whether the flush for some pages might not have been initiated */
bool buf_flush_list_space(fil_space_t *space, ulint *n_flushed= nullptr)
MY_ATTRIBUTE((warn_unused_result));
/** Write out dirty blocks from buf_pool.LRU.
@param max_n wished maximum mumber of blocks flushed
@return the number of processed pages
@retval 0 if a buf_pool.LRU batch is already running */
ulint buf_flush_LRU(ulint max_n);
/** Wait until a flush batch ends.
@param lru true=buf_pool.LRU; false=buf_pool.flush_list */
@ -106,9 +113,10 @@ void buf_flush_wait_batch_end(bool lru);
/** Wait until all persistent pages are flushed up to a limit.
@param sync_lsn buf_pool.get_oldest_modification(LSN_MAX) to wait for */
ATTRIBUTE_COLD void buf_flush_wait_flushed(lsn_t sync_lsn);
/** If innodb_flush_sync=ON, initiate a furious flush.
@param lsn buf_pool.get_oldest_modification(LSN_MAX) target */
void buf_flush_ahead(lsn_t lsn);
/** Initiate more eager page flushing if the log checkpoint age is too old.
@param lsn buf_pool.get_oldest_modification(LSN_MAX) target
@param furious true=furious flushing, false=limit to innodb_io_capacity */
ATTRIBUTE_COLD void buf_flush_ahead(lsn_t lsn, bool furious);
/********************************************************************//**
This function should be called at a mini-transaction commit, if a page was

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2019, 2020, MariaDB Corporation.
Copyright (c) 2019, 2021, 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
@ -26,17 +26,7 @@ Created 11/5/1995 Heikki Tuuri
#include "assume_aligned.h"
#include "buf0buf.h"
#include "mtr0mtr.h"
#include "srv0srv.h"
#include "fsp0types.h"
/********************************************************************//**
Inserts a modified block into the flush list. */
void
buf_flush_insert_into_flush_list(
/*=============================*/
buf_block_t* block, /*!< in/out: block which is modified */
lsn_t lsn); /*!< in: oldest modification */
/********************************************************************//**
This function should be called at a mini-transaction commit, if a page was
@ -52,8 +42,7 @@ buf_flush_note_modification(
lsn_t end_lsn) /*!< in: end lsn of the mtr that
modified this block */
{
ut_ad(!srv_read_only_mode
|| fsp_is_system_temporary(block->page.id().space()));
ut_ad(!srv_read_only_mode);
ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE);
ut_ad(block->page.buf_fix_count());
ut_ad(mach_read_from_8(block->frame + FIL_PAGE_LSN) <= end_lsn);
@ -65,12 +54,12 @@ buf_flush_note_modification(
const lsn_t oldest_modification = block->page.oldest_modification();
if (oldest_modification) {
if (oldest_modification > 1) {
ut_ad(oldest_modification <= start_lsn);
} else if (!fsp_is_system_temporary(block->page.id().space())) {
buf_flush_insert_into_flush_list(block, start_lsn);
} else {
} else if (fsp_is_system_temporary(block->page.id().space())) {
block->page.set_temp_modified();
} else {
buf_pool.insert_into_flush_list(block, start_lsn);
}
srv_stats.buf_pool_write_requests.inc();

View file

@ -588,6 +588,17 @@ public:
@return number of buffer count added by this mtr */
uint32_t get_fix_count(const buf_block_t *block) const;
/** type of page flushing is needed during commit() */
enum page_flush_ahead
{
/** no need to trigger page cleaner */
PAGE_FLUSH_NO= 0,
/** asynchronous flushing is needed */
PAGE_FLUSH_ASYNC,
/** furious flushing is needed */
PAGE_FLUSH_SYNC
};
private:
/** Log a write of a byte string to a page.
@param block buffer page
@ -621,7 +632,7 @@ private:
/** Append the redo log records to the redo log buffer.
@param len number of bytes to write
@return {start_lsn,flush_ahead} */
inline std::pair<lsn_t,bool> finish_write(ulint len);
inline std::pair<lsn_t,page_flush_ahead> finish_write(ulint len);
/** Release the resources */
inline void release_resources();

View file

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, 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
@ -32,7 +32,7 @@ inline bool mtr_t::is_block_dirtied(const buf_block_t *block)
{
ut_ad(block->page.state() == BUF_BLOCK_FILE_PAGE);
ut_ad(block->page.buf_fix_count());
return !block->page.oldest_modification();
return block->page.oldest_modification() <= 1;
}
/**

View file

@ -1111,10 +1111,9 @@ void os_aio_free();
@retval DB_IO_ERROR on I/O error */
dberr_t os_aio(const IORequest &type, void *buf, os_offset_t offset, size_t n);
/** Waits until there are no pending writes in os_aio_write_array. There can
be other, synchronous, pending writes. */
void
os_aio_wait_until_no_pending_writes();
/** Wait until there are no pending asynchronous writes.
Only used on FLUSH TABLES...FOR EXPORT. */
void os_aio_wait_until_no_pending_writes();
/** Wait until all pending asynchronous reads have completed. */
void os_aio_wait_until_no_pending_reads();

View file

@ -756,9 +756,6 @@ struct export_var_t{
ulint innodb_os_log_fsyncs; /*!< n_log_flushes */
ulint innodb_os_log_pending_writes; /*!< srv_os_log_pending_writes */
ulint innodb_os_log_pending_fsyncs; /*!< n_pending_log_flushes */
ulint innodb_pages_created; /*!< buf_pool.stat.n_pages_created */
ulint innodb_pages_read; /*!< buf_pool.stat.n_pages_read*/
ulint innodb_pages_written; /*!< buf_pool.stat.n_pages_written */
ulint innodb_row_lock_waits; /*!< srv_n_lock_wait_count */
ulint innodb_row_lock_current_waits; /*!< srv_n_lock_wait_current_count */
int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time

View file

@ -404,12 +404,12 @@ void mtr_t::commit()
{
ut_ad(!srv_read_only_mode || m_log_mode == MTR_LOG_NO_REDO);
std::pair<lsn_t,bool> lsns;
std::pair<lsn_t,page_flush_ahead> lsns;
if (const ulint len= prepare_write())
lsns= finish_write(len);
else
lsns= { m_commit_lsn, false };
lsns= { m_commit_lsn, PAGE_FLUSH_NO };
if (m_made_dirty)
mysql_mutex_lock(&log_sys.flush_order_mutex);
@ -449,8 +449,8 @@ void mtr_t::commit()
m_memo.for_each_block_in_reverse(CIterate<ReleaseLatches>());
if (lsns.second)
buf_flush_ahead(m_commit_lsn);
if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO))
buf_flush_ahead(m_commit_lsn, lsns.second == PAGE_FLUSH_SYNC);
if (m_made_dirty)
srv_stats.log_write_requests.inc();
@ -767,7 +767,7 @@ static void log_write_low(const void *str, size_t size)
/** Close the log at mini-transaction commit.
@return whether buffer pool flushing is needed */
static bool log_close(lsn_t lsn)
static mtr_t::page_flush_ahead log_close(lsn_t lsn)
{
mysql_mutex_assert_owner(&log_sys.mutex);
ut_ad(lsn == log_sys.get_lsn());
@ -790,7 +790,9 @@ static bool log_close(lsn_t lsn)
const lsn_t checkpoint_age= lsn - log_sys.last_checkpoint_lsn;
if (UNIV_UNLIKELY(checkpoint_age >= log_sys.log_capacity))
if (UNIV_UNLIKELY(checkpoint_age >= log_sys.log_capacity) &&
/* silence message on create_log_file() after the log had been deleted */
checkpoint_age != lsn)
{
time_t t= time(nullptr);
if (!log_close_warned || difftime(t, log_close_warn_time) > 15)
@ -799,15 +801,17 @@ static bool log_close(lsn_t lsn)
log_close_warn_time= t;
ib::error() << "The age of the last checkpoint is " << checkpoint_age
<< ", which exceeds the log capacity "
<< log_sys.log_capacity << ".";
<< ", which exceeds the log capacity "
<< log_sys.log_capacity << ".";
}
}
else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_modified_age_async))
return mtr_t::PAGE_FLUSH_NO;
else if (UNIV_LIKELY(checkpoint_age <= log_sys.max_checkpoint_age))
return false;
return mtr_t::PAGE_FLUSH_ASYNC;
log_sys.set_check_flush_or_checkpoint();
return true;
return mtr_t::PAGE_FLUSH_SYNC;
}
/** Write the block contents to the REDO log */
@ -871,8 +875,8 @@ inline ulint mtr_t::prepare_write()
/** Append the redo log records to the redo log buffer.
@param len number of bytes to write
@return {start_lsn,flush_ahead_lsn} */
inline std::pair<lsn_t,bool> mtr_t::finish_write(ulint len)
@return {start_lsn,flush_ahead} */
inline std::pair<lsn_t,mtr_t::page_flush_ahead> mtr_t::finish_write(ulint len)
{
ut_ad(m_log_mode == MTR_LOG_ALL);
mysql_mutex_assert_owner(&log_sys.mutex);
@ -888,19 +892,19 @@ inline std::pair<lsn_t,bool> mtr_t::finish_write(ulint len)
m_commit_lsn = log_reserve_and_write_fast(front->begin(), len,
&start_lsn);
if (m_commit_lsn) {
return std::make_pair(start_lsn, false);
if (!m_commit_lsn) {
goto piecewise;
}
} else {
piecewise:
/* Open the database log for log_write_low */
start_lsn = log_reserve_and_open(len);
mtr_write_log write_log;
m_log.for_each_block(write_log);
m_commit_lsn = log_sys.get_lsn();
}
/* Open the database log for log_write_low */
start_lsn = log_reserve_and_open(len);
mtr_write_log write_log;
m_log.for_each_block(write_log);
m_commit_lsn = log_sys.get_lsn();
bool flush = log_close(m_commit_lsn);
DBUG_EXECUTE_IF("ib_log_flush_ahead", flush=true;);
page_flush_ahead flush= log_close(m_commit_lsn);
DBUG_EXECUTE_IF("ib_log_flush_ahead", flush = PAGE_FLUSH_SYNC;);
return std::make_pair(start_lsn, flush);
}

View file

@ -3775,8 +3775,8 @@ static void os_aio_wait_until_no_pending_writes_low()
tpool::tpool_wait_end();
}
/** Waits until there are no pending writes. There can
be other, synchronous, pending writes. */
/** Wait until there are no pending asynchronous writes.
Only used on FLUSH TABLES...FOR EXPORT. */
void os_aio_wait_until_no_pending_writes()
{
os_aio_wait_until_no_pending_writes_low();

View file

@ -4213,7 +4213,17 @@ row_import_for_mysql(
/* Ensure that all pages dirtied during the IMPORT make it to disk.
The only dirty pages generated should be from the pessimistic purge
of delete marked records that couldn't be purged in Phase I. */
while (buf_flush_dirty_pages(prebuilt->table->space_id));
while (buf_flush_list_space(prebuilt->table->space));
for (ulint count = 0; prebuilt->table->space->referenced(); count++) {
/* Issue a warning every 10.24 seconds, starting after
2.56 seconds */
if ((count & 511) == 128) {
ib::warn() << "Waiting for flush to complete on "
<< prebuilt->table->name;
}
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
ib::info() << "Phase IV - Flush complete";
prebuilt->table->space->set_imported();

View file

@ -536,7 +536,7 @@ row_quiesce_table_start(
}
}
while (buf_flush_dirty_pages(table->space_id)) {
while (buf_flush_list_space(table->space)) {
if (trx_is_interrupted(trx)) {
goto aborted;
}

View file

@ -1092,12 +1092,6 @@ srv_export_innodb_status(void)
export_vars.innodb_log_writes = srv_stats.log_writes;
export_vars.innodb_pages_created = buf_pool.stat.n_pages_created;
export_vars.innodb_pages_read = buf_pool.stat.n_pages_read;
export_vars.innodb_pages_written = buf_pool.stat.n_pages_written;
mysql_mutex_lock(&lock_sys.wait_mutex);
export_vars.innodb_row_lock_waits = lock_sys.get_wait_cumulative();

View file

@ -672,7 +672,7 @@ not_free:
mini-transaction commit and the server was killed, then
discarding the to-be-trimmed pages without flushing would
break crash recovery. So, we cannot avoid the write. */
while (buf_flush_dirty_pages(space.id));
while (buf_flush_list_space(&space));
log_free_check();