diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2023-01-17 17:52:16 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2023-01-17 17:52:16 +0200 |
commit | 489b556947087f7606224d6fc09f302eabef14c8 (patch) | |
tree | 7fd6b5c2e7fb89c0c75d7b753e753e3cce051fe0 | |
parent | 834650c7cfb53773bbb64b6ab874e23b43b8c874 (diff) | |
download | mariadb-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.cc | 15 |
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); |