mirror of
https://github.com/postgres/postgres.git
synced 2025-07-07 00:36:50 +03:00
Enable parallel query with SERIALIZABLE isolation.
Previously, the SERIALIZABLE isolation level prevented parallel query
from being used. Allow the two features to be used together by
sharing the leader's SERIALIZABLEXACT with parallel workers.
An extra per-SERIALIZABLEXACT LWLock is introduced to make it safe to
share, and new logic is introduced to coordinate the early release
of the SERIALIZABLEXACT required for the SXACT_FLAG_RO_SAFE
optimization, as follows:
The first backend to observe the SXACT_FLAG_RO_SAFE flag (set by
some other transaction) will 'partially release' the SERIALIZABLEXACT,
meaning that the conflicts and locks it holds are released, but the
SERIALIZABLEXACT itself will remain active because other backends
might still have a pointer to it.
Whenever any backend notices the SXACT_FLAG_RO_SAFE flag, it clears
its own MySerializableXact variable and frees local resources so that
it can skip SSI checks for the rest of the transaction. In the
special case of the leader process, it transfers the SERIALIZABLEXACT
to a new variable SavedSerializableXact, so that it can be completely
released at the end of the transaction after all workers have exited.
Remove the serializable_okay flag added to CreateParallelContext() by
commit 9da0cc35
, because it's now redundant.
Author: Thomas Munro
Reviewed-by: Haribabu Kommi, Robert Haas, Masahiko Sawada, Kevin Grittner
Discussion: https://postgr.es/m/CAEepm=0gXGYhtrVDWOTHS8SQQy_=S9xo+8oCxGLWZAOoeJ=yzQ@mail.gmail.com
This commit is contained in:
44
src/test/isolation/expected/serializable-parallel-2.out
Normal file
44
src/test/isolation/expected/serializable-parallel-2.out
Normal file
@ -0,0 +1,44 @@
|
||||
Parsed test spec with 2 sessions
|
||||
|
||||
starting permutation: s1r s2r1 s1c s2r2 s2c
|
||||
step s1r: SELECT * FROM foo;
|
||||
a
|
||||
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
step s2r1: SELECT * FROM foo;
|
||||
a
|
||||
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
step s1c: COMMIT;
|
||||
step s2r2: SELECT * FROM foo;
|
||||
a
|
||||
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
10
|
||||
step s2c: COMMIT;
|
44
src/test/isolation/expected/serializable-parallel.out
Normal file
44
src/test/isolation/expected/serializable-parallel.out
Normal file
@ -0,0 +1,44 @@
|
||||
Parsed test spec with 3 sessions
|
||||
|
||||
starting permutation: s2rx s2ry s1ry s1wy s1c s2wx s2c s3c
|
||||
step s2rx: SELECT balance FROM bank_account WHERE id = 'X';
|
||||
balance
|
||||
|
||||
0
|
||||
step s2ry: SELECT balance FROM bank_account WHERE id = 'Y';
|
||||
balance
|
||||
|
||||
0
|
||||
step s1ry: SELECT balance FROM bank_account WHERE id = 'Y';
|
||||
balance
|
||||
|
||||
0
|
||||
step s1wy: UPDATE bank_account SET balance = 20 WHERE id = 'Y';
|
||||
step s1c: COMMIT;
|
||||
step s2wx: UPDATE bank_account SET balance = -11 WHERE id = 'X';
|
||||
step s2c: COMMIT;
|
||||
step s3c: COMMIT;
|
||||
|
||||
starting permutation: s2rx s2ry s1ry s1wy s1c s3r s3c s2wx
|
||||
step s2rx: SELECT balance FROM bank_account WHERE id = 'X';
|
||||
balance
|
||||
|
||||
0
|
||||
step s2ry: SELECT balance FROM bank_account WHERE id = 'Y';
|
||||
balance
|
||||
|
||||
0
|
||||
step s1ry: SELECT balance FROM bank_account WHERE id = 'Y';
|
||||
balance
|
||||
|
||||
0
|
||||
step s1wy: UPDATE bank_account SET balance = 20 WHERE id = 'Y';
|
||||
step s1c: COMMIT;
|
||||
step s3r: SELECT id, balance FROM bank_account WHERE id IN ('X', 'Y') ORDER BY id;
|
||||
id balance
|
||||
|
||||
X 0
|
||||
Y 20
|
||||
step s3c: COMMIT;
|
||||
step s2wx: UPDATE bank_account SET balance = -11 WHERE id = 'X';
|
||||
ERROR: could not serialize access due to read/write dependencies among transactions
|
@ -78,3 +78,5 @@ test: partition-key-update-3
|
||||
test: partition-key-update-4
|
||||
test: plpgsql-toast
|
||||
test: truncate-conflict
|
||||
test: serializable-parallel
|
||||
test: serializable-parallel-2
|
||||
|
30
src/test/isolation/specs/serializable-parallel-2.spec
Normal file
30
src/test/isolation/specs/serializable-parallel-2.spec
Normal file
@ -0,0 +1,30 @@
|
||||
# Exercise the case where a read-only serializable transaction has
|
||||
# SXACT_FLAG_RO_SAFE set in a parallel query.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE foo AS SELECT generate_series(1, 10)::int a;
|
||||
ALTER TABLE foo SET (parallel_workers = 2);
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE foo;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
|
||||
step "s1r" { SELECT * FROM foo; }
|
||||
step "s1c" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup {
|
||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE READ ONLY;
|
||||
SET parallel_setup_cost = 0;
|
||||
SET parallel_tuple_cost = 0;
|
||||
}
|
||||
step "s2r1" { SELECT * FROM foo; }
|
||||
step "s2r2" { SELECT * FROM foo; }
|
||||
step "s2c" { COMMIT; }
|
||||
|
||||
permutation "s1r" "s2r1" "s1c" "s2r2" "s2c"
|
47
src/test/isolation/specs/serializable-parallel.spec
Normal file
47
src/test/isolation/specs/serializable-parallel.spec
Normal file
@ -0,0 +1,47 @@
|
||||
# The example from the paper "A read-only transaction anomaly under snapshot
|
||||
# isolation"[1].
|
||||
#
|
||||
# Here we test that serializable snapshot isolation (SERIALIZABLE) doesn't
|
||||
# suffer from the anomaly, because s2 is aborted upon detection of a cycle.
|
||||
# In this case the read only query s3 happens to be running in a parallel
|
||||
# worker.
|
||||
#
|
||||
# [1] http://www.cs.umb.edu/~poneil/ROAnom.pdf
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE bank_account (id TEXT PRIMARY KEY, balance DECIMAL NOT NULL);
|
||||
INSERT INTO bank_account (id, balance) VALUES ('X', 0), ('Y', 0);
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE bank_account;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
|
||||
step "s1ry" { SELECT balance FROM bank_account WHERE id = 'Y'; }
|
||||
step "s1wy" { UPDATE bank_account SET balance = 20 WHERE id = 'Y'; }
|
||||
step "s1c" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup { BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; }
|
||||
step "s2rx" { SELECT balance FROM bank_account WHERE id = 'X'; }
|
||||
step "s2ry" { SELECT balance FROM bank_account WHERE id = 'Y'; }
|
||||
step "s2wx" { UPDATE bank_account SET balance = -11 WHERE id = 'X'; }
|
||||
step "s2c" { COMMIT; }
|
||||
|
||||
session "s3"
|
||||
setup {
|
||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||
SET force_parallel_mode = on;
|
||||
}
|
||||
step "s3r" { SELECT id, balance FROM bank_account WHERE id IN ('X', 'Y') ORDER BY id; }
|
||||
step "s3c" { COMMIT; }
|
||||
|
||||
# without s3, s1 and s2 commit
|
||||
permutation "s2rx" "s2ry" "s1ry" "s1wy" "s1c" "s2wx" "s2c" "s3c"
|
||||
|
||||
# once s3 observes the data committed by s1, a cycle is created and s2 aborts
|
||||
permutation "s2rx" "s2ry" "s1ry" "s1wy" "s1c" "s3r" "s3c" "s2wx"
|
Reference in New Issue
Block a user