summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2023-01-17 17:52:16 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2023-01-17 17:52:16 +0200
commit489b556947087f7606224d6fc09f302eabef14c8 (patch)
tree7fd6b5c2e7fb89c0c75d7b753e753e3cce051fe0
parent834650c7cfb53773bbb64b6ab874e23b43b8c874 (diff)
downloadmariadb-git-489b556947087f7606224d6fc09f302eabef14c8.tar.gz
MDEV-30422 Merge new release of InnoDB 5.7.41 to 10.3
MySQL 5.7.41 includes one InnoDB change mysql/mysql-server@d2d6b2dd00f709bc528386009150d4bc726e25a0 that seems to be applicable to MariaDB Server 10.3 and 10.4. Even though commit 5b9ee8d8193a8c7a8ebdd35eedcadc3ae78e7fc1 seems to have fixed sporadic failures on our CI systems, it is theoretically possible that another race condition remained. buf_flush_page_cleaner_coordinator(): In the final loop, wait also for buf_get_n_pending_read_ios() to reach 0. In this way, if a secondary index leaf page was read into the buffer pool and ibuf_merge_or_delete_for_page() modified that page or some change buffer pages, the flush loop would execute until the buffer pool really is in a clean state. This potential data corruption bug does not affect MariaDB Server 10.5 or later, thanks to commit b42294bc6409794bdbd2051b32fa079d81cea61d which removed change buffer merges that are not explicitly requested.
-rw-r--r--storage/innobase/buf/buf0flu.cc15
1 files changed, 11 insertions, 4 deletions
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 6e97be03bdd..b8f8c243a4f 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -3324,20 +3324,27 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(void*)
bool success;
do {
+ /* In case an asynchronous read request was posted by
+ any thread (other than something invoking
+ ibuf_merge_in_background()), it is possible that the
+ change buffer will be merged to the page once the read
+ completes. To avoid race conditions and corruption due
+ to that, we will loop here until there are no pending
+ page read operations. */
+ success = !buf_get_n_pending_read_ios();
pc_request(ULINT_MAX, LSN_MAX);
while (pc_flush_slot() > 0) {}
ulint n_flushed_lru = 0;
ulint n_flushed_list = 0;
- success = pc_wait_finished(&n_flushed_lru, &n_flushed_list);
-
- n_flushed = n_flushed_lru + n_flushed_list;
+ success = pc_wait_finished(&n_flushed_lru, &n_flushed_list)
+ && success && !n_flushed_lru && !n_flushed_list;
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
buf_flush_wait_LRU_batch_end();
- } while (!success || n_flushed > 0);
+ } while (!success);
/* Some sanity checks */
ut_a(srv_get_active_thread_type() == SRV_NONE);