Skip to content

Commit edbde4a

Browse files
committed
MDEV-24167: Replace fil_space::latch
We must avoid acquiring a latch while we are already holding one. The tablespace latch was being acquired recursively in some operations that allocate or free pages.
1 parent bdd88cf commit edbde4a

File tree

23 files changed

+201
-175
lines changed

23 files changed

+201
-175
lines changed

mysql-test/suite/perfschema/r/sxlock_func.result

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ TRUNCATE TABLE performance_schema.events_waits_current;
77
select name from performance_schema.setup_instruments
88
where name like "wait/synch/sxlock/%" order by name;
99
name
10-
wait/synch/sxlock/innodb/fil_space_latch
1110
wait/synch/sxlock/innodb/index_tree_rw_lock
1211
select name from performance_schema.rwlock_instances
1312
where name in

storage/innobase/btr/btr0btr.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ btr_get_size(
604604
if (!root) {
605605
return ULINT_UNDEFINED;
606606
}
607-
mtr_x_lock_space(index->table->space, mtr);
607+
mtr->x_lock_space(index->table->space);
608608
if (flag == BTR_N_LEAF_PAGES) {
609609
fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF
610610
+ root->frame, &n, mtr);
@@ -652,7 +652,7 @@ btr_get_size_and_reserved(
652652
return ULINT_UNDEFINED;
653653
}
654654

655-
mtr_x_lock_space(index->table->space, mtr);
655+
mtr->x_lock_space(index->table->space);
656656

657657
ulint n = fseg_n_reserved_pages(*root, PAGE_HEADER + PAGE_BTR_SEG_LEAF
658658
+ root->frame, used, mtr);
@@ -691,9 +691,10 @@ btr_page_free_for_ibuf(
691691
@param[in,out] index index tree
692692
@param[in,out] block block to be freed
693693
@param[in,out] mtr mini-transaction
694-
@param[in] blob whether this is freeing a BLOB page */
694+
@param[in] blob whether this is freeing a BLOB page
695+
@param[in] latched whether index->table->space->x_lock() was called */
695696
void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
696-
bool blob)
697+
bool blob, bool space_latched)
697698
{
698699
ut_ad(mtr->memo_contains_flagged(block, MTR_MEMO_PAGE_X_FIX));
699700
#ifdef BTR_CUR_HASH_ADAPT
@@ -726,7 +727,7 @@ void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
726727
? PAGE_HEADER + PAGE_BTR_SEG_LEAF
727728
: PAGE_HEADER + PAGE_BTR_SEG_TOP];
728729
fseg_free_page(seg_header,
729-
index->table->space, id.page_no(), mtr);
730+
index->table->space, id.page_no(), mtr, space_latched);
730731
buf_page_free(id, mtr, __FILE__, __LINE__);
731732

