Commit 6b91792a authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-29883 Deadlock between InnoDB statistics update and BLOB insert

This is a backport of commit 8b6a308e
from MariaDB Server 10.6.11. No attempt to reproduce the hang
in earlier an earlier version of MariaDB Server than 10.6 was made.

In each caller of fseg_n_reserved_pages() except ibuf_init_at_db_start()
which is a special case for ibuf.index at database startup, we must hold
an index latch that prevents concurrent allocation or freeing of index
pages.

Any operation that allocates or free pages that belong to an index tree
must first acquire an index latch in non-shared mode, and while
holding that, acquire an index root page latch in non-shared mode.

btr_get_size(), btr_get_size_and_reserved(): Assert that a strong enough
index latch is being held.

dict_stats_update_transient_for_index(),
dict_stats_analyze_index(): Acquire a strong enough index latch.

These operations had followed the same order of acquiring latches in
every InnoDB version since the very beginning
(commit c533308a).

The hang was introduced in
commit 2e814d47 which imported
mysql/mysql-server@ac74632293bea967b352d1b472abedeeaa921b98
which failed to strengthen the locking requirements of the function
btr_get_size().
parent fda58467
...@@ -603,7 +603,7 @@ btr_get_size( ...@@ -603,7 +603,7 @@ btr_get_size(
ut_ad(srv_read_only_mode ut_ad(srv_read_only_mode
|| mtr_memo_contains(mtr, dict_index_get_lock(index), || mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_S_LOCK)); MTR_MEMO_SX_LOCK));
if (index->page == FIL_NULL if (index->page == FIL_NULL
|| dict_index_is_online_ddl(index) || dict_index_is_online_ddl(index)
...@@ -657,7 +657,7 @@ btr_get_size_and_reserved( ...@@ -657,7 +657,7 @@ btr_get_size_and_reserved(
ulint dummy; ulint dummy;
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_S_LOCK)); MTR_MEMO_SX_LOCK));
ut_a(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE); ut_a(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE);
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2016, 2019, MariaDB Corporation. Copyright (c) 2016, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -282,7 +282,7 @@ dict_stats_save_defrag_stats( ...@@ -282,7 +282,7 @@ dict_stats_save_defrag_stats(
ulint n_leaf_pages; ulint n_leaf_pages;
ulint n_leaf_reserved; ulint n_leaf_reserved;
mtr.start(); mtr.start();
mtr_s_lock_index(index, &mtr); mtr_sx_lock_index(index, &mtr);
n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES, n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
&n_leaf_pages, &mtr); &n_leaf_pages, &mtr);
mtr.commit(); mtr.commit();
......
/***************************************************************************** /*****************************************************************************
Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2021, MariaDB Corporation. Copyright (c) 2015, 2022, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
...@@ -852,7 +852,7 @@ dict_stats_update_transient_for_index( ...@@ -852,7 +852,7 @@ dict_stats_update_transient_for_index(
ulint size; ulint size;
mtr.start(); mtr.start();
mtr_s_lock_index(index, &mtr); mtr_sx_lock_index(index, &mtr);
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
if (size != ULINT_UNDEFINED) { if (size != ULINT_UNDEFINED) {
...@@ -1945,7 +1945,7 @@ static index_stats_t dict_stats_analyze_index(dict_index_t* index) ...@@ -1945,7 +1945,7 @@ static index_stats_t dict_stats_analyze_index(dict_index_t* index)
DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name()); DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name());
mtr.start(); mtr.start();
mtr_s_lock_index(index, &mtr); mtr_sx_lock_index(index, &mtr);
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
if (size != ULINT_UNDEFINED) { if (size != ULINT_UNDEFINED) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment