diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-29 08:54:33 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2018-05-29 08:54:33 +0300 |
commit | 35a9c90fff5e2b8ffc5acc7d7ed051f04c013213 (patch) | |
tree | 7b7647ad28bdac118f02238aa2b578af4ea4a2a8 /storage/innobase/row/row0sel.cc | |
parent | d8da920264a0321e6d03b3cbe3c3b414f622aefa (diff) | |
download | mariadb-git-35a9c90fff5e2b8ffc5acc7d7ed051f04c013213.tar.gz |
MDEV-14589 InnoDB should not lock a delete-marked record
When the transaction isolation level is SERIALIZABLE, or when
a locking read is performed in the REPEATABLE READ isolation level,
InnoDB must lock delete-marked records in order to prevent another
transaction from inserting something.
However, at READ UNCOMMITTED or READ COMMITTED isolation level or
when the parameter innodb_locks_unsafe_for_binlog is set, the
repeatability of the reads does not matter, and there is no need
to lock any records.
row_search_for_mysql(): Skip locks on delete-marked committed records
upfront, instead of invoking row_unlock_for_mysql() afterwards.
The unlocking never worked for secondary index records.
Diffstat (limited to 'storage/innobase/row/row0sel.cc')
-rw-r--r-- | storage/innobase/row/row0sel.cc | 35 |
1 files changed, 21 insertions, 14 deletions
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 7af788973f2..06bf4cc30c0 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -4656,9 +4656,27 @@ wrong_offs: ulint lock_type; + if (srv_locks_unsafe_for_binlog + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) { + /* At READ COMMITTED or READ UNCOMMITTED + isolation levels, do not lock committed + delete-marked records. */ + if (!rec_get_deleted_flag(rec, comp)) { + goto no_gap_lock; + } + if (trx_id_t trx_id = index == clust_index + ? row_get_rec_trx_id(rec, index, offsets) + : row_vers_impl_x_locked(rec, index, offsets)) { + if (trx_rw_is_active(trx_id, NULL)) { + /* The record belongs to an active + transaction. We must acquire a lock. */ + goto no_gap_lock; + } + } + goto locks_ok_del_marked; + } + if (!set_also_gap_locks - || srv_locks_unsafe_for_binlog - || trx->isolation_level <= TRX_ISO_READ_COMMITTED || (unique_search && !rec_get_deleted_flag(rec, comp))) { goto no_gap_lock; @@ -4849,20 +4867,9 @@ locks_ok: page_rec_is_comp() cannot be used! */ if (rec_get_deleted_flag(rec, comp)) { - +locks_ok_del_marked: /* The record is delete-marked: we can skip it */ - if ((srv_locks_unsafe_for_binlog - || trx->isolation_level <= TRX_ISO_READ_COMMITTED) - && prebuilt->select_lock_type != LOCK_NONE - && !did_semi_consistent_read) { - - /* No need to keep a lock on a delete-marked record - if we do not want to use next-key locking. */ - - row_unlock_for_mysql(prebuilt, TRUE); - } - /* This is an optimization to skip setting the next key lock on the record that follows this delete-marked record. This optimization works because of the unique search criteria |