732733
/* The page was marked free in the allocation bitmap, but it

storage/innobase/btr/btr0cur.cc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7638,8 +7638,8 @@ btr_free_externally_stored_field(
76387638
MTR_MEMO_PAGE_X_FIX));
76397639
ut_ad(!rec || rec_offs_validate(rec, index, offsets));
76407640
ut_ad(!rec || field_ref == btr_rec_get_field_ref(rec, offsets, i));
7641-
ut_ad(local_mtr->is_named_space(
7642-
page_get_space_id(page_align(field_ref))));
7641+
ut_ad(index->table->space_id == index->table->space->id);
7642+
ut_ad(local_mtr->is_named_space(index->table->space));
76437643

76447644
if (UNIV_UNLIKELY(!memcmp(field_ref, field_ref_zero,
76457645
BTR_EXTERN_FIELD_REF_SIZE))) {
@@ -7653,7 +7653,6 @@ btr_free_externally_stored_field(
76537653
ut_ad(!(mach_read_from_4(field_ref + BTR_EXTERN_LEN)
76547654
& ~((BTR_EXTERN_OWNER_FLAG
76557655
| BTR_EXTERN_INHERITED_FLAG) << 24)));
7656-
ut_ad(space_id == index->table->space->id);
76577656
ut_ad(space_id == index->table->space_id);
76587657

76597658
const ulint ext_zip_size = index->table->space->zip_size();
@@ -7727,7 +7726,9 @@ btr_free_externally_stored_field(
77277726
}
77287727
next_page_no = mach_read_from_4(page + FIL_PAGE_NEXT);
77297728

7730-
btr_page_free(index, ext_block, &mtr, true);
7729+
btr_page_free(index, ext_block, &mtr, true,
7730+
local_mtr->memo_contains(
7731+
*index->table->space));
77317732

77327733
if (UNIV_LIKELY_NULL(block->page.zip.data)) {
77337734
mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
@@ -7751,7 +7752,9 @@ btr_free_externally_stored_field(
77517752
next_page_no = mach_read_from_4(
77527753
page + FIL_PAGE_DATA
77537754
+ BTR_BLOB_HDR_NEXT_PAGE_NO);
7754-
btr_page_free(index, ext_block, &mtr, true);
7755+
btr_page_free(index, ext_block, &mtr, true,
7756+
local_mtr->memo_contains(
7757+
*index->table->space));
77557758

77567759
mtr.write<4>(*block, BTR_EXTERN_PAGE_NO + field_ref,
77577760
next_page_no);

storage/innobase/fil/fil0fil.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -853,7 +853,6 @@ fil_space_free_low(
853853

854854
ut_ad(space->size == 0);
855855

856-
rw_lock_free(&space->latch);
857856
fil_space_destroy_crypt_data(&space->crypt_data);
858857

859858
space->~fil_space_t();
@@ -885,7 +884,7 @@ fil_space_free(
885884

886885
if (space != NULL) {
887886
if (x_latched) {
888-
rw_lock_x_unlock(&space->latch);
887+
space->x_unlock();
889888
}
890889

891890
if (!recv_recovery_is_on()) {
@@ -958,7 +957,7 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
958957
<< " " << fil_crypt_get_type(crypt_data));
959958
}
960959

961-
rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
960+
space->latch.init(fil_space_latch_key);
962961

963962
if (space->purpose == FIL_TYPE_TEMPORARY) {
964963
/* SysTablespace::open_or_create() would pass
@@ -978,7 +977,6 @@ fil_space_t *fil_space_t::create(const char *name, ulint id, ulint flags,
978977
<< " to the tablespace memory cache, but tablespace '"
979978
<< old_space->name << "' already exists in the cache!";
980979
mutex_exit(&fil_system.mutex);
981-
rw_lock_free(&space->latch);
982980
space->~fil_space_t();
983981
ut_free(space->name);
984982
ut_free(space);
@@ -1797,7 +1795,7 @@ void fil_close_tablespace(ulint id)
17971795
return;
17981796
}
17991797

1800-
rw_lock_x_lock(&space->latch);
1798+
space->x_lock();
18011799

18021800
/* Invalidate in the buffer pool all pages belonging to the
18031801
tablespace. Since we have invoked space->set_stopping(), readahead
@@ -1809,11 +1807,11 @@ void fil_close_tablespace(ulint id)
18091807
os_aio_wait_until_no_pending_writes();
18101808
ut_ad(space->is_stopping());
18111809

1812-
/* If the free is successful, the X lock will be released before
1810+
/* If the free is successful, the wrlock will be released before
18131811
the space memory data structure is freed. */
18141812

18151813
if (!fil_space_free(id, true)) {
1816-
rw_lock_x_unlock(&space->latch);
1814+
space->x_unlock();
18171815
}
18181816

