Skip to content

Commit 477285c

Browse files
committed
MDEV-31253 Freed data pages are not always being scrubbed
fil_space_t::flush_freed(): Renamed from buf_flush_freed_pages(); this is a backport of aa45850 from 10.6. Invoke log_write_up_to() on last_freed_lsn, instead of avoiding the operation when the log has not yet been written. A more costly alternative would be that log_checkpoint() would invoke this function on every affected tablespace.
1 parent 279d012 commit 477285c

File tree

3 files changed

+54
-39
lines changed

3 files changed

+54
-39
lines changed

storage/innobase/buf/buf0flu.cc

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,63 +1042,65 @@ static page_id_t buf_flush_check_neighbors(const fil_space_t &space,
10421042
return i;
10431043
}
10441044

1045-
MY_ATTRIBUTE((nonnull, warn_unused_result))
1046-
/** Write punch-hole or zeroes of the freed ranges when
1047-
innodb_immediate_scrub_data_uncompressed from the freed ranges.
1048-
@param space tablespace which may contain ranges of freed pages
1049-
@param writable whether the tablespace is writable
1045+
MY_ATTRIBUTE((warn_unused_result))
1046+
/** Apply freed_ranges to the file.
1047+
@param writable whether the file is writable
10501048
@return number of pages written or hole-punched */
1051-
static uint32_t buf_flush_freed_pages(fil_space_t *space, bool writable)
1049+
uint32_t fil_space_t::flush_freed(bool writable)
10521050
{
1053-
const bool punch_hole= space->punch_hole;
10541051
if (!punch_hole && !srv_immediate_scrub_data_uncompressed)
10551052
return 0;
10561053

10571054
mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
10581055
mysql_mutex_assert_not_owner(&buf_pool.mutex);
10591056

1060-
space->freed_range_mutex.lock();
1061-
if (space->freed_ranges.empty() ||
1062-
log_sys.get_flushed_lsn() < space->get_last_freed_lsn())
1057+
for (;;)
10631058
{
1064-
space->freed_range_mutex.unlock();
1065-
return 0;
1059+
freed_range_mutex.lock();
1060+
if (freed_ranges.empty())
1061+
{
1062+
freed_range_mutex.unlock();
1063+
return 0;
1064+
}
1065+
const lsn_t flush_lsn= last_freed_lsn;
1066+
if (log_sys.get_flushed_lsn() >= flush_lsn)
1067+
break;
1068+
freed_range_mutex.unlock();
1069+
log_write_up_to(flush_lsn, true);
10661070
}
10671071

1068-
const unsigned physical_size{space->physical_size()};
1072+
const unsigned physical{physical_size()};
10691073

1070-
range_set freed_ranges= std::move(space->freed_ranges);
1074+
range_set freed= std::move(freed_ranges);
10711075
uint32_t written= 0;
10721076

10731077
if (!writable);
10741078
else if (punch_hole)
10751079
{
1076-
for (const auto &range : freed_ranges)
1080+
for (const auto &range : freed)
10771081
{
10781082
written+= range.last - range.first + 1;
1079-
space->reacquire();
1080-
space->io(IORequest(IORequest::PUNCH_RANGE),
1081-
os_offset_t{range.first} * physical_size,
1082-
(range.last - range.first + 1) * physical_size,
1083-
nullptr);
1083+
reacquire();
1084+
io(IORequest(IORequest::PUNCH_RANGE),
1085+
os_offset_t{range.first} * physical,
1086+
(range.last - range.first + 1) * physical, nullptr);
10841087
}
10851088
}
10861089
else
10871090
{
1088-
for (const auto &range : freed_ranges)
1091+
for (const auto &range : freed)
10891092
{
10901093
written+= range.last - range.first + 1;
10911094
for (os_offset_t i= range.first; i <= range.last; i++)
10921095
{
1093-
space->reacquire();
1094-
space->io(IORequest(IORequest::WRITE_ASYNC),
1095-
i * physical_size, physical_size,
1096-
const_cast<byte*>(field_ref_zero));
1096+
reacquire();
1097+
io(IORequest(IORequest::WRITE_ASYNC), i * physical, physical,
1098+
const_cast<byte*>(field_ref_zero));
10971099
}
10981100
}
10991101
}
11001102

1101-
space->freed_range_mutex.unlock();
1103+
freed_range_mutex.unlock();
11021104
return written;
11031105
}
11041106

