1
0
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:
Thomas Munro
2019-03-15 16:23:46 +13:00
parent 13e8643bfc
commit bb16aba50c
19 changed files with 429 additions and 67 deletions

View 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;

View 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

View File

@ -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

View 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"

View 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"