[MDEV-31816] buf_LRU_free_page() does not preserve ROW_FORMAT=COMPRESSED block state Created: 2023-08-01  Updated: 2023-08-01  Resolved: 2023-08-01

Status: Closed
Project: MariaDB Server
Component/s: Storage Engine - InnoDB
Affects Version/s: 10.6, 10.7, 10.8, 10.9, 10.10, 10.11, 11.0, 11.1, 11.2
Fix Version/s: 10.6.15, 10.9.8, 10.10.6, 10.11.5, 11.0.3, 11.1.2, 11.2.1

Type: Bug Priority: Major
Reporter: Marko Mäkelä Assignee: Marko Mäkelä
Resolution: Fixed Votes: 0
Labels: crash

Issue Links:
Relates
relates to MDEV-15528 Avoid writing freed InnoDB pages Closed
relates to MDEV-19738 Doublewrite buffer is unnecessarily u... Closed
relates to MDEV-27058 Buffer page descriptors are too large Closed
relates to MDEV-31386 InnoDB: Failing assertion: page_type ... Closed

 Description   

mleich reproduced what looks like the bug MDEV-31386, in a branch where the fix is present:

ssh pluto
rr replay /data/results/1690818484/MDEV-31386-Rebirth/1/rr/latest-trace

2023-07-31 17:25:55 0x70d307fff700  InnoDB: Assertion failure in file /data/Server/bb-11.2-MDEV-14795_1D/storage/innobase/handler/i_s.cc line 3842
InnoDB: Failing assertion: page_type == i_s_page_type[page_type].type_value

The block descriptor state had been last modified by buf_LRU_free_page(), which had discarded the uncompressed page frame of a ROW_FORMAT=COMPRESSED page. The block descriptor state at that point was buf_page_t::FREED, but it got lost due to an assignment that had better be an increment of the buffer-fix count:

diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 6cc4f1c3987..3ba31da2ffc 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -851,7 +851,12 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip)
 		mysql_mutex_lock(&buf_pool.flush_list_mutex);
 		new (b) buf_page_t(*bpage);
 		b->frame = nullptr;
-		b->set_state(buf_page_t::UNFIXED + 1);
+		{
+			ut_d(uint32_t s=) b->fix();
+			ut_ad(s == buf_page_t::FREED
+			      || s == buf_page_t::UNFIXED
+			      || s == buf_page_t::REINIT);
+		}
 		break;
 	default:
 		if (zip || !bpage->zip.data || !bpage->frame) {

For testing, I added a statement that would output of the value s (the state of the block descriptor before incrementing the buffer-fix count). All three values (FREED, UNFIXED, REINIT) were observed while executing the test innodb_zip.wl5522_zip.

As far as I can tell, the main impact of this bug is that a crash like MDEV-31386 is possible when accessing the views INFORMATION_SCHEMA.INNODB_BUFFER_PAGE or INFORMATION_SCHEMA.INNODB_BUFFER_PAGE_LRU at an unfortunate moment. A minor performance impact is that there may be unnecessary writes (MDEV-15528) or doublewrites (MDEV-19738) of affected ROW_FORMAT=COMPRESSED pages.


Generated at Thu Feb 08 10:26:41 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.