@@ -1051,16 +1051,25 @@ inline trx_purge_rec_t purge_sys_t::fetch_next_rec()
1051
1051
/* * Close all tables that were opened in a purge batch for a worker.
1052
1052
@param node purge task context
1053
1053
@param thd purge coordinator thread handle */
1054
- static void trx_purge_close_tables (purge_node_t *node, THD *thd)
1054
+ static void trx_purge_close_tables (purge_node_t *node, THD *thd) noexcept
1055
1055
{
1056
1056
for (auto &t : node->tables )
1057
1057
{
1058
- if (!t.second .first );
1059
- else if (t.second .first == reinterpret_cast <dict_table_t *>(-1 ));
1060
- else
1058
+ dict_table_t *table= t.second .first ;
1059
+ if (table != nullptr && table != reinterpret_cast <dict_table_t *>(-1 ))
1060
+ dict_table_close (table);
1061
+ }
1062
+
1063
+ MDL_context *mdl_context= static_cast <MDL_context*>(thd_mdl_context (thd));
1064
+
1065
+ for (auto &t : node->tables )
1066
+ {
1067
+ dict_table_t *table= t.second .first ;
1068
+ if (table != nullptr && table != reinterpret_cast <dict_table_t *>(-1 ))
1061
1069
{
1062
- dict_table_close (t.second .first , false , thd, t.second .second );
1063
1070
t.second .first = reinterpret_cast <dict_table_t *>(-1 );
1071
+ if (mdl_context != nullptr && t.second .second != nullptr )
1072
+ mdl_context->release_lock (t.second .second );
1064
1073
}
1065
1074
}
1066
1075
}
@@ -1072,44 +1081,43 @@ void purge_sys_t::wait_FTS(bool also_sys)
1072
1081
}
1073
1082
1074
1083
__attribute__ ((nonnull))
1075
- /* * Aqcuire a metadata lock on a table.
1084
+ /* * Acquire a metadata lock on a table.
1076
1085
@param table table handle
1077
1086
@param mdl_context metadata lock acquisition context
1078
- @param mdl metadata lcok
1087
+ @param mdl metadata lock
1079
1088
@return table handle
1080
1089
@retval nullptr if the table is not found or accessible
1081
1090
@retval -1 if the purge of history must be suspended due to DDL */
1082
1091
static dict_table_t *trx_purge_table_acquire(dict_table_t *table,
1083
1092
MDL_context *mdl_context,
1084
- MDL_ticket **mdl)
1093
+ MDL_ticket **mdl) noexcept
1085
1094
{
1086
1095
ut_ad (dict_sys.frozen_not_locked ());
1087
1096
*mdl= nullptr ;
1088
1097
1089
1098
if (!table->is_readable () || table->corrupted )
1090
- {
1091
- table->release ();
1092
1099
return nullptr ;
1093
- }
1094
1100
1095
1101
size_t db_len= dict_get_db_name_len (table->name .m_name );
1096
1102
if (db_len == 0 )
1097
- return table; /* InnoDB system tables are not covered by MDL */
1103
+ {
1104
+ /* InnoDB system tables are not covered by MDL */
1105
+ got_table:
1106
+ table->acquire ();
1107
+ return table;
1108
+ }
1098
1109
1099
1110
if (purge_sys.must_wait_FTS ())
1100
- {
1101
1111
must_wait:
1102
- table->release ();
1103
1112
return reinterpret_cast <dict_table_t *>(-1 );
1104
- }
1105
1113
1106
1114
char db_buf[NAME_LEN + 1 ];
1107
1115
char tbl_buf[NAME_LEN + 1 ];
1108
1116
size_t tbl_len;
1109
1117
1110
1118
if (!table->parse_name <true >(db_buf, tbl_buf, &db_len, &tbl_len))
1111
1119
/* The name of an intermediate table starts with #sql */
1112
- return table ;
1120
+ goto got_table ;
1113
1121
1114
1122
{
1115
1123
MDL_request request;
@@ -1122,37 +1130,38 @@ static dict_table_t *trx_purge_table_acquire(dict_table_t *table,
1122
1130
goto must_wait;
1123
1131
}
1124
1132
1125
- return table ;
1133
+ goto got_table ;
1126
1134
}
1127
1135
1128
1136
/* * Open a table handle for the purge of committed transaction history
1129
1137
@param table_id InnoDB table identifier
1130
1138
@param mdl_context metadata lock acquisition context
1131
- @param mdl metadata lcok
1139
+ @param mdl metadata lock
1132
1140
@return table handle
1133
1141
@retval nullptr if the table is not found or accessible
1134
1142
@retval -1 if the purge of history must be suspended due to DDL */
1135
1143
static dict_table_t *trx_purge_table_open (table_id_t table_id,
1136
1144
MDL_context *mdl_context,
1137
- MDL_ticket **mdl)
1145
+ MDL_ticket **mdl) noexcept
1138
1146
{
1139
- dict_sys.freeze (SRW_LOCK_CALL);
1140
-
1141
- dict_table_t *table= dict_sys.find_table (table_id);
1147
+ dict_table_t *table;
1142
1148
1143
- if (table)
1144
- table->acquire ();
1145
- else
1149
+ for (;;)
1146
1150
{
1151
+ dict_sys.freeze (SRW_LOCK_CALL);
1152
+ table= dict_sys.find_table (table_id);
1153
+ if (table)
1154
+ break ;
1147
1155
dict_sys.unfreeze ();
1148
1156
dict_sys.lock (SRW_LOCK_CALL);
1149
1157
table= dict_load_table_on_id (table_id, DICT_ERR_IGNORE_FK_NOKEY);
1150
- if (table)
1151
- table->acquire ();
1152
1158
dict_sys.unlock ();
1153
1159
if (!table)
1154
1160
return nullptr ;
1155
- dict_sys.freeze (SRW_LOCK_CALL);
1161
+ /* At this point, the freshly loaded table may already have been evicted.
1162
+ We must look it up again while holding a shared dict_sys.latch. We keep
1163
+ trying this until the table is found in the cache or it cannot be found
1164
+ in the dictionary (because the table has been dropped or rebuilt). */
1156
1165
}
1157
1166
1158
1167
table= trx_purge_table_acquire (table, mdl_context, mdl);
@@ -1171,10 +1180,7 @@ dict_table_t *purge_sys_t::close_and_reopen(table_id_t id, THD *thd,
1171
1180
1172
1181
for (que_thr_t *thr= UT_LIST_GET_FIRST (purge_sys.query ->thrs ); thr;
1173
1182
thr= UT_LIST_GET_NEXT (thrs, thr))
1174
- {
1175
- purge_node_t *node= static_cast <purge_node_t *>(thr->child );
1176
- trx_purge_close_tables (node, thd);
1177
- }
1183
+ trx_purge_close_tables (static_cast <purge_node_t *>(thr->child ), thd);
1178
1184
1179
1185
m_active= false ;
1180
1186
wait_FTS (false );
0 commit comments