Skip to content

Commit 394bf15

Browse files
committed
[RP007] Changes dict_sys->mutex to rw_lock for innodb_purge_threads scaling performance
Comparing user threads DML CPU scale performance, innodb_purge_threads seems not to scale enough. dict_sys->mutex around dd_table_open_on_id() causes contention among purge_threads, and the History list length might growing huge. Changes dict_sys->mutex to dict_sys->lock and base operation is changed to x-lock. Only for just only HASH_SEARCH of dict_sys->table_id_hash, uses s-lock to minimize contention.
1 parent 2046983 commit 394bf15

File tree

14 files changed

+111
-54
lines changed

14 files changed

+111
-54
lines changed

MYSQL_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ MYSQL_VERSION_MINOR=0
33
MYSQL_VERSION_PATCH=42
44
MYSQL_VERSION_EXTRA=
55
MYSQL_VERSION_STABILITY="LTS"
6-
MYSQL_RP_REVISION="-RP006"
6+
MYSQL_RP_REVISION="-RP007"

storage/innobase/clone/clone0api.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2763,17 +2763,19 @@ static int clone_init_tablespaces(THD *thd) {
27632763

27642764
/* Acquire dict mutex to prevent race against concurrent DML trying to
27652765
load the space. */
2766-
IB_mutex_guard sys_mutex(&dict_sys->mutex, UT_LOCATION_HERE);
2766+
dict_sys_mutex_enter();
27672767

27682768
/* Re-check if space exists after acquiring dict sys mutex. Concurrent
27692769
DML could have already loaded the space. Space name is already adjusted
27702770
in previous call. */
27712771
if (fil_space_exists_in_mem(space_id, space_name, false, false)) {
2772+
dict_sys_mutex_exit();
27722773
continue;
27732774
}
27742775

27752776
auto err = fil_ibd_open(false, FIL_TYPE_TABLESPACE, space_id, space_flags,
27762777
space_name, filename.c_str(), false, false);
2778+
dict_sys_mutex_exit();
27772779

27782780
if (err != DB_SUCCESS) {
27792781
ib::error(ER_IB_CLONE_INTERNAL)

storage/innobase/dict/dict0crea.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1996, 2025, Oracle and/or its affiliates.
4+
Copyright (c) 2025, buildup-db.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License, version 2.0, as published by the
@@ -648,9 +649,11 @@ void dict_table_assign_new_id(dict_table_t *table) {
648649
@param[in] space_discarded true if space is discarded
649650
@param[in] in_flags space flags to use when space_discarded is true
650651
@param[in] is_create true when creating SDI index
652+
@param[in] has_x_lock false when holding s-lock of dict_sys
651653
@return in-memory index structure for tablespace dictionary or NULL */
652654
dict_index_t *dict_sdi_create_idx_in_mem(space_id_t space, bool space_discarded,
653-
uint32_t in_flags, bool is_create) {
655+
uint32_t in_flags, bool is_create,
656+
bool has_x_lock) {
654657
uint32_t flags = space_discarded ? in_flags : fil_space_get_flags(space);
655658

656659
/* This means the tablespace is evicted from cache */
@@ -660,7 +663,11 @@ dict_index_t *dict_sdi_create_idx_in_mem(space_id_t space, bool space_discarded,
660663

661664
ut_ad(fsp_flags_is_valid(flags));
662665

663-
dict_sys_mutex_exit();
666+
if (has_x_lock) {
667+
dict_sys_mutex_exit();
668+
} else {
669+
dict_sys_s_unlock();
670+
}
664671

665672
rec_format_t rec_format;
666673

storage/innobase/dict/dict0dd.cc

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 2017, 2025, Oracle and/or its affiliates.
4+
Copyright (c) 2025, buildup-db.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License, version 2.0, as published by the
@@ -399,7 +400,7 @@ int dd_table_open_on_dd_obj(THD *thd, dd::cache::Dictionary_client *client,
399400

400401
ut_ad(table_id != dd::INVALID_OBJECT_ID);
401402

402-
dict_sys_mutex_enter();
403+
dict_sys_s_lock();
403404

404405
HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *,
405406
table, ut_ad(table->cached), table->id == table_id);
@@ -408,7 +409,7 @@ int dd_table_open_on_dd_obj(THD *thd, dd::cache::Dictionary_client *client,
408409
table->acquire();
409410
}
410411

411-
dict_sys_mutex_exit();
412+
dict_sys_s_unlock();
412413

413414
if (table != nullptr) {
414415
return 0;
@@ -697,17 +698,19 @@ hold Shared MDL lock on it.
697698
table_id was found) mdl=NULL if we are resurrecting table IX locks in recovery
698699
@param[in] dict_locked dict_sys mutex is held
699700
@param[in] check_corruption check if the table is corrupted or not.
701+
@param[in] for_modification if false, dict_locked means s-lock.
700702
@return table
701703
@retval NULL if the table does not exist or cannot be opened */
702704
dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
703705
MDL_ticket **mdl, bool dict_locked,
704-
bool check_corruption) {
706+
bool check_corruption,
707+
bool for_modification) {
705708
dict_table_t *ib_table;
706709
const auto hash_value = ut::hash_uint64(table_id);
707710
char full_name[MAX_FULL_NAME_LEN + 1];
708711

709712
if (!dict_locked) {
710-
dict_sys_mutex_enter();
713+
dict_sys_s_lock();
711714
}
712715

713716
HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *,
@@ -721,12 +724,12 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
721724
space_id_t space_id = dict_sdi_get_space_id(table_id);
722725

723726
/* Create in-memory table object for SDI table */
724-
dict_index_t *sdi_index =
725-
dict_sdi_create_idx_in_mem(space_id, false, 0, false);
727+
dict_index_t *sdi_index = dict_sdi_create_idx_in_mem(
728+
space_id, false, 0, false, dict_locked && for_modification);
726729

727730
if (sdi_index == nullptr) {
728731
if (!dict_locked) {
729-
dict_sys_mutex_exit();
732+
dict_sys_s_unlock();
730733
}
731734
return nullptr;
732735
}
@@ -737,15 +740,24 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
737740
ib_table->acquire();
738741

739742
if (!dict_locked) {
743+
/* dict_sdi_create_idx_in_mem() re-obtains with x-lock. */
740744
dict_sys_mutex_exit();
741745
}
742746
} else {
743-
dict_sys_mutex_exit();
747+
if (dict_locked && for_modification) {
748+
dict_sys_mutex_exit();
749+
} else {
750+
dict_sys_s_unlock();
751+
}
744752

745753
ib_table = dd_table_open_on_id_low(thd, mdl, table_id);
746754

747755
if (dict_locked) {
748-
dict_sys_mutex_enter();
756+
if (for_modification) {
757+
dict_sys_mutex_enter();
758+
} else {
759+
dict_sys_s_lock();
760+
}
749761
}
750762
}
751763
#else /* !UNIV_HOTBACKUP */
@@ -762,7 +774,7 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
762774
}
763775

764776
if (!dict_locked) {
765-
dict_sys_mutex_exit();
777+
dict_sys_s_unlock();
766778
}
767779
} else {
768780
for (;;) {
@@ -778,12 +790,20 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
778790

779791
ut_ad(!ib_table->is_temporary());
780792

781-
dict_sys_mutex_exit();
793+
if (dict_locked && for_modification) {
794+
dict_sys_mutex_exit();
795+
} else {
796+
dict_sys_s_unlock();
797+
}
782798

783799
#ifndef UNIV_HOTBACKUP
784800
if (db_str.empty() || tbl_str.empty()) {
785801
if (dict_locked) {
786-
dict_sys_mutex_enter();
802+
if (for_modification) {
803+
dict_sys_mutex_enter();
804+
} else {
805+
dict_sys_s_lock();
806+
}
787807
}
788808
return nullptr;
789809
}
@@ -797,7 +817,11 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
797817
#endif /* !UNIV_HOTBACKUP */
798818

799819
/* Re-lookup the table after acquiring MDL. */
800-
dict_sys_mutex_enter();
820+
if (dict_locked && for_modification) {
821+
dict_sys_mutex_enter();
822+
} else {
823+
dict_sys_s_lock();
824+
}
801825

802826
HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *,
803827
ib_table, ut_ad(ib_table->cached), ib_table->id == table_id);
@@ -832,7 +856,11 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
832856
}
833857
}
834858

835-
dict_sys_mutex_exit();
859+
if (dict_locked && for_modification) {
860+
dict_sys_mutex_exit();
861+
} else {
862+
dict_sys_s_unlock();
863+
}
836864
break;
837865
}
838866

