diff --git a/mysql-test/suite/innodb/r/lock_release.result b/mysql-test/suite/innodb/r/lock_release.result new file mode 100644 index 00000000000..6bafe79a36c --- /dev/null +++ b/mysql-test/suite/innodb/r/lock_release.result @@ -0,0 +1,23 @@ +# +# MDEV-34542 Assertion `lock_trx_has_sys_table_locks(trx) == __null' +# failed in void row_mysql_unfreeze_data_dictionary(trx_t*) +# +# +CREATE TABLE t1 (c1 CHAR(1) ,c2 INT) ENGINE=INNODB +PARTITION BY LINEAR HASH ((c2)) PARTITIONS 512; +CREATE TABLE t2 (a INT) ENGINE=INNODB; +set @old_table_open_cache= @@table_open_cache; +XA START 'a'; +INSERT INTO mysql.innodb_index_stats SELECT * FROM mysql.innodb_index_stats WHERE table_name=''; +SET GLOBAL table_open_cache=10; +INSERT into t2 (a) VALUES (1); +SELECT * FROM t1; +c1 c2 +XA END 'a'; +XA PREPARE 'a'; +SELECT sleep(3); +sleep(3) +0 +XA ROLLBACK 'a'; +DROP TABLE t1, t2; +SET GLOBAL table_open_cache=@old_table_open_cache; diff --git a/mysql-test/suite/innodb/t/lock_release.test b/mysql-test/suite/innodb/t/lock_release.test new file mode 100644 index 00000000000..6620bf69d14 --- /dev/null +++ b/mysql-test/suite/innodb/t/lock_release.test @@ -0,0 +1,26 @@ +--source include/have_innodb.inc +--source include/have_partition.inc + +--echo # +--echo # MDEV-34542 Assertion `lock_trx_has_sys_table_locks(trx) == __null' +--echo # failed in void row_mysql_unfreeze_data_dictionary(trx_t*) +--echo # +--echo # +CREATE TABLE t1 (c1 CHAR(1) ,c2 INT) ENGINE=INNODB + PARTITION BY LINEAR HASH ((c2)) PARTITIONS 512; +CREATE TABLE t2 (a INT) ENGINE=INNODB; + +set @old_table_open_cache= @@table_open_cache; +XA START 'a'; +INSERT INTO mysql.innodb_index_stats SELECT * FROM mysql.innodb_index_stats WHERE table_name=''; +SET GLOBAL table_open_cache=10; +INSERT into t2 (a) VALUES (1); +SELECT * FROM t1; +XA END 'a'; +XA PREPARE 'a'; +# Added sleep to make sure that InnoDB main thread is to remove +# the innodb_index_stats from table cache +SELECT sleep(3); +XA ROLLBACK 'a'; +DROP TABLE t1, t2; +SET GLOBAL table_open_cache=@old_table_open_cache; diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index d0b4105d9c6..3dd4b5fa6f6 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4382,80 +4382,6 @@ static void lock_rec_unlock_supremum(lock_t *lock) trx_mutex_exit(lock->trx); } -/** Release non-exclusive locks on XA PREPARE, -and release possible other transactions waiting because of these locks. */ -void lock_release_on_prepare(trx_t *trx) -{ - trx->set_skip_lock_inheritance(); - - ulint count= 0; - lock_mutex_enter(); - ut_ad(!trx_mutex_own(trx)); - - for (lock_t *lock= UT_LIST_GET_LAST(trx->lock.trx_locks); lock; ) - { - ut_ad(lock->trx == trx); - - if (lock_get_type_low(lock) == LOCK_REC) - { - ut_ad(!lock->index->table->is_temporary()); - if ((lock->type_mode & (LOCK_MODE_MASK | LOCK_GAP)) != LOCK_X) - lock_rec_dequeue_from_page(lock); - else if (lock_rec_get_nth_bit(lock, PAGE_HEAP_NO_SUPREMUM)) - lock_rec_unlock_supremum(lock); - else - { - ut_ad(trx->dict_operation || - lock->index->table->id >= DICT_HDR_FIRST_ID); - ut_ad(lock->trx->isolation_level > TRX_ISO_READ_COMMITTED || - /* Insert-intention lock is valid for supremum for isolation - level > TRX_ISO_READ_COMMITTED */ - lock_get_mode(lock) == LOCK_X || - !lock_rec_get_nth_bit(lock, PAGE_HEAP_NO_SUPREMUM)); -retain_lock: - lock= UT_LIST_GET_PREV(trx_locks, lock); - continue; - } - } - else - { - ut_ad(lock_get_type_low(lock) & LOCK_TABLE); - ut_d(dict_table_t *table= lock->un_member.tab_lock.table); - ut_ad(!table->is_temporary()); - - switch (lock_get_mode(lock)) { - case LOCK_IS: - case LOCK_S: - lock_table_dequeue(lock); - break; - case LOCK_IX: - case LOCK_X: - ut_ad(table->id >= DICT_HDR_FIRST_ID || trx->dict_operation); - /* fall through */ - default: - goto retain_lock; - } - } - - if (++count == LOCK_RELEASE_INTERVAL) - { - lock_mutex_exit(); - count= 0; - lock_mutex_enter(); - } - - lock= UT_LIST_GET_LAST(trx->lock.trx_locks); - } - - lock_mutex_exit(); - -} - -/* True if a lock mode is S or X */ -#define IS_LOCK_S_OR_X(lock) \ - (lock_get_mode(lock) == LOCK_S \ - || lock_get_mode(lock) == LOCK_X) - /*********************************************************************//** Removes table locks of the transaction on a table to be dropped. */ static @@ -4502,6 +4428,81 @@ lock_trx_table_locks_remove( ut_error; } +/** Release non-exclusive locks on XA PREPARE, +and release possible other transactions waiting because of these locks. */ +void lock_release_on_prepare(trx_t *trx) +{ + trx->set_skip_lock_inheritance(); + + ulint count= 0; + lock_mutex_enter(); + ut_ad(!trx_mutex_own(trx)); + + for (lock_t *lock= UT_LIST_GET_LAST(trx->lock.trx_locks); lock; ) + { + ut_ad(lock->trx == trx); + + if (lock_get_type_low(lock) == LOCK_REC) + { + ut_ad(!lock->index->table->is_temporary()); + if ((lock->type_mode & (LOCK_MODE_MASK | LOCK_GAP)) != LOCK_X) + lock_rec_dequeue_from_page(lock); + else if (lock_rec_get_nth_bit(lock, PAGE_HEAP_NO_SUPREMUM)) + lock_rec_unlock_supremum(lock); + else + { + ut_ad(trx->dict_operation || + lock->index->table->id >= DICT_HDR_FIRST_ID); + ut_ad(lock->trx->isolation_level > TRX_ISO_READ_COMMITTED || + /* Insert-intention lock is valid for supremum for isolation + level > TRX_ISO_READ_COMMITTED */ + lock_get_mode(lock) == LOCK_X || + !lock_rec_get_nth_bit(lock, PAGE_HEAP_NO_SUPREMUM)); +retain_lock: + lock= UT_LIST_GET_PREV(trx_locks, lock); + continue; + } + } + else + { + ut_ad(lock_get_type_low(lock) & LOCK_TABLE); + ut_d(dict_table_t *table= lock->un_member.tab_lock.table); + ut_ad(!table->is_temporary()); + + switch (lock_get_mode(lock)) { + case LOCK_IS: + case LOCK_S: + lock_table_dequeue(lock); + lock_trx_table_locks_remove(lock); + break; + case LOCK_IX: + case LOCK_X: + ut_ad(table->id >= DICT_HDR_FIRST_ID || trx->dict_operation); + /* fall through */ + default: + goto retain_lock; + } + } + + if (++count == LOCK_RELEASE_INTERVAL) + { + lock_mutex_exit(); + count= 0; + lock_mutex_enter(); + } + + lock= UT_LIST_GET_LAST(trx->lock.trx_locks); + } + + lock_mutex_exit(); + +} + +/* True if a lock mode is S or X */ +#define IS_LOCK_S_OR_X(lock) \ + (lock_get_mode(lock) == LOCK_S \ + || lock_get_mode(lock) == LOCK_X) + /*===================== VALIDATION AND DEBUGGING ====================*/ /** Print info of a table lock.