Skip to content

Commit a327e4f

Browse files
committed
[#21705] docdb: Port partition-drop-index-locking and timeouts isolation tests to YB
Summary: Currently ported tests requiring table-level locking: * create-trigger * deadlock-simple * deadlock-hard * deadlock-soft * deadlock-soft-2 This diff ported two more tests partition-drop-index-locking: * Removed query column and pg_stat_activity join from pg_locks query since the lock pid is not avaliable from pg_locks timeouts: * Skipped row-level lock tests with lock_timeout as row-level locks don't respect lock_timeout yet (see #29549). * Enabled LOCK_TIMEOUT on the pg side before calling YBCAcquireObjectLock and added CHECK_FOR_INTERRUPTS() after the call to ensure error messages match pg behavior. reindex-concurrently-toast test is not added as YB doesn't use toast tables. Tracked by gh issue: #29553 Test Plan: ./yb_build.sh --java-test 'org.yb.pgsql.TestPgRegressLock#testIsolation' Reviewers: bkolagani Reviewed By: bkolagani Subscribers: jason, ybase, yql Differential Revision: https://phorge.dev.yugabyte.com/D48672
1 parent 9354c5f commit a327e4f

File tree

8 files changed

+265
-5
lines changed

8 files changed

+265
-5
lines changed

src/postgres/src/backend/storage/lmgr/lock.c

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

5353
/* YB includes */
5454
#include "pg_yb_utils.h"
55+
#include "utils/timeout.h"
5556

5657

5758
/* This configuration variable is used to set the lock table size */
@@ -848,7 +849,17 @@ LockAcquireExtended(const LOCKTAG *locktag,
848849
elog(log_level, "LockAcquire start: lock [%u,%u] mode: %s",
849850
locktag->locktag_field1, locktag->locktag_field2, lockMethodTable->lockModeNames[lockmode]);
850851

851-
HandleYBStatus(YBCAcquireObjectLock(GetYBObjectLockId(locktag), (YbcObjectLockMode) lockmode));
852+
if (LockTimeout > 0)
853+
enable_timeout_after(LOCK_TIMEOUT, LockTimeout);
854+
855+
YbcStatus status = YBCAcquireObjectLock(GetYBObjectLockId(locktag), (YbcObjectLockMode) lockmode);
856+
857+
CHECK_FOR_INTERRUPTS();
858+
859+
if (LockTimeout > 0)
860+
disable_timeout(LOCK_TIMEOUT, false);
861+
862+
HandleYBStatus(status);
852863

853864
elog(log_level, "LockAcquired: lock [%u,%u] mode: %s",
854865
locktag->locktag_field1, locktag->locktag_field2, lockMethodTable->lockModeNames[lockmode]);
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
Parsed test spec with 3 sessions
2+
3+
starting permutation: s1begin s1lock s2begin s2drop s1select s3getlocks s1commit s3getlocks s2commit
4+
step s1begin: BEGIN;
5+
step s1lock: LOCK TABLE part_drop_index_locking_subpart_child IN ACCESS SHARE MODE;
6+
step s2begin: BEGIN;
7+
step s2drop: DROP INDEX part_drop_index_locking_idx; <waiting ...>
8+
step s1select: SELECT * FROM part_drop_index_locking_subpart_child;
9+
id
10+
--
11+
(0 rows)
12+
13+
step s3getlocks:
14+
SELECT c.relname, l.mode, l.granted -- YB: Removed query because pid is NULL, can't join pg_stat_activity
15+
FROM pg_locks l
16+
JOIN pg_class c ON l.relation = c.oid
17+
WHERE c.relname LIKE 'part_drop_index_locking%'
18+
ORDER BY c.relname, l.mode, l.granted; -- YB: Removed query because pid is NULL, can't join pg_stat_activity
19+
20+
relname |mode |granted
21+
---------------------------------------------+-------------------+-------
22+
part_drop_index_locking |AccessExclusiveLock|t
23+
part_drop_index_locking_idx |AccessExclusiveLock|t
24+
part_drop_index_locking_subpart |AccessExclusiveLock|t
25+
part_drop_index_locking_subpart_child |AccessExclusiveLock|f
26+
part_drop_index_locking_subpart_child |AccessShareLock |t
27+
part_drop_index_locking_subpart_child |AccessShareLock |t
28+
part_drop_index_locking_subpart_child_id_idx |AccessShareLock |t
29+
part_drop_index_locking_subpart_child_id_idx1|AccessShareLock |t
30+
(8 rows)
31+
32+
step s1commit: COMMIT;
33+
step s2drop: <... completed>
34+
step s3getlocks:
35+
SELECT c.relname, l.mode, l.granted -- YB: Removed query because pid is NULL, can't join pg_stat_activity
36+
FROM pg_locks l
37+
JOIN pg_class c ON l.relation = c.oid
38+
WHERE c.relname LIKE 'part_drop_index_locking%'
39+
ORDER BY c.relname, l.mode, l.granted; -- YB: Removed query because pid is NULL, can't join pg_stat_activity
40+
41+
relname |mode |granted
42+
--------------------------------------------+-------------------+-------
43+
part_drop_index_locking |AccessExclusiveLock|t
44+
part_drop_index_locking_idx |AccessExclusiveLock|t
45+
part_drop_index_locking_subpart |AccessExclusiveLock|t
46+
part_drop_index_locking_subpart_child |AccessExclusiveLock|t
47+
part_drop_index_locking_subpart_child_id_idx|AccessExclusiveLock|t
48+
part_drop_index_locking_subpart_id_idx |AccessExclusiveLock|t
49+
(6 rows)
50+
51+
step s2commit: COMMIT;
52+
53+
starting permutation: s1begin s1lock s2begin s2dropsub s1select s3getlocks s1commit s3getlocks s2commit
54+
step s1begin: BEGIN;
55+
step s1lock: LOCK TABLE part_drop_index_locking_subpart_child IN ACCESS SHARE MODE;
56+
step s2begin: BEGIN;
57+
step s2dropsub: DROP INDEX part_drop_index_locking_subpart_idx; <waiting ...>
58+
step s1select: SELECT * FROM part_drop_index_locking_subpart_child;
59+
id
60+
--
61+
(0 rows)
62+
63+
step s3getlocks:
64+
SELECT c.relname, l.mode, l.granted -- YB: Removed query because pid is NULL, can't join pg_stat_activity
65+
FROM pg_locks l
66+
JOIN pg_class c ON l.relation = c.oid
67+
WHERE c.relname LIKE 'part_drop_index_locking%'
68+
ORDER BY c.relname, l.mode, l.granted; -- YB: Removed query because pid is NULL, can't join pg_stat_activity
69+
70+
relname |mode |granted
71+
---------------------------------------------+-------------------+-------
72+
part_drop_index_locking_subpart |AccessExclusiveLock|t
73+
part_drop_index_locking_subpart_child |AccessExclusiveLock|f
74+
part_drop_index_locking_subpart_child |AccessShareLock |t
75+
part_drop_index_locking_subpart_child |AccessShareLock |t
76+
part_drop_index_locking_subpart_child_id_idx |AccessShareLock |t
77+
part_drop_index_locking_subpart_child_id_idx1|AccessShareLock |t
78+
part_drop_index_locking_subpart_idx |AccessExclusiveLock|t
79+
(7 rows)
80+
81+
step s1commit: COMMIT;
82+
step s2dropsub: <... completed>
83+
step s3getlocks:
84+
SELECT c.relname, l.mode, l.granted -- YB: Removed query because pid is NULL, can't join pg_stat_activity
85+
FROM pg_locks l
86+
JOIN pg_class c ON l.relation = c.oid
87+
WHERE c.relname LIKE 'part_drop_index_locking%'
88+
ORDER BY c.relname, l.mode, l.granted; -- YB: Removed query because pid is NULL, can't join pg_stat_activity
89+
90+
relname |mode |granted
91+
---------------------------------------------+-------------------+-------
92+
part_drop_index_locking_subpart |AccessExclusiveLock|t
93+
part_drop_index_locking_subpart_child |AccessExclusiveLock|t
94+
part_drop_index_locking_subpart_child_id_idx1|AccessExclusiveLock|t
95+
part_drop_index_locking_subpart_idx |AccessExclusiveLock|t
96+
(4 rows)
97+
98+
step s2commit: COMMIT;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: rdtbl sto locktbl
4+
step rdtbl: SELECT * FROM accounts;
5+
accountid|balance
6+
---------+-------
7+
checking | 600
8+
savings | 600
9+
(2 rows)
10+
11+
step sto: SET statement_timeout = '10ms';
12+
step locktbl: LOCK TABLE accounts; <waiting ...>
13+
step locktbl: <... completed>
14+
ERROR: canceling statement due to statement timeout
15+
16+
starting permutation: rdtbl lto locktbl
17+
step rdtbl: SELECT * FROM accounts;
18+
accountid|balance
19+
---------+-------
20+
checking | 600
21+
savings | 600
22+
(2 rows)
23+
24+
step lto: SET lock_timeout = '10ms';
25+
step locktbl: LOCK TABLE accounts; <waiting ...>
26+
step locktbl: <... completed>
27+
ERROR: canceling statement due to lock timeout
28+
29+
starting permutation: rdtbl lsto locktbl
30+
step rdtbl: SELECT * FROM accounts;
31+
accountid|balance
32+
---------+-------
33+
checking | 600
34+
savings | 600
35+
(2 rows)
36+
37+
step lsto: SET lock_timeout = '10ms'; SET statement_timeout = '10s';
38+
step locktbl: LOCK TABLE accounts; <waiting ...>
39+
step locktbl: <... completed>
40+
ERROR: canceling statement due to lock timeout
41+
42+
starting permutation: rdtbl slto locktbl
43+
step rdtbl: SELECT * FROM accounts;
44+
accountid|balance
45+
---------+-------
46+
checking | 600
47+
savings | 600
48+
(2 rows)
49+
50+
step slto: SET lock_timeout = '10s'; SET statement_timeout = '10ms';
51+
step locktbl: LOCK TABLE accounts; <waiting ...>
52+
step locktbl: <... completed>
53+
ERROR: canceling statement due to statement timeout
54+
55+
starting permutation: wrtbl sto update
56+
step wrtbl: UPDATE accounts SET balance = balance + 100;
57+
step sto: SET statement_timeout = '10ms';
58+
step update: DELETE FROM accounts WHERE accountid = 'checking'; <waiting ...>
59+
step update: <... completed>
60+
ERROR: canceling statement due to statement timeout
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# Verify that DROP INDEX properly locks all downward sub-partitions
2+
# and partitions before locking the indexes.
3+
4+
setup
5+
{
6+
CREATE TABLE part_drop_index_locking (id int) PARTITION BY RANGE(id);
7+
CREATE TABLE part_drop_index_locking_subpart PARTITION OF part_drop_index_locking FOR VALUES FROM (1) TO (100) PARTITION BY RANGE(id);
8+
CREATE TABLE part_drop_index_locking_subpart_child PARTITION OF part_drop_index_locking_subpart FOR VALUES FROM (1) TO (100);
9+
CREATE INDEX part_drop_index_locking_idx ON part_drop_index_locking(id);
10+
CREATE INDEX part_drop_index_locking_subpart_idx ON part_drop_index_locking_subpart(id);
11+
}
12+
13+
teardown
14+
{
15+
DROP TABLE part_drop_index_locking;
16+
}
17+
18+
# SELECT will take AccessShare lock first on the table and then on its index.
19+
# We can simulate the case where DROP INDEX starts between those steps
20+
# by manually taking the table lock beforehand.
21+
session s1
22+
step s1begin { BEGIN; }
23+
step s1lock { LOCK TABLE part_drop_index_locking_subpart_child IN ACCESS SHARE MODE; }
24+
step s1select { SELECT * FROM part_drop_index_locking_subpart_child; }
25+
step s1commit { COMMIT; }
26+
27+
session s2
28+
step s2begin { BEGIN; }
29+
step s2drop { DROP INDEX part_drop_index_locking_idx; }
30+
step s2dropsub { DROP INDEX part_drop_index_locking_subpart_idx; }
31+
step s2commit { COMMIT; }
32+
33+
session s3
34+
step s3getlocks {
35+
SELECT c.relname, l.mode, l.granted -- YB: Removed query because pid is NULL, can't join pg_stat_activity
36+
FROM pg_locks l
37+
JOIN pg_class c ON l.relation = c.oid
38+
WHERE c.relname LIKE 'part_drop_index_locking%'
39+
ORDER BY c.relname, l.mode, l.granted; -- YB: Removed query because pid is NULL, can't join pg_stat_activity
40+
}
41+
42+
# Run DROP INDEX on top partitioned table
43+
permutation s1begin s1lock s2begin s2drop(s1commit) s1select s3getlocks s1commit s3getlocks s2commit
44+
45+
# Run DROP INDEX on top sub-partition table
46+
permutation s1begin s1lock s2begin s2dropsub(s1commit) s1select s3getlocks s1commit s3getlocks s2commit
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Simple tests for statement_timeout and lock_timeout features
2+
3+
setup
4+
{
5+
CREATE TABLE accounts (accountid text PRIMARY KEY, balance numeric not null);
6+
INSERT INTO accounts VALUES ('checking', 600), ('savings', 600);
7+
}
8+
9+
teardown
10+
{
11+
DROP TABLE accounts;
12+
}
13+
14+
session s1
15+
setup { BEGIN ISOLATION LEVEL READ COMMITTED; }
16+
step rdtbl { SELECT * FROM accounts; }
17+
step wrtbl { UPDATE accounts SET balance = balance + 100; }
18+
teardown { ABORT; }
19+
20+
session s2
21+
setup { BEGIN ISOLATION LEVEL READ COMMITTED; }
22+
step sto { SET statement_timeout = '10ms'; }
23+
step lto { SET lock_timeout = '10ms'; }
24+
step lsto { SET lock_timeout = '10ms'; SET statement_timeout = '10s'; }
25+
step slto { SET lock_timeout = '10s'; SET statement_timeout = '10ms'; }
26+
step locktbl { LOCK TABLE accounts; }
27+
step update { DELETE FROM accounts WHERE accountid = 'checking'; }
28+
teardown { ABORT; }
29+
30+
# It's possible that the isolation tester will not observe the final
31+
# steps as "waiting", thanks to the relatively short timeouts we use.
32+
# We can ensure consistent test output by marking those steps with (*).
33+
34+
# statement timeout, table-level lock
35+
permutation rdtbl sto locktbl(*)
36+
# lock timeout, table-level lock
37+
permutation rdtbl lto locktbl(*)
38+
# lock timeout expires first, table-level lock
39+
permutation rdtbl lsto locktbl(*)
40+
# statement timeout expires first, table-level lock
41+
permutation rdtbl slto locktbl(*)
42+
# statement timeout, row-level lock
43+
permutation wrtbl sto update(*)

src/postgres/src/test/isolation/yb_pg_isolation_lock_schedule

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ test: yb.port.deadlock-hard
33
test: yb.port.deadlock-soft
44
test: yb.port.deadlock-soft-2
55
test: create-trigger
6-
# TODO(#26792): Enable the test once we add support for honoring lock_timeout.
7-
# test: timeouts
6+
# TODO(#29549): Port row-level lock timeout tests once lock_timeout is supported for row-level locks.
7+
test: yb.port.timeouts
8+
test: yb.port.partition-drop-index-locking

src/yb/yql/pgwrapper/pg_ddl_atomicity-test.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,6 +1044,7 @@ TEST_P(PgDdlAtomicitySanityTestWithTableLocks, DmlWithAddColTest) {
10441044
// With table locks, the add-column operation will be blocked until the DML transaction
10451045
// is committed. This is because the add-column operation acquires an EXCLUSIVE lock on the table
10461046
// and the DML transaction acquires an ACCESS_SHARE lock on the table (at ts-1).
1047+
const int kTimeoutSec = 3;
10471048
auto client = ASSERT_RESULT(cluster_->CreateClient());
10481049
const string table = "dml_with_add_col_test";
10491050
CreateTable(table);
@@ -1056,7 +1057,7 @@ TEST_P(PgDdlAtomicitySanityTestWithTableLocks, DmlWithAddColTest) {
10561057

10571058
// Conn2: Initiate rollback of the alter.
10581059
ASSERT_OK(cluster_->SetFlagOnMasters("TEST_pause_ddl_rollback", "true"));
1059-
ASSERT_OK(conn2.Execute("SET statement_timeout = 8"));
1060+
ASSERT_OK(conn2.Execute("SET statement_timeout = '" + std::to_string(kTimeoutSec) + "s'"));
10601061

10611062
if (TableLocksEnabled()) {
10621063
// Conn2 will have to fail because it cannot get the table locks held by conn1.

src/yb/yql/pgwrapper/pg_object_locks-test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ TEST_F(PgObjectLocksTest, VerifyLockTimeout) {
848848
// Verify the lock attempt fails with lock timeout error.
849849
Status result = conn2_lock_future.get();
850850
ASSERT_NOK(result);
851-
ASSERT_STR_CONTAINS(result.ToString(), "Timed out");
851+
ASSERT_STR_CONTAINS(result.ToString(), "canceling statement due to lock timeout");
852852

853853
// Conn1 should still be able to commit
854854
ASSERT_OK(conn1.CommitTransaction());

0 commit comments

Comments
 (0)