1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-07 00:04:31 +03:00

MDEV-24861 Assertion `trx->rsegs.m_redo.rseg' failed in innodb_prepare_commit_versioned

trx_t::commit_tables(): Ensure that mod_tables will be empty.
This was broken in commit b08448de64
where the query cache invalidation was moved from lock_release().
This commit is contained in:
Marko Mäkelä
2021-02-15 10:15:00 +02:00
parent 4df0249b9a
commit 2e84846ec0
3 changed files with 57 additions and 26 deletions

View File

@@ -91,3 +91,16 @@ ALTER TABLE t1 FORCE;
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `test`.`t3` (`f2`)) ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `test`.`t3` (`f2`))
DROP TABLE t2, t1; DROP TABLE t2, t1;
#
# MDEV-24861 Assertion `trx->rsegs.m_redo.rseg' failed
# in innodb_prepare_commit_versioned
#
CREATE TABLE t1 (id INT PRIMARY KEY, f TEXT UNIQUE,
s BIGINT UNSIGNED AS ROW START, e BIGINT UNSIGNED AS ROW END,
PERIOD FOR SYSTEM_TIME(s,e))
ENGINE=InnoDB WITH SYSTEM VERSIONING;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
ALTER TABLE t1 FORCE;
TRUNCATE TABLE t2;
DROP TABLE t1, t2;
# End of 10.6 tests

View File

@@ -92,3 +92,19 @@ ALTER TABLE t1 FORCE;
--error ER_TRUNCATE_ILLEGAL_FK --error ER_TRUNCATE_ILLEGAL_FK
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
DROP TABLE t2, t1; DROP TABLE t2, t1;
--echo #
--echo # MDEV-24861 Assertion `trx->rsegs.m_redo.rseg' failed
--echo # in innodb_prepare_commit_versioned
--echo #
CREATE TABLE t1 (id INT PRIMARY KEY, f TEXT UNIQUE,
s BIGINT UNSIGNED AS ROW START, e BIGINT UNSIGNED AS ROW END,
PERIOD FOR SYSTEM_TIME(s,e))
ENGINE=InnoDB WITH SYSTEM VERSIONING;
CREATE TABLE t2 (id INT PRIMARY KEY) ENGINE=InnoDB;
ALTER TABLE t1 FORCE;
TRUNCATE TABLE t2;
DROP TABLE t1, t2;
--echo # End of 10.6 tests

View File

@@ -1226,44 +1226,46 @@ trx_flush_log_if_needed(
/** Process tables that were modified by the committing transaction. */ /** Process tables that were modified by the committing transaction. */
inline void trx_t::commit_tables() inline void trx_t::commit_tables()
{ {
if (!undo_no || mod_tables.empty()) if (mod_tables.empty())
return; return;
if (undo_no)
{
#if defined SAFE_MUTEX && defined UNIV_DEBUG #if defined SAFE_MUTEX && defined UNIV_DEBUG
const bool preserve_tables= !innodb_evict_tables_on_commit_debug || const bool preserve_tables= !innodb_evict_tables_on_commit_debug ||
is_recovered || /* avoid trouble with XA recovery */ is_recovered || /* avoid trouble with XA recovery */
# if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */ # if 1 /* if dict_stats_exec_sql() were not playing dirty tricks */
dict_sys.mutex_is_locked(); dict_sys.mutex_is_locked();
# else /* this would be more proper way to do it */ # else /* this would be more proper way to do it */
dict_operation_lock_mode || dict_operation; dict_operation_lock_mode || dict_operation;
# endif # endif
#endif #endif
const trx_id_t max_trx_id= trx_sys.get_max_trx_id(); const trx_id_t max_trx_id= trx_sys.get_max_trx_id();
const auto now= start_time; const auto now= start_time;
for (const auto& p : mod_tables) for (const auto& p : mod_tables)
{ {
dict_table_t *table= p.first; dict_table_t *table= p.first;
table->update_time= now; table->update_time= now;
table->query_cache_inv_trx_id= max_trx_id; table->query_cache_inv_trx_id= max_trx_id;
#if defined SAFE_MUTEX && defined UNIV_DEBUG #if defined SAFE_MUTEX && defined UNIV_DEBUG
if (preserve_tables || table->get_ref_count() || table->is_temporary() || if (preserve_tables || table->get_ref_count() || table->is_temporary() ||
UT_LIST_GET_LEN(table->locks)) UT_LIST_GET_LEN(table->locks))
/* do not evict when committing DDL operations or if some other /* do not evict when committing DDL operations or if some other
transaction is holding the table handle */ transaction is holding the table handle */
continue; continue;
/* recheck while holding the mutex that blocks /* recheck while holding the mutex that blocks table->acquire() */
table->acquire() */ dict_sys.mutex_lock();
dict_sys.mutex_lock(); {
{ LockMutexGuard g{SRW_LOCK_CALL};
LockMutexGuard g{SRW_LOCK_CALL}; if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks))
if (!table->get_ref_count() && !UT_LIST_GET_LEN(table->locks)) dict_sys.remove(table, true);
dict_sys.remove(table, true); }
} dict_sys.mutex_unlock();
dict_sys.mutex_unlock();
#endif #endif
}
} }
mod_tables.clear(); mod_tables.clear();