diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2022-01-20 08:02:58 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2022-01-20 08:02:58 +0200 |
commit | 5e6fd4e80435ae6d5994abbff6032c7957713410 (patch) | |
tree | c6d90b712b406e5d34ae19449ac5b01a5dd97e6c | |
parent | b0998583f8e7331245597a7bf9a878cf6c7fa969 (diff) | |
parent | 21778b8aa88280458f2196aab93044149cf0a18c (diff) | |
download | mariadb-git-5e6fd4e80435ae6d5994abbff6032c7957713410.tar.gz |
Merge 10.6 into 10.7
-rw-r--r-- | mysql-test/main/distinct.result | 36 | ||||
-rw-r--r-- | mysql-test/main/distinct.test | 38 | ||||
-rw-r--r-- | mysql-test/suite/galera/disabled.def | 1 | ||||
-rw-r--r-- | mysql-test/suite/innodb/r/lock_wait_conflict.result | 27 | ||||
-rw-r--r-- | mysql-test/suite/innodb/t/lock_wait_conflict.test | 60 | ||||
-rw-r--r-- | mysql-test/suite/versioning/r/update.result | 1 | ||||
-rw-r--r-- | mysql-test/suite/versioning/t/update.test | 4 | ||||
-rw-r--r-- | sql/sql_limit.h | 2 | ||||
-rw-r--r-- | storage/innobase/buf/buf0flu.cc | 4 | ||||
-rw-r--r-- | storage/innobase/include/hash0hash.h | 41 | ||||
-rw-r--r-- | storage/innobase/include/lock0lock.h | 9 | ||||
-rw-r--r-- | storage/innobase/lock/lock0lock.cc | 145 |
12 files changed, 322 insertions, 46 deletions
diff --git a/mysql-test/main/distinct.result b/mysql-test/main/distinct.result index 2062ff0091d..0e31a174be7 100644 --- a/mysql-test/main/distinct.result +++ b/mysql-test/main/distinct.result @@ -1070,3 +1070,39 @@ UNION 1 drop table t1; End of 5.5 tests +# +# MDEV-27382: OFFSET is ignored when it is combined with the DISTINCT, IN() and JOIN +# +CREATE TABLE t1 ( +id int(7) NOT NULL AUTO_INCREMENT, +name varchar(50) DEFAULT NULL, +primary key (id) +); +INSERT INTO t1 VALUES (1, 'Reed'), (10, 'no-child'); +CREATE TABLE t2 ( +id int(11) NOT NULL AUTO_INCREMENT, +parent_id int(7) NOT NULL, +name varchar(100) DEFAULT NULL, +primary key (id), +key(parent_id) +); +INSERT INTO t2 VALUES (1, 1,'John'), (2, 2,'no-parent'); +SELECT DISTINCT p.id +FROM t1 p LEFT JOIN t2 c ON p.id = c.parent_id +WHERE p.id=1 +LIMIT 0; +id +SELECT DISTINCT p.id +FROM t1 p LEFT JOIN t2 c ON p.id = c.parent_id +WHERE p.id=1 +LIMIT 0 offset 5; +id +# Test the second part of the fix: just check that "LIMIT 0 OFFSET n" is +# handled in the same way as "LIMIT 0" +explain select * from t1 limit 0; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit +explain select * from t1 limit 0 offset 10; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Zero limit +drop table t1, t2; diff --git a/mysql-test/main/distinct.test b/mysql-test/main/distinct.test index da12c7273b2..32e189da98a 100644 --- a/mysql-test/main/distinct.test +++ b/mysql-test/main/distinct.test @@ -818,3 +818,41 @@ UNION drop table t1; --echo End of 5.5 tests + +--echo # +--echo # MDEV-27382: OFFSET is ignored when it is combined with the DISTINCT, IN() and JOIN +--echo # +CREATE TABLE t1 ( + id int(7) NOT NULL AUTO_INCREMENT, + name varchar(50) DEFAULT NULL, + primary key (id) +); +INSERT INTO t1 VALUES (1, 'Reed'), (10, 'no-child'); + +CREATE TABLE t2 ( + id int(11) NOT NULL AUTO_INCREMENT, + parent_id int(7) NOT NULL, + name varchar(100) DEFAULT NULL, + primary key (id), + key(parent_id) +); + +INSERT INTO t2 VALUES (1, 1,'John'), (2, 2,'no-parent'); + +SELECT DISTINCT p.id +FROM t1 p LEFT JOIN t2 c ON p.id = c.parent_id +WHERE p.id=1 +LIMIT 0; + +SELECT DISTINCT p.id +FROM t1 p LEFT JOIN t2 c ON p.id = c.parent_id +WHERE p.id=1 +LIMIT 0 offset 5; + +--echo # Test the second part of the fix: just check that "LIMIT 0 OFFSET n" is +--echo # handled in the same way as "LIMIT 0" + +explain select * from t1 limit 0; +explain select * from t1 limit 0 offset 10; + +drop table t1, t2; diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 493ea2c87c0..c00bc326bca 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -15,6 +15,7 @@ GCF-939 : MDEV-21520 galera.GCF-939 MDEV-20225 : MDEV-20886 galera.MDEV-20225 MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 +MW-328D : MDEV-27550 ER_LOCK_DEADLOCK is gone after MDEV-27025 MW-329 : MDEV-19962 Galera test failure on MW-329 galera_applier_ftwrl_table_alter : MDEV-26502 : galera.galera_applier_ftwrl_table_alter MTR failed : Result content mismatch galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event() diff --git a/mysql-test/suite/innodb/r/lock_wait_conflict.result b/mysql-test/suite/innodb/r/lock_wait_conflict.result new file mode 100644 index 00000000000..25d18c03ea1 --- /dev/null +++ b/mysql-test/suite/innodb/r/lock_wait_conflict.result @@ -0,0 +1,27 @@ +# +# MDEV-27025 insert-intention lock conflicts with waiting ORDINARY lock +# +CREATE TABLE t (a INT PRIMARY KEY, b INT NOT NULL UNIQUE) ENGINE=InnoDB; +connect prevent_purge,localhost,root,,; +start transaction with consistent snapshot; +connection default; +INSERT INTO t VALUES (20,20); +DELETE FROM t WHERE b = 20; +connect con_ins,localhost,root,,; +SET DEBUG_SYNC = 'row_ins_sec_index_entry_dup_locks_created SIGNAL ins_set_locks WAIT_FOR ins_cont'; +INSERT INTO t VALUES(10, 20); +connect con_del,localhost,root,,; +SET DEBUG_SYNC = 'now WAIT_FOR ins_set_locks'; +SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL del_locked'; +DELETE FROM t WHERE b = 20; +connection default; +SET DEBUG_SYNC = 'now WAIT_FOR del_locked'; +SET DEBUG_SYNC = 'now SIGNAL ins_cont'; +connection con_ins; +disconnect con_ins; +connection con_del; +disconnect con_del; +disconnect prevent_purge; +connection default; +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t; diff --git a/mysql-test/suite/innodb/t/lock_wait_conflict.test b/mysql-test/suite/innodb/t/lock_wait_conflict.test new file mode 100644 index 00000000000..46a29e14b43 --- /dev/null +++ b/mysql-test/suite/innodb/t/lock_wait_conflict.test @@ -0,0 +1,60 @@ +--source include/have_innodb.inc +--source include/count_sessions.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +--echo # +--echo # MDEV-27025 insert-intention lock conflicts with waiting ORDINARY lock +--echo # + +# The test checks the ability to acquire exclusive record lock if the acquiring +# transaction already holds a shared lock on the record and another transaction +# is waiting for a lock. + +CREATE TABLE t (a INT PRIMARY KEY, b INT NOT NULL UNIQUE) ENGINE=InnoDB; + +--connect(prevent_purge,localhost,root,,) +start transaction with consistent snapshot; + +--connection default +INSERT INTO t VALUES (20,20); +DELETE FROM t WHERE b = 20; + +--connect(con_ins,localhost,root,,) +SET DEBUG_SYNC = 'row_ins_sec_index_entry_dup_locks_created SIGNAL ins_set_locks WAIT_FOR ins_cont'; +send +INSERT INTO t VALUES(10, 20); + +--connect(con_del,localhost,root,,) +SET DEBUG_SYNC = 'now WAIT_FOR ins_set_locks'; +SET DEBUG_SYNC = 'lock_wait_suspend_thread_enter SIGNAL del_locked'; +############################################################################### +# This DELETE creates waiting ORDINARY X-lock for heap_no 2 as the record is +# delete-marked, this lock conflicts with ORDINARY S-lock set by the the last +# INSERT. After the last INSERT creates insert-intention lock on +# heap_no 2, this lock will conflict with waiting ORDINARY X-lock of this +# DELETE, what causes DEADLOCK error for this DELETE. +############################################################################### +send +DELETE FROM t WHERE b = 20; + +--connection default +SET DEBUG_SYNC = 'now WAIT_FOR del_locked'; +SET DEBUG_SYNC = 'now SIGNAL ins_cont'; + +--connection con_ins +--reap +--disconnect con_ins + +--connection con_del +# Without the fix, ER_LOCK_DEADLOCK would be reported here. +--reap +--disconnect con_del + +--disconnect prevent_purge + +--connection default + +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t; +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/suite/versioning/r/update.result b/mysql-test/suite/versioning/r/update.result index 9e5e28b09a1..41058969801 100644 --- a/mysql-test/suite/versioning/r/update.result +++ b/mysql-test/suite/versioning/r/update.result @@ -283,7 +283,6 @@ connection default; update t1 set b = 'foo'; connection con1; update t1 set a = 'bar'; -ERROR 40001: Deadlock found when trying to get lock; try restarting transaction disconnect con1; connection default; drop table t1; diff --git a/mysql-test/suite/versioning/t/update.test b/mysql-test/suite/versioning/t/update.test index a3252c9f8e3..df07cec33cb 100644 --- a/mysql-test/suite/versioning/t/update.test +++ b/mysql-test/suite/versioning/t/update.test @@ -186,7 +186,9 @@ send update t1 set b = 'foo'; connection con1; let $wait_condition= select count(*) from information_schema.innodb_lock_waits; source include/wait_condition.inc; -error ER_LOCK_DEADLOCK; +# There must no be DEADLOCK here as con1 transaction already holds locks, and +# default's transaction lock is waiting, so the locks of the following "UPDATE" +# must not conflict with waiting lock. update t1 set a = 'bar'; disconnect con1; connection default; diff --git a/sql/sql_limit.h b/sql/sql_limit.h index b51ebf72493..41308bc12db 100644 --- a/sql/sql_limit.h +++ b/sql/sql_limit.h @@ -37,6 +37,8 @@ class Select_limit_counters void set_limit(ha_rows limit, ha_rows offset, bool with_ties_arg) { + if (limit == 0) + offset= 0; offset_limit_cnt= offset; select_limit_cnt= limit; with_ties= with_ties_arg; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 45aa4267d48..28f03eedac9 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2448,6 +2448,10 @@ void buf_flush_sync() { const lsn_t lsn= log_sys.get_lsn(); buf_flush_wait(lsn); + /* Wait for the page cleaner to be idle (for log resizing at startup) */ + while (buf_flush_sync_lsn) + my_cond_wait(&buf_pool.done_flush_list, + &buf_pool.flush_list_mutex.m_mutex); if (lsn == log_sys.get_lsn()) break; } diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 8e7b8dfd1e6..a732c17f767 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2018, 2021, MariaDB Corporation. +Copyright (c) 2018, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -29,8 +29,43 @@ Created 5/20/1997 Heikki Tuuri #include "ut0new.h" struct hash_table_t; -struct hash_cell_t{ - void* node; /*!< hash chain node, NULL if none */ +struct hash_cell_t +{ + /** singly-linked, nullptr terminated list of hash buckets */ + void *node; + + /** Append an element. + @tparam T type of the element + @param insert the being-inserted element + @param next the next-element pointer in T */ + template<typename T> + void append(T &insert, T *T::*next) + { + void **after; + for (after= &node; *after; + after= reinterpret_cast<void**>(&(static_cast<T*>(*after)->*next))); + insert.*next= nullptr; + *after= &insert; + } + + /** Insert an element after another. + @tparam T type of the element + @param after the element after which to insert + @param insert the being-inserted element + @param next the next-element pointer in T */ + template<typename T> + void insert_after(T &after, T &insert, T *T::*next) + { +#ifdef UNIV_DEBUG + for (const T *c= static_cast<const T*>(node); c; c= c->*next) + if (c == &after) + goto found; + ut_error; + found: +#endif + insert.*next= after.*next; + after.*next= &insert; + } }; /*******************************************************************//** diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 50b9792cf2b..f2b1dc488d6 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1175,6 +1175,10 @@ without checking for deadlocks or conflicts. @param[in] index the index tree @param[in,out] trx transaction @param[in] holds_trx_mutex whether the caller holds trx->mutex +@param[in] insert_before_waiting if true, inserts new B-tree record lock +just after the last non-waiting lock of the current transaction which is +located before the first waiting for the current transaction lock, otherwise +the lock is inserted at the end of the queue @return created lock */ lock_t* lock_rec_create_low( @@ -1185,7 +1189,8 @@ lock_rec_create_low( ulint heap_no, dict_index_t* index, trx_t* trx, - bool holds_trx_mutex); + bool holds_trx_mutex, + bool insert_before_waiting = false); /** Enqueue a waiting request for a lock which cannot be granted immediately. Check for deadlocks. diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index bebd2acfa0d..5551c85db0b 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1004,24 +1004,43 @@ func_exit: /*********************************************************************//** Checks if some other transaction has a conflicting explicit lock request in the queue, so that we have to wait. -@return lock or NULL */ -static -lock_t* -lock_rec_other_has_conflicting( -/*===========================*/ - unsigned mode, /*!< in: LOCK_S or LOCK_X, - possibly ORed to LOCK_GAP or - LOC_REC_NOT_GAP, - LOCK_INSERT_INTENTION */ - const hash_cell_t& cell, /*!< in: lock hash table cell */ - const page_id_t id, /*!< in: page identifier */ - ulint heap_no,/*!< in: heap number of the record */ - const trx_t* trx) /*!< in: our transaction */ +@param[in] mode LOCK_S or LOCK_X, possibly ORed to LOCK_GAP or LOC_REC_NOT_GAP, +LOCK_INSERT_INTENTION +@param[in] cell lock hash table cell +@param[in] id page identifier +@param[in] heap_no heap number of the record +@param[in] trx our transaction +@param[out] was_ignored true if conflicting locks waiting for the current +transaction were ignored +@return conflicting lock and the flag which indicated if conflicting locks +which wait for the current transaction were ignored */ +static lock_t *lock_rec_other_has_conflicting(unsigned mode, + const hash_cell_t &cell, + const page_id_t id, + ulint heap_no, const trx_t *trx, + bool *was_ignored= nullptr) { bool is_supremum = (heap_no == PAGE_HEAP_NO_SUPREMUM); for (lock_t* lock = lock_sys_t::get_first(cell, id, heap_no); lock; lock = lock_rec_get_next(heap_no, lock)) { + /* There is no need to lock lock_sys.wait_mutex to check + trx->lock.wait_trx here because the current function is + executed under the cell latch, and trx->lock.wait_trx + transaction can change wait_trx field only under the cell + latch, wait_trx trx_t object can not be deinitialized before + releasing all its locks, and during releasing the locks the + cell latch will also be requested. So while the cell latch is + held, lock->trx->lock.wait_trx can't be changed. There also + can't be lock loops for one record, because all waiting locks + of the record will always wait for the same lock of the record + in a cell array, and check for conflicting lock will always + start with the first lock for the heap_no, and go ahead with + the same order(the order of the locks in the cell array) */ + if (lock->is_waiting() && lock->trx->lock.wait_trx == trx) { + if (was_ignored) *was_ignored= true; + continue; + } if (lock_rec_has_to_wait(true, trx, mode, lock, is_supremum)) { return(lock); } @@ -1147,6 +1166,10 @@ without checking for deadlocks or conflicts. @param[in] index the index tree @param[in,out] trx transaction @param[in] holds_trx_mutex whether the caller holds trx->mutex +@param[in] insert_before_waiting if true, inserts new B-tree record lock +just after the last non-waiting lock of the current transaction which is +located before the first waiting for the current transaction lock, otherwise +the lock is inserted at the end of the queue @return created lock */ lock_t* lock_rec_create_low( @@ -1157,7 +1180,8 @@ lock_rec_create_low( ulint heap_no, dict_index_t* index, trx_t* trx, - bool holds_trx_mutex) + bool holds_trx_mutex, + bool insert_before_waiting) { lock_t* lock; ulint n_bytes; @@ -1232,7 +1256,36 @@ lock_rec_create_low( ut_ad(index->table->get_ref_count() || !index->table->can_be_evicted); const auto lock_hash = &lock_sys.hash_get(type_mode); - HASH_INSERT(lock_t, hash, lock_hash, page_id.fold(), lock); + hash_cell_t& cell = *lock_hash->cell_get(page_id.fold()); + + if (insert_before_waiting + && !(type_mode & (LOCK_PREDICATE | LOCK_PRDT_PAGE))) { + /* Try to insert the lock just after the last non-waiting + lock of the current transaction which immediately + precedes the first waiting lock request. */ + + lock_t* last_non_waiting = nullptr; + + for (lock_t* l = lock_sys_t::get_first(cell, page_id, heap_no); + l; l = lock_rec_get_next(heap_no, l)) { + if (l->is_waiting() && l->trx->lock.wait_trx == trx) { + break; + } + if (l->trx == trx) { + last_non_waiting = l; + } + } + + if (!last_non_waiting) { + goto append_last; + } + + cell.insert_after(*last_non_waiting, *lock, &lock_t::hash); + } + else { +append_last: + cell.append(*lock, &lock_t::hash); + } if (type_mode & LOCK_WAIT) { if (trx->lock.wait_trx) { @@ -1357,24 +1410,22 @@ on the record, and the request to be added is not a waiting request, we can reuse a suitable record lock object already existing on the same page, just setting the appropriate bit in its bitmap. This is a low-level function which does NOT check for deadlocks or lock compatibility! -@return lock where the bit was set */ +@param[in] type_mode lock mode, wait, gap etc. flags +@param[in,out] cell first hash table cell +@param[in] id page identifier +@param[in] page buffer block containing the record +@param[in] heap_no heap number of the record +@param[in] index index of record +@param[in,out] trx transaction +@param[in] caller_owns_trx_mutex TRUE if caller owns the transaction mutex +@param[in] insert_before_waiting true=insert B-tree record lock right +before a waiting lock request; false=insert the lock at the end of the queue */ TRANSACTIONAL_TARGET -static -void -lock_rec_add_to_queue( -/*==================*/ - unsigned type_mode,/*!< in: lock mode, wait, gap - etc. flags */ - hash_cell_t& cell, /*!< in,out: first hash table cell */ - const page_id_t id, /*!< in: page identifier */ - const page_t* page, /*!< in: buffer block containing - the record */ - ulint heap_no,/*!< in: heap number of the record */ - dict_index_t* index, /*!< in: index of record */ - trx_t* trx, /*!< in/out: transaction */ - bool caller_owns_trx_mutex) - /*!< in: TRUE if caller owns the - transaction mutex */ +static void lock_rec_add_to_queue(unsigned type_mode, hash_cell_t &cell, + const page_id_t id, const page_t *page, + ulint heap_no, dict_index_t *index, + trx_t *trx, bool caller_owns_trx_mutex, + bool insert_before_waiting= false) { ut_d(lock_sys.hash_get(type_mode).assert_locked(id)); ut_ad(xtest() || caller_owns_trx_mutex == trx->mutex_is_owner()); @@ -1469,7 +1520,7 @@ create: lock_rec_create_low(nullptr, type_mode, id, page, heap_no, index, trx, - caller_owns_trx_mutex); + caller_owns_trx_mutex, insert_before_waiting); } /*********************************************************************//** @@ -1536,8 +1587,10 @@ lock_rec_lock( /* Do nothing if the trx already has a strong enough lock on rec */ if (!lock_rec_has_expl(mode, g.cell(), id, heap_no, trx)) { + bool was_ignored = false; if (lock_t *c_lock= lock_rec_other_has_conflicting(mode, g.cell(), id, - heap_no, trx)) + heap_no, trx, + &was_ignored)) /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not @@ -1550,7 +1603,7 @@ lock_rec_lock( { /* Set the requested lock on the record. */ lock_rec_add_to_queue(mode, g.cell(), id, block->page.frame, heap_no, - index, trx, true); + index, trx, true, was_ignored); err= DB_SUCCESS_LOCKED_REC; } } @@ -4654,7 +4707,7 @@ func_exit: wsrep_report_bf_lock_wait(impl_trx->mysql_thd, impl_trx->id); wsrep_report_bf_lock_wait(other_lock->trx->mysql_thd, other_lock->trx->id); - if (!lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, + if (!lock_rec_has_expl(LOCK_S | LOCK_REC_NOT_GAP, cell, id, heap_no, impl_trx)) { ib::info() << "WSREP impl BF lock conflict"; @@ -4663,8 +4716,22 @@ func_exit: #endif /* WITH_WSREP */ { ut_ad(other_lock->is_waiting()); - ut_ad(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, - cell, id, heap_no, + /* After MDEV-27025 fix the following case is + possible: + 1. trx 1 acquires S-lock; + 2. trx 2 creates X-lock waiting for trx 1; + 3. trx 1 creates implicit lock, as + lock_rec_other_has_conflicting() returns no + conflicting trx 2 X-lock, the explicit lock + will not be created; + 4. trx 3 creates waiting X-lock, + it will wait for S-lock of trx 1. + That is why we relaxing the condition here and + check only for S-lock. + */ + ut_ad(lock_rec_has_expl(LOCK_S + | LOCK_REC_NOT_GAP, + cell, id, heap_no, impl_trx)); } } @@ -5060,7 +5127,7 @@ lock_rec_convert_impl_to_expl_for_trx( !lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, g.cell(), id, heap_no, trx)) lock_rec_add_to_queue(LOCK_X | LOCK_REC_NOT_GAP, g.cell(), id, - page_align(rec), heap_no, index, trx, true); + page_align(rec), heap_no, index, trx, true, true); } trx->mutex_unlock(); |