mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Implement SKIP LOCKED for row-level locks
This clause changes the behavior of SELECT locking clauses in the presence of locked rows: instead of causing a process to block waiting for the locks held by other processes (or raise an error, with NOWAIT), SKIP LOCKED makes the new reader skip over such rows. While this is not appropriate behavior for general purposes, there are some cases in which it is useful, such as queue-like tables. Catalog version bumped because this patch changes the representation of stored rules. Reviewed by Craig Ringer (based on a previous attempt at an implementation by Simon Riggs, who also provided input on the syntax used in the current patch), David Rowley, and Álvaro Herrera. Author: Thomas Munro
This commit is contained in:
49
src/test/isolation/expected/skip-locked-2.out
Normal file
49
src/test/isolation/expected/skip-locked-2.out
Normal file
@ -0,0 +1,49 @@
|
||||
Parsed test spec with 2 sessions
|
||||
|
||||
starting permutation: s1a s2a s2b s1b s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s2b s1b s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s2b s1a s1b s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: COMMIT;
|
||||
step s2c: COMMIT;
|
19
src/test/isolation/expected/skip-locked-3.out
Normal file
19
src/test/isolation/expected/skip-locked-3.out
Normal file
@ -0,0 +1,19 @@
|
||||
Parsed test spec with 3 sessions
|
||||
|
||||
starting permutation: s1a s2a s3a s1b s2b s3b
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE LIMIT 1; <waiting ...>
|
||||
step s3a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: COMMIT;
|
||||
step s2a: <... completed>
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: COMMIT;
|
||||
step s3b: COMMIT;
|
21
src/test/isolation/expected/skip-locked-4.out
Normal file
21
src/test/isolation/expected/skip-locked-4.out
Normal file
@ -0,0 +1,21 @@
|
||||
Parsed test spec with 2 sessions
|
||||
|
||||
starting permutation: s2a s1a s2b s2c s2d s2e s1b s2f
|
||||
step s2a: SELECT pg_advisory_lock(0);
|
||||
pg_advisory_lock
|
||||
|
||||
|
||||
step s1a: SELECT * FROM foo WHERE pg_advisory_lock(0) IS NOT NULL ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED; <waiting ...>
|
||||
step s2b: UPDATE foo SET data = data WHERE id = 1;
|
||||
step s2c: BEGIN;
|
||||
step s2d: UPDATE foo SET data = data WHERE id = 1;
|
||||
step s2e: SELECT pg_advisory_unlock(0);
|
||||
pg_advisory_unlock
|
||||
|
||||
t
|
||||
step s1a: <... completed>
|
||||
id data
|
||||
|
||||
2 x
|
||||
step s1b: COMMIT;
|
||||
step s2f: COMMIT;
|
19
src/test/isolation/expected/skip-locked-4_1.out
Normal file
19
src/test/isolation/expected/skip-locked-4_1.out
Normal file
@ -0,0 +1,19 @@
|
||||
Parsed test spec with 2 sessions
|
||||
|
||||
starting permutation: s2a s1a s2b s2c s2d s2e s1b s2f
|
||||
step s2a: SELECT pg_advisory_lock(0);
|
||||
pg_advisory_lock
|
||||
|
||||
|
||||
step s1a: SELECT * FROM foo WHERE pg_advisory_lock(0) IS NOT NULL ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED; <waiting ...>
|
||||
step s2b: UPDATE foo SET data = data WHERE id = 1;
|
||||
step s2c: BEGIN;
|
||||
step s2d: UPDATE foo SET data = data WHERE id = 1;
|
||||
step s2e: SELECT pg_advisory_unlock(0);
|
||||
pg_advisory_unlock
|
||||
|
||||
t
|
||||
step s1a: <... completed>
|
||||
error in steps s2e s1a: ERROR: could not serialize access due to concurrent update
|
||||
step s1b: COMMIT;
|
||||
step s2f: COMMIT;
|
401
src/test/isolation/expected/skip-locked.out
Normal file
401
src/test/isolation/expected/skip-locked.out
Normal file
@ -0,0 +1,401 @@
|
||||
Parsed test spec with 2 sessions
|
||||
|
||||
starting permutation: s1a s1b s1c s2a s2b s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s1b s2a s1c s2b s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s1b s2a s2b s1c s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s1b s2a s2b s2c s1c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s1b s1c s2b s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s1b s2b s1c s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s1b s2b s2c s1c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s2b s1b s1c s2c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s2b s1b s2c s1c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s1a s2a s2b s2c s1b s1c
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s1b s1c s2b s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s1b s2b s1c s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s1b s2b s2c s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s2b s1b s1c s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s2b s1b s2c s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s1a s2b s2c s1b s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s2b s1a s1b s1c s2c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1c: COMMIT;
|
||||
step s2c: COMMIT;
|
||||
|
||||
starting permutation: s2a s2b s1a s1b s2c s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s2b s1a s2c s1b s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
2 bar NEW
|
||||
step s2c: COMMIT;
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
||||
|
||||
starting permutation: s2a s2b s2c s1a s1b s1c
|
||||
step s2a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s2c: COMMIT;
|
||||
step s1a: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1b: SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1;
|
||||
id data status
|
||||
|
||||
1 foo NEW
|
||||
step s1c: COMMIT;
|
@ -27,6 +27,10 @@ test: nowait-2
|
||||
test: nowait-3
|
||||
test: nowait-4
|
||||
test: nowait-5
|
||||
test: skip-locked
|
||||
test: skip-locked-2
|
||||
test: skip-locked-3
|
||||
test: skip-locked-4
|
||||
test: drop-index-concurrently-1
|
||||
test: alter-table-1
|
||||
test: timeouts
|
||||
|
@ -27,4 +27,9 @@ step "s2d" { UPDATE foo SET data = data; }
|
||||
step "s2e" { SELECT pg_advisory_unlock(0); }
|
||||
step "s2f" { COMMIT; }
|
||||
|
||||
# s1 takes a snapshot but then waits on an advisory lock, then s2
|
||||
# updates the row in one transaction, then again in another without
|
||||
# committing, before allowing s1 to proceed to try to lock a row;
|
||||
# because it has a snapshot that sees the older version, we reach the
|
||||
# waiting code in EvalPlanQualFetch which ereports when in NOWAIT mode.
|
||||
permutation "s2a" "s1a" "s2b" "s2c" "s2d" "s2e" "s1b" "s2f"
|
||||
|
41
src/test/isolation/specs/skip-locked-2.spec
Normal file
41
src/test/isolation/specs/skip-locked-2.spec
Normal file
@ -0,0 +1,41 @@
|
||||
# Test SKIP LOCKED with multixact locks.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE queue (
|
||||
id int PRIMARY KEY,
|
||||
data text NOT NULL,
|
||||
status text NOT NULL
|
||||
);
|
||||
INSERT INTO queue VALUES (1, 'foo', 'NEW'), (2, 'bar', 'NEW');
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE queue;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN; }
|
||||
step "s1a" { SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1; }
|
||||
step "s1b" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup { BEGIN; }
|
||||
step "s2a" { SELECT * FROM queue ORDER BY id FOR SHARE SKIP LOCKED LIMIT 1; }
|
||||
step "s2b" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s2c" { COMMIT; }
|
||||
|
||||
# s1 and s2 both get SHARE lock, creating a multixact lock, then s2
|
||||
# tries to update to UPDATE but skips the record because it can't
|
||||
# acquire a multixact lock
|
||||
permutation "s1a" "s2a" "s2b" "s1b" "s2c"
|
||||
|
||||
# the same but with the SHARE locks acquired in a different order, so
|
||||
# s2 again skips because it can't acquired a multixact lock
|
||||
permutation "s2a" "s1a" "s2b" "s1b" "s2c"
|
||||
|
||||
# s2 acquires SHARE then UPDATE, then s1 tries to acquire SHARE but
|
||||
# can't so skips the first record because it can't acquire a regular
|
||||
# lock
|
||||
permutation "s2a" "s2b" "s1a" "s1b" "s2c"
|
36
src/test/isolation/specs/skip-locked-3.spec
Normal file
36
src/test/isolation/specs/skip-locked-3.spec
Normal file
@ -0,0 +1,36 @@
|
||||
# Test SKIP LOCKED with tuple locks.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE queue (
|
||||
id int PRIMARY KEY,
|
||||
data text NOT NULL,
|
||||
status text NOT NULL
|
||||
);
|
||||
INSERT INTO queue VALUES (1, 'foo', 'NEW'), (2, 'bar', 'NEW');
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE queue;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN; }
|
||||
step "s1a" { SELECT * FROM queue ORDER BY id FOR UPDATE LIMIT 1; }
|
||||
step "s1b" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup { BEGIN; }
|
||||
step "s2a" { SELECT * FROM queue ORDER BY id FOR UPDATE LIMIT 1; }
|
||||
step "s2b" { COMMIT; }
|
||||
|
||||
session "s3"
|
||||
setup { BEGIN; }
|
||||
step "s3a" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s3b" { COMMIT; }
|
||||
|
||||
# s3 skips to the second record because it can't obtain the tuple lock
|
||||
# (s2 holds the tuple lock because it is next in line to obtain the
|
||||
# row lock, and s1 holds the row lock)
|
||||
permutation "s1a" "s2a" "s3a" "s1b" "s2b" "s3b"
|
36
src/test/isolation/specs/skip-locked-4.spec
Normal file
36
src/test/isolation/specs/skip-locked-4.spec
Normal file
@ -0,0 +1,36 @@
|
||||
# Test SKIP LOCKED with an updated tuple chain.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE foo (
|
||||
id int PRIMARY KEY,
|
||||
data text NOT NULL
|
||||
);
|
||||
INSERT INTO foo VALUES (1, 'x'), (2, 'x');
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE foo;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN; }
|
||||
step "s1a" { SELECT * FROM foo WHERE pg_advisory_lock(0) IS NOT NULL ORDER BY id LIMIT 1 FOR UPDATE SKIP LOCKED; }
|
||||
step "s1b" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
step "s2a" { SELECT pg_advisory_lock(0); }
|
||||
step "s2b" { UPDATE foo SET data = data WHERE id = 1; }
|
||||
step "s2c" { BEGIN; }
|
||||
step "s2d" { UPDATE foo SET data = data WHERE id = 1; }
|
||||
step "s2e" { SELECT pg_advisory_unlock(0); }
|
||||
step "s2f" { COMMIT; }
|
||||
|
||||
# s1 takes a snapshot but then waits on an advisory lock, then s2
|
||||
# updates the row in one transaction, then again in another without
|
||||
# committing, before allowing s1 to proceed to try to lock a row;
|
||||
# because it has a snapshot that sees the older version, we reach the
|
||||
# waiting code in EvalPlanQualFetch which skips rows when in SKIP
|
||||
# LOCKED mode, so s1 sees the second row
|
||||
permutation "s2a" "s1a" "s2b" "s2c" "s2d" "s2e" "s1b" "s2f"
|
28
src/test/isolation/specs/skip-locked.spec
Normal file
28
src/test/isolation/specs/skip-locked.spec
Normal file
@ -0,0 +1,28 @@
|
||||
# Test SKIP LOCKED when regular row locks can't be acquired.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE queue (
|
||||
id int PRIMARY KEY,
|
||||
data text NOT NULL,
|
||||
status text NOT NULL
|
||||
);
|
||||
INSERT INTO queue VALUES (1, 'foo', 'NEW'), (2, 'bar', 'NEW');
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE queue;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN; }
|
||||
step "s1a" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s1b" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s1c" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup { BEGIN; }
|
||||
step "s2a" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s2b" { SELECT * FROM queue ORDER BY id FOR UPDATE SKIP LOCKED LIMIT 1; }
|
||||
step "s2c" { COMMIT; }
|
Reference in New Issue
Block a user