@@ -1225,7 +1227,7 @@ static ulint buf_free_from_unzip_LRU_list_batch(ulint max)
12251227
static std::pair<fil_space_t*, uint32_t> buf_flush_space(const uint32_t id)
12261228
{
12271229
if (fil_space_t *space= fil_space_t::get(id))
1228-
return {space, buf_flush_freed_pages(space, true)};
1230+
return {space, space->flush_freed(true)};
12291231
return {nullptr, 0};
12301232
}
12311233

@@ -1617,7 +1619,7 @@ bool buf_flush_list_space(fil_space_t *space, ulint *n_flushed)
16171619

16181620
bool acquired= space->acquire();
16191621
{
1620-
const uint32_t written{buf_flush_freed_pages(space, acquired)};
1622+
const uint32_t written{space->flush_freed(acquired)};
16211623
mysql_mutex_lock(&buf_pool.mutex);
16221624
if (written)
16231625
buf_pool.stat.n_pages_written+= written;

storage/innobase/buf/buf0rea.cc

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,13 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
728728
return count;
729729
}
730730

731+
/** @return whether a page has been freed */
732+
inline bool fil_space_t::is_freed(uint32_t page)
733+
{
734+
std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
735+
return freed_ranges.contains(page);
736+
}
737+
731738
/** Issues read requests for pages which recovery wants to read in.
732739
@param[in] space_id tablespace id
733740
@param[in] page_nos array of page numbers to read, with the
@@ -747,7 +754,7 @@ void buf_read_recv_pages(ulint space_id, const uint32_t* page_nos, ulint n)
747754
for (ulint i = 0; i < n; i++) {
748755

749756
/* Ignore if the page already present in freed ranges. */
750-
if (space->freed_ranges.contains(page_nos[i])) {
757+
if (space->is_freed(page_nos[i])) {
751758
continue;
752759
}
753760

storage/innobase/include/fil0fil.h

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -415,16 +415,16 @@ struct fil_space_t final
415415
punch hole */
416416
boolpunch_hole;
417417

418-
/** mutex to protect freed ranges */
419-
std::mutex freed_range_mutex;
420-
421-
/** Variables to store freed ranges. This can be used to write
422-
zeroes/punch the hole in files. Protected by freed_mutex */
423-
range_set freed_ranges;
418+
private:
419+
/** mutex to protect freed_ranges and last_freed_lsn */
420+
std::mutex freed_range_mutex;
424421

425-
/** Stores last page freed lsn. Protected by freed_mutex */
426-
lsn_tlast_freed_lsn;
422+
/** Ranges of freed page numbers; protected by freed_range_mutex */
423+
range_set freed_ranges;
427424

425+
/** LSN of freeing last page; protected by freed_range_mutex */
426+
lsn_t last_freed_lsn;
427+
public:
428428
ulint magic_n;/*!< FIL_SPACE_MAGIC_N */
429429

430430
/** @return whether doublewrite buffering is needed */
@@ -434,6 +434,14 @@ struct fil_space_t final
434434
buf_dblwr.is_initialised();
435435
}
436436

437+
/** @return whether a page has been freed */
438+
inline bool is_freed(uint32_t page);
439+
440+
/** Apply freed_ranges to the file.
441+
@param writable whether the file is writable
442+
@return number of pages written or hole-punched */
443+
uint32_t flush_freed(bool writable);
444+
437445
/** Append a file to the chain of files of a space.
438446
@param[in] name file name of a file that is not open
439447
@param[in] handle file handle, or OS_FILE_CLOSED
@@ -589,8 +597,6 @@ struct fil_space_t final
589597
/** Close all tablespace files at shutdown */
590598
static void close_all();
591599

592-
/** @return last_freed_lsn */
593-
lsn_t get_last_freed_lsn() { return last_freed_lsn; }
594600
/** Update last_freed_lsn */
595601
void update_last_freed_lsn(lsn_t lsn)
596602
{

0 commit comments

Comments
 (0)