Hi Kyle,
Thank you for the simplified example. It is showing a different
problem than the one that I initially had in mind.
I converted it to the following .test file and invoked ./mtr --rr on
the test for more convenient debugging with rr replay:
--source include/have_innodb.inc
CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1,1),(2,2),(3,3);
BEGIN;
SELECT * FROM t1 WHERE a=2;
--connect t3,localhost,root
UPDATE t1 SET b=12 WHERE a=2;
--disconnect t3
--connection default
SELECT * FROM t1 WHERE a=2;
UPDATE t1 SET b=-1 WHERE a=2;
SELECT * FROM t1 WHERE a=2;
COMMIT;
DROP TABLE t1;
During the last UPDATE, I set a breakpoint on row_search_mvcc and then
watch -l prebuilt->trx.lock.n_rec_locks
to catch where the record lock is created. Here is a MariaDB Server
10.6 stack trace:
#0 lock_rec_set_nth_bit (lock=0x7f4e583e5c80, i=3) at
/mariadb/10.6/storage/innobase/include/lock0priv.inl:101
#1 0x0000564e48969508 in lock_rec_create_low (c_lock=0x0,
type_mode=1027, page_id=..., page=0x7f4e53cd0000 "", heap_no=3,
index=0x7f4e2c115a18, trx=0x7f4e583e5b80, holds_trx_mutex=false)
at /mariadb/10.6/storage/innobase/lock/lock0lock.cc:1270
#2 0x0000564e4896b704 in lock_rec_lock (impl=false, mode=1027,
block=0x7f4e5380f490, heap_no=3, index=0x7f4e2c115a18,
thr=0x7f4e2c203118) at
/mariadb/10.6/storage/innobase/lock/lock0lock.cc:1692
#3 0x0000564e4897d320 in lock_clust_rec_read_check_and_lock (flags=0,
block=0x7f4e5380f490, rec=0x7f4e53cd0097 "\200", index=0x7f4e2c115a18,
offsets=0x7f4e5814bb40, mode=LOCK_X, gap_mode=1024,
thr=0x7f4e2c203118) at /mariadb/10.6/storage/innobase/lock/lock0lock.cc:5927
#4 0x0000564e48ac85b7 in sel_set_rec_lock (pcur=0x7f4e2c202978,
rec=0x7f4e53cd0097 "\200", index=0x7f4e2c115a18,
offsets=0x7f4e5814bb40, mode=3, type=1024, thr=0x7f4e2c203118,
mtr=0x7f4e5814bf20)
at /mariadb/10.6/storage/innobase/row/row0sel.cc:1349
#5 0x0000564e48ad3dfe in row_search_mvcc (buf=0x7f4e2c2012f8 "\377",
mode=PAGE_CUR_GE, prebuilt=0x7f4e2c2027a8, match_mode=1, direction=0)
at /mariadb/10.6/storage/innobase/row/row0sel.cc:5234
I tried a quick and dirty patch (attached) to fix this particular
case. Note: it only works with a fixed-length PRIMARY KEY, and I did
not run the regression test suite, only this particular test. We would
also need something similar for secondary indexes. But it is a start:
mysqltest: At line 9: query 'UPDATE t1 SET b=12 WHERE a=2' failed:
ER_LOCK_DEADLOCK (1213): Deadlock found when trying to get lock; try
restarting transaction
Would you be interested to help fix all this? It would be an iterative
process: you provide tests and we would update a branch accordingly.
You could even download precompiled packages from our CI system if
that is more convenient. Once we have it sorted out in some way (such
as "faking" deadlock errors), then it would be time to polish it, to
introduce new error messages or a new transaction isolation level, to
avoid risk of breaking any applications that would expect the current
buggy behaviour. First we would have to get the logic right.
Best regards,
Marko
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index c9072998e66..3b205e6be50 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -5924,6 +5924,13 @@ lock_clust_rec_read_check_and_lock(
return DB_SUCCESS;
}
+ if (auto offset = index->trx_id_offset) {
+ if (!trx->read_view.changes_visible(
+ trx_read_trx_id(rec + offset))) {
+ return DB_DEADLOCK;
+ }
+ }
+
dberr_t err = lock_rec_lock(false, gap_mode | mode,
block, heap_no, index, thr);
_______________________________________________
discuss mailing list -- [email protected]
To unsubscribe send an email to [email protected]