Skip to content

Commit 86c1bf1

Browse files
committed
MDEV-27992 DELETE fails to delete record after blocking is released
MDEV-27025 allows to insert records before the record on which DELETE is locked, as a result the DELETE misses those records, what causes serious ACID violation. Revert MDEV-27025, MDEV-27550. The test which shows the scenario of ACID violation is added.
1 parent 02da00a commit 86c1bf1

File tree

15 files changed

+249
-427
lines changed

15 files changed

+249
-427
lines changed

mysql-test/suite/galera/disabled.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
1414
MW-328B : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002
15-
MW-328D : MDEV-27550 ER_LOCK_DEADLOCK is gone after MDEV-27025
1615
MW-329 : MDEV-19962 Galera test failure on MW-329
1716
galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event()
1817
galera_concurrent_ctas : MDEV-24842 Galera test failure on galera_concurrent_ctas
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB;
2+
INSERT INTO t VALUES (3);
3+
BEGIN;
4+
connection default;
5+
UPDATE t SET a = 2;
6+
connect con1,localhost,root;
7+
DELETE FROM t;
8+
connection default;
9+
UPDATE t SET a = 1;
10+
COMMIT;
11+
connection con1;
12+
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
13+
disconnect con1;
14+
connection default;
15+
# The above DELETE must delete all the rows in the table, so the
16+
# following SELECT must show 0 rows.
17+
SELECT count(*) FROM t;
18+
count(*)
19+
1
20+
DROP TABLE t;

mysql-test/suite/innodb/r/lock_wait_conflict.result

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--source include/have_innodb.inc
2+
--source include/count_sessions.inc
3+
4+
CREATE TABLE t(a INT PRIMARY KEY) ENGINE=InnoDB;
5+
INSERT INTO t VALUES (3);
6+
7+
BEGIN;
8+
9+
connection default;
10+
UPDATE t SET a = 2;
11+
12+
connect con1,localhost,root;
13+
send DELETE FROM t;
14+
15+
connection default;
16+
let $wait_condition=
17+
select count(*) = 1 from information_schema.processlist
18+
where state = "Updating" and info = "DELETE FROM t";
19+
--source include/wait_condition.inc
20+
21+
UPDATE t SET a = 1;
22+
COMMIT;
23+
24+
connection con1;
25+
error ER_LOCK_DEADLOCK;
26+
reap;
27+
disconnect con1;
28+
29+
connection default;
30+
--echo # The above DELETE must delete all the rows in the table, so the
31+
--echo # following SELECT must show 0 rows.
32+
SELECT count(*) FROM t;
33+
DROP TABLE t;
34+
--source include/wait_until_count_sessions.inc

mysql-test/suite/innodb/t/lock_wait_conflict.test

Lines changed: 0 additions & 60 deletions
This file was deleted.

mysql-test/suite/versioning/r/update.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ connection default;
283283
update t1 set b = 'foo';
284284
connection con1;
285285
update t1 set a = 'bar';
286+
ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
286287
disconnect con1;
287288
connection default;
288289
drop table t1;

mysql-test/suite/versioning/t/update.test

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,7 @@ send update t1 set b = 'foo';
186186
connection con1;
187187
let $wait_condition= select count(*) from information_schema.innodb_lock_waits;
188188
source include/wait_condition.inc;
189-
# There must no be DEADLOCK here as con1 transaction already holds locks, and
190-
# default's transaction lock is waiting, so the locks of the following "UPDATE"
191-
# must not conflict with waiting lock.
189+
error ER_LOCK_DEADLOCK;
192190
update t1 set a = 'bar';
193191
disconnect con1;
194192
connection default;

storage/innobase/include/hash0hash.h

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
4-
Copyright (c) 2018, 2022, MariaDB Corporation.
4+
Copyright (c) 2018, MariaDB Corporation.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -31,31 +31,7 @@ Created 5/20/1997 Heikki Tuuri
3131
#include "sync0rw.h"
3232