18191817
/* If it is a delete then also delete any generated files, otherwise

storage/innobase/fsp/fsp0fsp.cc

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ xdes_get_descriptor_with_space_hdr(
318318
mtr_t* mtr,
319319
bool init_space = false)
320320
{
321-
ut_ad(mtr->memo_contains(*space));
321+
ut_ad(space->is_owner());
322322
ut_ad(mtr->memo_contains_flagged(header, MTR_MEMO_PAGE_SX_FIX
323323
| MTR_MEMO_PAGE_X_FIX));
324324
/* Read free limit and space size */
@@ -404,7 +404,7 @@ xdes_get_descriptor_const(
404404
page_no_t offset,
405405
mtr_t* mtr)
406406
{
407-
ut_ad(mtr->memo_contains(space->latch, MTR_MEMO_S_LOCK));
407+
ut_ad(mtr->memo_contains(*space, true));
408408
ut_ad(offset < space->free_limit);
409409
ut_ad(offset < space->size_in_header);
410410

@@ -549,7 +549,7 @@ void fsp_header_init(fil_space_t* space, uint32_t size, mtr_t* mtr)
549549

550550
buf_block_t *free_block = buf_LRU_get_free_block(false);
551551

552-
mtr_x_lock_space(space, mtr);
552+
mtr->x_lock_space(space);
553553

554554
buf_block_t* block = buf_page_create(space, 0, zip_size, mtr,
555555
free_block);
@@ -1262,7 +1262,7 @@ static void fsp_free_page(fil_space_t* space, page_no_t offset, mtr_t* mtr)
12621262
@param[in,out] mtr mini-transaction */
12631263
static void fsp_free_extent(fil_space_t* space, page_no_t offset, mtr_t* mtr)
12641264
{
1265-
ut_ad(mtr->memo_contains(*space));
1265+
ut_ad(space->is_owner());
12661266

12671267
buf_block_t *block= fsp_get_header(space, mtr);
12681268
buf_block_t *xdes= 0;
@@ -1650,7 +1650,7 @@ fseg_create(fil_space_t *space, ulint byte_offset, mtr_t *mtr,
16501650
ut_ad(byte_offset + FSEG_HEADER_SIZE
16511651
<= srv_page_size - FIL_PAGE_DATA_END);
16521652

1653-
mtr_x_lock_space(space, mtr);
1653+
mtr->x_lock_space(space);
16541654
ut_d(space->modify_check(*mtr));
16551655

16561656
if (block) {
@@ -2199,7 +2199,7 @@ fseg_alloc_free_page_general(
21992199
uint32_t n_reserved;
22002200

22012201
space_id = page_get_space_id(page_align(seg_header));
2202-
space = mtr_x_lock_space(space_id, mtr);
2202+
space = mtr->x_lock_space(space_id);
22032203
inode = fseg_inode_get(seg_header, space_id, space->zip_size(),
22042204
mtr, &iblock);
22052205
if (!space->full_crc32()) {
@@ -2323,7 +2323,7 @@ fsp_reserve_free_extents(
23232323

23242324
const uint32_t extent_size = FSP_EXTENT_SIZE;
23252325

2326-
mtr_x_lock_space(space, mtr);
2326+
mtr->x_lock_space(space);
23272327
const unsigned physical_size = space->physical_size();
23282328

23292329
buf_block_t* header = fsp_get_header(space, mtr);
@@ -2528,18 +2528,24 @@ fseg_free_page_low(
25282528
@param[in,out] seg_header file segment header
25292529
@param[in,out] space tablespace
25302530
@param[in] offset page number
2531-
@param[in,out] mtr mini-transaction */
2531+
@param[in,out] mtr mini-transaction
2532+
@param[in] have_latch whether space->x_lock() was already called */
25322533
void
25332534
fseg_free_page(
25342535
fseg_header_t* seg_header,
25352536
fil_space_t* space,
25362537
uint32_t offset,
2537-
mtr_t* mtr)
2538+
mtr_t* mtr,
2539+
bool have_latch)
25382540
{
25392541
DBUG_ENTER("fseg_free_page");
25402542
fseg_inode_t* seg_inode;
25412543
buf_block_t* iblock;
2542-
mtr_x_lock_space(space, mtr);
2544+
if (have_latch) {
2545+
ut_ad(space->is_owner());
2546+
} else {
2547+
mtr->x_lock_space(space);
2548+
}
25432549

25442550
DBUG_LOG("fseg_free_page", "space_id: " << space->id
25452551
<< ", page_no: " << offset);
@@ -2569,7 +2575,7 @@ fseg_page_is_free(fil_space_t* space, unsigned page)
25692575
page);
25702576

25712577
mtr.start();
2572-
mtr_s_lock_space(space, &mtr);
2578+
mtr.s_lock_space(space);
25732579

25742580
if (page >= space->free_limit || page >= space->size_in_header) {
25752581
is_free = true;
@@ -2666,7 +2672,7 @@ fseg_free_step(
26662672
const uint32_t space_id = page_get_space_id(page_align(header));
26672673
const uint32_t header_page = page_get_page_no(page_align(header));
26682674

2669-
fil_space_t* space = mtr_x_lock_space(space_id, mtr);
2675+
fil_space_t* space = mtr->x_lock_space(space_id);
26702676
buf_block_t* xdes;
26712677
xdes_t* descr = xdes_get_descriptor(space, header_page, &xdes, mtr);
26722678

@@ -2740,7 +2746,7 @@ fseg_free_step_not_header(
27402746
const uint32_t space_id = page_get_space_id(page_align(header));
27412747
ut_ad(mtr->is_named_space(space_id));
27422748

2743-
fil_space_t* space = mtr_x_lock_space(space_id, mtr);
2749+
fil_space_t* space = mtr->x_lock_space(space_id);
27442750
buf_block_t* iblock;
27452751

27462752
inode = fseg_inode_get(header, space_id, space->zip_size(), mtr,

storage/innobase/handler/ha_innodb.cc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,7 @@ const struct _ft_vft_ext ft_vft_ext_result = {innobase_fts_get_version,
493493

494494
#ifdef HAVE_PSI_INTERFACE
495495
# define PSI_KEY(n) {&n##_key, #n, 0}
496-
/* All RWLOCK used in Innodb are SX-locks */
497-
# define PSI_RWLOCK_KEY(n) {&n##_key, #n, PSI_RWLOCK_FLAG_SX}
498-
499-
/* Keys to register pthread mutexes/cond in the current file with
496+
/** Keys to register pthread mutexes/cond in the current file with
500497
performance schema */
501498
static mysql_pfs_key_t commit_cond_mutex_key;
502499
static mysql_pfs_key_t commit_cond_key;
@@ -562,15 +559,16 @@ static PSI_mutex_info all_innodb_mutexes[] = {
562559
/* all_innodb_rwlocks array contains rwlocks that are
563560
performance schema instrumented if "UNIV_PFS_RWLOCK"
564561
is defined */
565-
static PSI_rwlock_info all_innodb_rwlocks[] = {
562+
static PSI_rwlock_info all_innodb_rwlocks[] =
563+
{
566564
# ifdef BTR_CUR_HASH_ADAPT
567565
{ &btr_search_latch_key, "btr_search_latch", 0 },
568566
# endif
569-
{ &dict_operation_lock_key, "dict_operation_lock", 0 },
570-
PSI_RWLOCK_KEY(fil_space_latch),
571-
{ &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 },
572-
{ &trx_purge_latch_key, "trx_purge_latch", 0 },
573-
PSI_RWLOCK_KEY(index_tree_rw_lock),
567+
{ &dict_operation_lock_key, "dict_operation_lock", 0 },
568+
{ &fil_space_latch_key, "fil_space_latch", 0 },
569+
{ &trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0 },
570+
{ &trx_purge_latch_key, "trx_purge_latch", 0 },
571+
{ &index_tree_rw_lock_key, "index_tree_rw_lock", PSI_RWLOCK_FLAG_SX }
574572
};
575573
# endif /* UNIV_PFS_RWLOCK */
576574

storage/innobase/ibuf/ibuf0ibuf.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ ibuf_init_at_db_start(void)
417417
mtr.start();
418418
compile_time_assert(IBUF_SPACE_ID == TRX_SYS_SPACE);
419419
compile_time_assert(IBUF_SPACE_ID == 0);
420-
mtr_x_lock_space(fil_system.sys_space, &mtr);
420+
mtr.x_lock_space(fil_system.sys_space);
421421
buf_block_t* header_page = buf_page_get(
422422
page_id_t(IBUF_SPACE_ID, FSP_IBUF_HEADER_PAGE_NO),
423423
0, RW_X_LATCH, &mtr);
@@ -1834,7 +1834,7 @@ static bool ibuf_add_free_page()
18341834
mtr.start();
18351835
/* Acquire the fsp latch before the ibuf header, obeying the latching
18361836
order */
1837-
mtr_x_lock_space(fil_system.sys_space, &mtr);
1837+
mtr.x_lock_space(fil_system.sys_space);
18381838
header_page = ibuf_header_page_get(&mtr);
18391839

18401840
/* Allocate a new page: NOTE that if the page has been a part of a
@@ -1908,7 +1908,7 @@ ibuf_remove_free_page(void)
19081908
/* Acquire the fsp latch before the ibuf header, obeying the latching
19091909
order */
19101910

1911-
mtr_x_lock_space(fil_system.sys_space, &mtr);
1911+
mtr.x_lock_space(fil_system.sys_space);
19121912
header_page = ibuf_header_page_get(&mtr);
19131913

19141914
/* Prevent pessimistic inserts to insert buffer trees for a while */

storage/innobase/include/btr0btr.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -648,10 +648,11 @@ btr_page_create(
648648
@param[in,out] index index tree
649649
@param[in,out] block block to be freed
650650
@param[in,out] mtr mini-transaction
651-
@param[in] blob whether this is freeing a BLOB page */
651+
@param[in] blob whether this is freeing a BLOB page
652+
@param[in] latched whether index->table->space->x_lock() was called */
652653
MY_ATTRIBUTE((nonnull))
653654
void btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr,
654-
bool blob = false);
655+
bool blob = false, bool space_latched = false);
655656

656657
/**************************************************************//**
657658
Gets the root node of a tree and x- or s-latches it.

0 commit comments

Comments
 (0)