From 44df6f35aa690cdac0409b7853468891ade33cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 17 Aug 2023 10:31:28 +0300 Subject: [PATCH] MDEV-31875 ROW_FORMAT=COMPRESSED table: InnoDB: ... Only 0 bytes read buf_read_ahead_random(), buf_read_ahead_linear(): Avoid read-ahead of the last page(s) of ROW_FORMAT=COMPRESSED tablespaces that use a page size of 1024 or 2048 bytes. We invoke os_file_set_size() on integer multiples of 4096 bytes in order to be compatible with the requirements of innodb_flush_method=O_DIRECT regardless of the physical block size of the underlying storage. This change must be null-merged to MariaDB Server 10.5 and later. There, out-of-bounds read-ahead should be handled gracefully by simply discarding the buffer page that had been allocated. Tested by: Matthias Leich --- storage/innobase/buf/buf0rea.cc | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 1ea3070cbda..5ea177dbbd0 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -266,8 +266,24 @@ buf_read_ahead_random(const page_id_t page_id, ulint zip_size, bool ibuf) * buf_read_ahead_random_area; if (fil_space_t* space = fil_space_acquire(page_id.space())) { - high = space->max_page_number_for_io(high); + ulint space_size = space->committed_size; + ulint zip_size = space->zip_size(); space->release(); + /* Avoid read-ahead of the last page(s) of + small-page-size ROW_FORMAT=COMPRESSED tablespaces, + because fil_space_extend_must_retry() would invoke + os_file_set_size() on integer multiples of 4 KiB. */ + switch (UNIV_EXPECT(zip_size, 0)) { + case 1024: + space_size &= ~ulint{3}; + break; + case 2048: + space_size &= ~ulint{1}; + break; + } + if (high > space_size) { + high = space_size; + } } else { return(0); } @@ -531,7 +547,20 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf) if (fil_space_t* space = fil_space_acquire(page_id.space())) { space_size = space->committed_size; + ulint zip_size = space->zip_size(); space->release(); + /* Avoid read-ahead of the last page(s) of + small-page-size ROW_FORMAT=COMPRESSED tablespaces, + because fil_space_extend_must_retry() would invoke + os_file_set_size() on integer multiples of 4 KiB. */ + switch (UNIV_EXPECT(zip_size, 0)) { + case 1024: + space_size &= ~ulint{3}; + break; + case 2048: + space_size &= ~ulint{1}; + break; + } if (high > space_size) { /* The area is not whole */