3333
struct hash_table_t;
34-
35-
struct hash_cell_t
36-
{
37-
/** singly-linked, nullptr terminated list of hash buckets */
38-
void *node;
39-
40-
/** Insert an element after another.
41-
@tparam T type of the element
42-
@param after the element after which to insert
43-
@param insert the being-inserted element
44-
@param next the next-element pointer in T */
45-
template<typename T>
46-
void insert_after(T &after, T &insert, T *T::*next)
47-
{
48-
#ifdef UNIV_DEBUG
49-
for (const T *c= static_cast<const T*>(node); c; c= c->*next)
50-
if (c == &after)
51-
goto found;
52-
ut_error;
53-
found:
54-
#endif
55-
insert.*next= after.*next;
56-
after.*next= &insert;
57-
}
58-
};
34+
struct hash_cell_t;
5935

6036
typedef void*hash_node_t;
6137

@@ -501,6 +477,10 @@ hash_unlock_x_all_but(
501477
hash_table_t*table,/*!< in: hash table */
502478
rw_lock_t*keep_lock);/*!< in: lock to keep */
503479

480+
struct hash_cell_t{
481+
void*node;/*!< hash chain node, NULL if none */
482+
};
483+
504484
/* The hash table structure */
505485
struct hash_table_t {
506486
enum hash_table_sync_ttype;/*<! type of hash_table. */

storage/innobase/include/lock0lock.h

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
4-
Copyright (c) 2017, 2020, 2022, MariaDB Corporation.
4+
Copyright (c) 2017, 2020, MariaDB Corporation.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -888,29 +888,26 @@ class lock_sys_t
888888
/*********************************************************************//**
889889
Creates a new record lock and inserts it to the lock queue. Does NOT check
890890
for deadlocks or lock compatibility!
891-
@param[in] c_lock conflicting lock
892-
@param[in] thr thread owning trx
893-
@param[in] type_mode lock mode and wait flag, type is ignored and replaced by
894-
LOCK_REC
895-
@param[in] block buffer block containing the record
896-
@param[in] heap_no heap number of the record
897-
@param[in] index index of record
898-
@param[in,out] trx transaction
899-
@param[in] caller_owns_trx_mutex TRUE if caller owns trx mutex
900-
@param[in] insert_before_waiting if true, inserts new B-tree record lock
901-
just after the last non-waiting lock of the current transaction which is
902-
located before the first waiting for the current transaction lock, otherwise
903-
the lock is inserted at the end of the queue
904891
@return created lock */
905892
UNIV_INLINE
906-
lock_t *lock_rec_create(lock_t *c_lock,
893+
lock_t*
894+
lock_rec_create(
895+
/*============*/
907896
#ifdef WITH_WSREP
908-
que_thr_t *thr,
897+
lock_t* c_lock,/*!< conflicting lock */
898+
que_thr_t* thr,/*!< thread owning trx */
909899
#endif
910-
ulint type_mode, const buf_block_t *block,
911-
ulint heap_no, dict_index_t *index, trx_t *trx,
912-
bool caller_owns_trx_mutex,
913-
bool insert_before_waiting= false);
900+
ulint type_mode,/*!< in: lock mode and wait
901+
flag, type is ignored and
902+
replaced by LOCK_REC */
903+
const buf_block_t* block,/*!< in: buffer block containing
904+
the record */
905+
ulint heap_no,/*!< in: heap number of the record */
906+
dict_index_t* index,/*!< in: index of record */
907+
trx_t* trx,/*!< in,out: transaction */
908+
boolcaller_owns_trx_mutex);
909+
/*!< in: true if caller owns
910+
trx mutex */
914911

915912
/*************************************************************//**
916913
Removes a record lock request, waiting or granted, from the queue. */
@@ -923,7 +920,6 @@ lock_rec_discard(
923920

924921
/** Create a new record lock and inserts it to the lock queue,
925922
without checking for deadlocks or conflicts.
926-
@param[in] c_lock conflicting lock
927923
@param[in] type_mode lock mode and wait flag; type will be replaced
928924
with LOCK_REC
929925
@param[in] space tablespace id
@@ -933,15 +929,11 @@ without checking for deadlocks or conflicts.
933929
@param[in] index the index tree
934930
@param[in,out] trx transaction
935931
@param[in] holds_trx_mutex whether the caller holds trx->mutex
936-
@param[in] insert_before_waiting if true, inserts new B-tree record lock
937-
just after the last non-waiting lock of the current transaction which is
938-
located before the first waiting for the current transaction lock, otherwise
939-
the lock is inserted at the end of the queue
940932
@return created lock */
941933
lock_t*
942934
lock_rec_create_low(
943-
lock_t* c_lock,
944935
#ifdef WITH_WSREP
936+
lock_t* c_lock,/*!< conflicting lock */
945937
que_thr_t* thr,/*!< thread owning trx */
946938
#endif
947939
ulint type_mode,
@@ -951,12 +943,9 @@ lock_rec_create_low(
951943
ulint heap_no,
952944
dict_index_t* index,
953945
trx_t* trx,
954-
boolholds_trx_mutex,
955-
boolinsert_before_waiting = false);
956-
946+
boolholds_trx_mutex);
957947
/** Enqueue a waiting request for a lock which cannot be granted immediately.
958948
Check for deadlocks.
959-
@param[in] c_lock conflicting lock
960949
@param[in] type_mode the requested lock mode (LOCK_S or LOCK_X)
961950
possibly ORed with LOCK_GAP or
962951
LOCK_REC_NOT_GAP, ORed with
@@ -975,7 +964,9 @@ Check for deadlocks.
975964
(or it happened to commit) */
976965
dberr_t
977966
lock_rec_enqueue_waiting(
978-
lock_t* c_lock,
967+
#ifdef WITH_WSREP
968+
lock_t* c_lock,/*!< conflicting lock */
969+
#endif
979970
ulint type_mode,
980971
const buf_block_t* block,
981972
ulint heap_no,

storage/innobase/include/lock0lock.inl

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -101,37 +101,34 @@ lock_hash_get(
101101
/*********************************************************************//**
102102
Creates a new record lock and inserts it to the lock queue. Does NOT check
103103
for deadlocks or lock compatibility!
104-
@param[in] c_lock conflicting lock
105-
@param[in] thr thread owning trx
106-
@param[in] type_mode lock mode and wait flag, type is ignored and replaced by
107-
LOCK_REC
108-
@param[in] block buffer block containing the record
109-
@param[in] heap_no heap number of the record
110-
@param[in] index index of record
111-
@param[in,out] trx transaction
112-
@param[in] caller_owns_trx_mutex TRUE if caller owns trx mutex
113-
@param[in] insert_before_waiting if true, inserts new B-tree record lock
114-
just after the last non-waiting lock of the current transaction which is
115-
located before the first waiting for the current transaction lock, otherwise
116-
the lock is inserted at the end of the queue
117104
@return created lock */
118105
UNIV_INLINE
119-
lock_t *lock_rec_create(lock_t *c_lock,
106+
lock_t*
107+
lock_rec_create(
108+
/*============*/
120109
#ifdef WITH_WSREP
121-
que_thr_t *thr,
110+
lock_t* c_lock,/*!< conflicting lock */
111+
que_thr_t* thr,/*!< thread owning trx */
122112
#endif
123-
ulint type_mode, const buf_block_t *block,
124-
ulint heap_no, dict_index_t *index, trx_t *trx,
125-
bool caller_owns_trx_mutex,
126-
bool insert_before_waiting)
113+
ulint type_mode,/*!< in: lock mode and wait
114+
flag, type is ignored and
115+
replaced by LOCK_REC */
116+
const buf_block_t* block,/*!< in: buffer block containing
117+
the record */
118+
ulint heap_no,/*!< in: heap number of the record */
119+
dict_index_t* index,/*!< in: index of record */
120+
trx_t* trx,/*!< in,out: transaction */
121+
boolcaller_owns_trx_mutex)
122+
/*!< in: TRUE if caller owns
123+
trx mutex */
127124
{
128125
btr_assert_not_corrupted(block, index);
129-
return lock_rec_create_low(c_lock,
126+
return lock_rec_create_low(
130127
#ifdef WITH_WSREP
131-
thr,
128+
c_lock, thr,
132129
#endif
133130
type_mode,
134131
block->page.id.space(), block->page.id.page_no(),
135-
block->frame, heap_no, index, trx,
136-
caller_owns_trx_mutex, insert_before_waiting);
132+
block->frame, heap_no,
133+
index, trx, caller_owns_trx_mutex);
137134
}

0 commit comments

Comments
 (0)