@@ -857,11 +885,16 @@ dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
857885
#endif /* !UNIV_HOTBACKUP */
858886

859887
if (dict_locked) {
860-
dict_sys_mutex_enter();
888+
if (for_modification) {
889+
dict_sys_mutex_enter();
890+
} else {
891+
dict_sys_s_lock();
892+
}
861893
}
862894
}
863895

864-
ut_ad(dict_locked == dict_sys_mutex_own());
896+
ut_ad(dict_locked ==
897+
(for_modification ? dict_sys_mutex_own() : dict_sys_s_lock_own()));
865898

866899
return ib_table;
867900
}

storage/innobase/dict/dict0dict.cc

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
Copyright (c) 1996, 2025, Oracle and/or its affiliates.
44
Copyright (c) 2012, Facebook Inc.
5+
Copyright (c) 2025, buildup-db.
56
67
This program is free software; you can redistribute it and/or modify it under
78
the terms of the GNU General Public License, version 2.0, as published by the
@@ -499,19 +500,18 @@ void dict_table_close(dict_table_t *table, bool dict_locked, bool try_drop) {
499500
#ifdef UNIV_DEBUG
500501
if (!table->is_intrinsic()) {
501502
/* This is now only for validation in debug mode */
503+
/* Cannot execute the validation when s-locked */
502504
if (!dict_locked) {
503505
dict_sys_mutex_enter();
504-
}
505506

506-
ut_ad(dict_lru_validate());
507+
ut_ad(dict_lru_validate());
507508

508-
if (table->can_be_evicted) {
509-
ut_ad(dict_lru_find_table(table));
510-
} else {
511-
ut_ad(dict_non_lru_find_table(table));
512-
}
509+
if (table->can_be_evicted) {
510+
ut_ad(dict_lru_find_table(table));
511+
} else {
512+
ut_ad(dict_non_lru_find_table(table));
513+
}
513514

514-
if (!dict_locked) {
515515
dict_sys_mutex_exit();
516516
}
517517
}
@@ -1016,7 +1016,7 @@ void dict_init(void) {
10161016
UT_LIST_INIT(dict_sys->table_LRU);
10171017
UT_LIST_INIT(dict_sys->table_non_LRU);
10181018

1019-
mutex_create(LATCH_ID_DICT_SYS, &dict_sys->mutex);
1019+
rw_lock_create(dict_sys_mutex_key, &dict_sys->lock, LATCH_ID_DICT_SYS);
10201020

10211021
dict_sys->table_hash = ut::new_<hash_table_t>(
10221022
buf_pool_get_curr_size() / (DICT_POOL_PER_TABLE_HASH * UNIV_WORD_SIZE));
@@ -2777,7 +2777,7 @@ void dict_index_remove_from_cache(dict_table_t *table, /*!< in/out: table */
27772777

27782778
std::vector<table_id_t> dict_get_all_table_ids() {
27792779
std::vector<table_id_t> ids;
2780-
mutex_enter(&dict_sys->mutex);
2780+
rw_lock_s_lock(&dict_sys->lock, UT_LOCATION_HERE);
27812781
ids.reserve(dict_sys->table_LRU.get_length() +
27822782
dict_sys->table_non_LRU.get_length());
27832783
for (dict_table_t *table : dict_sys->table_LRU) {
@@ -2786,7 +2786,7 @@ std::vector<table_id_t> dict_get_all_table_ids() {
27862786
for (dict_table_t *table : dict_sys->table_non_LRU) {
27872787
ids.push_back(table->id);
27882788
}
2789-
mutex_exit(&dict_sys->mutex);
2789+
rw_lock_s_unlock(&dict_sys->lock);
27902790
return ids;
27912791
}
27922792

storage/innobase/handler/handler0alter.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10949,10 +10949,10 @@ int ha_innopart::exchange_partition_low(uint part_id, dd::Table *part_table,
1094910949
dict_table_t *swap;
1095010950
const auto hash_value = ut::hash_uint64(table_id);
1095110951

10952-
dict_sys_mutex_enter();
10952+
dict_sys_s_lock();
1095310953
HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *,
1095410954
swap, ut_ad(swap->cached), swap->id == table_id);
10955-
dict_sys_mutex_exit();
10955+
dict_sys_s_unlock();
1095610956
ut_ad(swap != nullptr);
1095710957
ut_ad(swap->n_ref_count == 1);
1095810958

storage/innobase/include/dict0crea.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1996, 2025, Oracle and/or its affiliates.
4+
Copyright (c) 2025, buildup-db.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License, version 2.0, as published by the
@@ -139,9 +140,11 @@ struct tab_node_t {
139140
@param[in] space_discarded true if space is discarded
140141
@param[in] in_flags space flags to use when space_discarded is true
141142
@param[in] is_create true when creating SDI index
143+
@param[in] has_x_lock false when holding s-lock of dict_sys
142144
@return in-memory index structure for tablespace dictionary or NULL */
143145
dict_index_t *dict_sdi_create_idx_in_mem(space_id_t space, bool space_discarded,
144-
uint32_t in_flags, bool is_create);
146+
uint32_t in_flags, bool is_create,
147+
bool has_x_lock = true);
145148

146149
/* Index create node struct */
147150

storage/innobase/include/dict0dd.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 2015, 2025, Oracle and/or its affiliates.
4+
Copyright (c) 2025, buildup-db.
45
56
This program is free software; you can redistribute it and/or modify it under
67
the terms of the GNU General Public License, version 2.0, as published by the
@@ -1163,11 +1164,13 @@ hold Shared MDL lock on it.
11631164
table_id was found) mdl=NULL if we are resurrecting table IX locks in recovery
11641165
@param[in] dict_locked dict_sys mutex is held
11651166
@param[in] check_corruption check if the table is corrupted or not.
1167+
@param[in] for_modification if false, dict_locked means s-lock.
11661168
@return table
11671169
@retval NULL if the table does not exist or cannot be opened */
11681170
dict_table_t *dd_table_open_on_id(table_id_t table_id, THD *thd,
11691171
MDL_ticket **mdl, bool dict_locked,
1170-
bool check_corruption);
1172+
bool check_corruption,
1173+
bool for_modification = true);
11711174

11721175
/** Close an internal InnoDB table handle.
11731176
@param[in,out] table InnoDB table handle

0 commit comments

Comments
 (0)