Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitda9456d

Browse files
committed
Add an isolation test to exercise parallel-worker deadlock resolution.
Commita1c1af2 added logic in the deadlock checker to handle lockgrouping, but it was very poorly tested, as evidenced by the bugfixed in3420851. Add a test case that exercises that a bit better(and catches the bug --- if you revert3420851, this will hang).Since it's pretty hard to get parallel workers to take exclusiveregular locks that their parents don't already have, this test operatesby creating a deadlock among advisory locks taken in parallel workers.To make that happen, we must override the parallel-safety labeling ofthe advisory-lock functions, which we do by putting them in mislabeled,non-inlinable wrapper functions.We also have to remove the redundant PreventAdvisoryLocksInParallelModechecks in lockfuncs.c. That seems fine though; if some user accidentallydoes what this test is intentionally doing, not much harm will ensue.(If there are any remaining bugs that are reachable that way, they'reprobably reachable in other ways too.)Discussion:https://postgr.es/m/3243.1564437314@sss.pgh.pa.us
1 parent4886da8 commitda9456d

File tree

4 files changed

+137
-29
lines changed

4 files changed

+137
-29
lines changed

‎src/backend/utils/adt/lockfuncs.c

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -655,15 +655,6 @@ pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
655655
#defineSET_LOCKTAG_INT32(tag,key1,key2) \
656656
SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
657657

658-
staticvoid
659-
PreventAdvisoryLocksInParallelMode(void)
660-
{
661-
if (IsInParallelMode())
662-
ereport(ERROR,
663-
(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
664-
errmsg("cannot use advisory locks during a parallel operation")));
665-
}
666-
667658
/*
668659
* pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
669660
*/
@@ -673,7 +664,6 @@ pg_advisory_lock_int8(PG_FUNCTION_ARGS)
673664
int64key=PG_GETARG_INT64(0);
674665
LOCKTAGtag;
675666

676-
PreventAdvisoryLocksInParallelMode();
677667
SET_LOCKTAG_INT64(tag,key);
678668

679669
(void)LockAcquire(&tag,ExclusiveLock, true, false);
@@ -691,7 +681,6 @@ pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
691681
int64key=PG_GETARG_INT64(0);
692682
LOCKTAGtag;
693683

694-
PreventAdvisoryLocksInParallelMode();
695684
SET_LOCKTAG_INT64(tag,key);
696685

697686
(void)LockAcquire(&tag,ExclusiveLock, false, false);
@@ -708,7 +697,6 @@ pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
708697
int64key=PG_GETARG_INT64(0);
709698
LOCKTAGtag;
710699

711-
PreventAdvisoryLocksInParallelMode();
712700
SET_LOCKTAG_INT64(tag,key);
713701

714702
(void)LockAcquire(&tag,ShareLock, true, false);
@@ -726,7 +714,6 @@ pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
726714
int64key=PG_GETARG_INT64(0);
727715
LOCKTAGtag;
728716

729-
PreventAdvisoryLocksInParallelMode();
730717
SET_LOCKTAG_INT64(tag,key);
731718

732719
(void)LockAcquire(&tag,ShareLock, false, false);
@@ -746,7 +733,6 @@ pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
746733
LOCKTAGtag;
747734
LockAcquireResultres;
748735

749-
PreventAdvisoryLocksInParallelMode();
750736
SET_LOCKTAG_INT64(tag,key);
751737

752738
res=LockAcquire(&tag,ExclusiveLock, true, true);
@@ -767,7 +753,6 @@ pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
767753
LOCKTAGtag;
768754
LockAcquireResultres;
769755

770-
PreventAdvisoryLocksInParallelMode();
771756
SET_LOCKTAG_INT64(tag,key);
772757

773758
res=LockAcquire(&tag,ExclusiveLock, false, true);
@@ -787,7 +772,6 @@ pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
787772
LOCKTAGtag;
788773
LockAcquireResultres;
789774

790-
PreventAdvisoryLocksInParallelMode();
791775
SET_LOCKTAG_INT64(tag,key);
792776

793777
res=LockAcquire(&tag,ShareLock, true, true);
@@ -808,7 +792,6 @@ pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
808792
LOCKTAGtag;
809793
LockAcquireResultres;
810794

811-
PreventAdvisoryLocksInParallelMode();
812795
SET_LOCKTAG_INT64(tag,key);
813796

814797
res=LockAcquire(&tag,ShareLock, false, true);
@@ -828,7 +811,6 @@ pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
828811
LOCKTAGtag;
829812
boolres;
830813

831-
PreventAdvisoryLocksInParallelMode();
832814
SET_LOCKTAG_INT64(tag,key);
833815

834816
res=LockRelease(&tag,ExclusiveLock, true);
@@ -848,7 +830,6 @@ pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
848830
LOCKTAGtag;
849831
boolres;
850832

851-
PreventAdvisoryLocksInParallelMode();
852833
SET_LOCKTAG_INT64(tag,key);
853834

854835
res=LockRelease(&tag,ShareLock, true);
@@ -866,7 +847,6 @@ pg_advisory_lock_int4(PG_FUNCTION_ARGS)
866847
int32key2=PG_GETARG_INT32(1);
867848
LOCKTAGtag;
868849

869-
PreventAdvisoryLocksInParallelMode();
870850
SET_LOCKTAG_INT32(tag,key1,key2);
871851

872852
(void)LockAcquire(&tag,ExclusiveLock, true, false);
@@ -885,7 +865,6 @@ pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
885865
int32key2=PG_GETARG_INT32(1);
886866
LOCKTAGtag;
887867

888-
PreventAdvisoryLocksInParallelMode();
889868
SET_LOCKTAG_INT32(tag,key1,key2);
890869

891870
(void)LockAcquire(&tag,ExclusiveLock, false, false);
@@ -903,7 +882,6 @@ pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
903882
int32key2=PG_GETARG_INT32(1);
904883
LOCKTAGtag;
905884

906-
PreventAdvisoryLocksInParallelMode();
907885
SET_LOCKTAG_INT32(tag,key1,key2);
908886

909887
(void)LockAcquire(&tag,ShareLock, true, false);
@@ -922,7 +900,6 @@ pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
922900
int32key2=PG_GETARG_INT32(1);
923901
LOCKTAGtag;
924902

925-
PreventAdvisoryLocksInParallelMode();
926903
SET_LOCKTAG_INT32(tag,key1,key2);
927904

928905
(void)LockAcquire(&tag,ShareLock, false, false);
@@ -943,7 +920,6 @@ pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
943920
LOCKTAGtag;
944921
LockAcquireResultres;
945922

946-
PreventAdvisoryLocksInParallelMode();
947923
SET_LOCKTAG_INT32(tag,key1,key2);
948924

949925
res=LockAcquire(&tag,ExclusiveLock, true, true);
@@ -965,7 +941,6 @@ pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
965941
LOCKTAGtag;
966942
LockAcquireResultres;
967943

968-
PreventAdvisoryLocksInParallelMode();
969944
SET_LOCKTAG_INT32(tag,key1,key2);
970945

971946
res=LockAcquire(&tag,ExclusiveLock, false, true);
@@ -986,7 +961,6 @@ pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
986961
LOCKTAGtag;
987962
LockAcquireResultres;
988963

989-
PreventAdvisoryLocksInParallelMode();
990964
SET_LOCKTAG_INT32(tag,key1,key2);
991965

992966
res=LockAcquire(&tag,ShareLock, true, true);
@@ -1008,7 +982,6 @@ pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
1008982
LOCKTAGtag;
1009983
LockAcquireResultres;
1010984

1011-
PreventAdvisoryLocksInParallelMode();
1012985
SET_LOCKTAG_INT32(tag,key1,key2);
1013986

1014987
res=LockAcquire(&tag,ShareLock, false, true);
@@ -1029,7 +1002,6 @@ pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
10291002
LOCKTAGtag;
10301003
boolres;
10311004

1032-
PreventAdvisoryLocksInParallelMode();
10331005
SET_LOCKTAG_INT32(tag,key1,key2);
10341006

10351007
res=LockRelease(&tag,ExclusiveLock, true);
@@ -1050,7 +1022,6 @@ pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
10501022
LOCKTAGtag;
10511023
boolres;
10521024

1053-
PreventAdvisoryLocksInParallelMode();
10541025
SET_LOCKTAG_INT32(tag,key1,key2);
10551026

10561027
res=LockRelease(&tag,ShareLock, true);
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Parsed test spec with 4 sessions
2+
3+
starting permutation: d1a1 d2a2 e1l e2l d1a2 d2a1 d1c e1c d2c e2c
4+
step d1a1: SELECT lock_share(1,x) FROM bigt LIMIT 1;
5+
lock_share
6+
7+
1
8+
step d2a2: select lock_share(2,x) FROM bigt LIMIT 1;
9+
lock_share
10+
11+
1
12+
step e1l: SELECT lock_excl(1,x) FROM bigt LIMIT 1; <waiting ...>
13+
step e2l: SELECT lock_excl(2,x) FROM bigt LIMIT 1; <waiting ...>
14+
step d1a2: SET force_parallel_mode = on;
15+
SET parallel_setup_cost = 0;
16+
SET parallel_tuple_cost = 0;
17+
SET min_parallel_table_scan_size = 0;
18+
SET parallel_leader_participation = off;
19+
SET max_parallel_workers_per_gather = 4;
20+
SELECT sum(lock_share(2,x)) FROM bigt; <waiting ...>
21+
step d2a1: SET force_parallel_mode = on;
22+
SET parallel_setup_cost = 0;
23+
SET parallel_tuple_cost = 0;
24+
SET min_parallel_table_scan_size = 0;
25+
SET parallel_leader_participation = off;
26+
SET max_parallel_workers_per_gather = 4;
27+
SELECT sum(lock_share(1,x)) FROM bigt; <waiting ...>
28+
step d1a2: <... completed>
29+
sum
30+
31+
10000
32+
step d1c: COMMIT;
33+
step e1l: <... completed>
34+
lock_excl
35+
36+
1
37+
step d2a1: <... completed>
38+
sum
39+
40+
10000
41+
step e1c: COMMIT;
42+
step d2c: COMMIT;
43+
step e2l: <... completed>
44+
lock_excl
45+
46+
1
47+
step e2c: COMMIT;

‎src/test/isolation/isolation_schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ test: deadlock-simple
2121
test: deadlock-hard
2222
test: deadlock-soft
2323
test: deadlock-soft-2
24+
test: deadlock-parallel
2425
test: fk-contention
2526
test: fk-deadlock
2627
test: fk-deadlock2
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Test deadlock resolution with parallel process groups.
2+
3+
# It's fairly hard to get parallel worker processes to block on locks,
4+
# since generally they don't want any locks their leader didn't already
5+
# take. We cheat like mad here by making a function that takes a lock,
6+
# and is incorrectly marked parallel-safe so that it can execute in a worker.
7+
8+
# Note that we explicitly override any global settings of isolation level
9+
# or force_parallel_mode, to ensure we're testing what we intend to.
10+
11+
# Otherwise, this is morally equivalent to deadlock-soft.spec:
12+
# Four-process deadlock with two hard edges and two soft edges.
13+
# d2 waits for e1 (soft edge), e1 waits for d1 (hard edge),
14+
# d1 waits for e2 (soft edge), e2 waits for d2 (hard edge).
15+
# The deadlock detector resolves the deadlock by reversing the d1-e2 edge,
16+
# unblocking d1.
17+
18+
setup
19+
{
20+
createfunctionlock_share(int,int)returnsintlanguagesqlas
21+
'select pg_advisory_xact_lock_shared($1); select 1;'parallelsafe;
22+
23+
createfunctionlock_excl(int,int)returnsintlanguagesqlas
24+
'select pg_advisory_xact_lock($1); select 1;'parallelsafe;
25+
26+
createtablebigtasselectxfromgenerate_series(1,10000)x;
27+
analyzebigt;
28+
}
29+
30+
teardown
31+
{
32+
dropfunctionlock_share(int,int);
33+
dropfunctionlock_excl(int,int);
34+
droptablebigt;
35+
}
36+
37+
session"d1"
38+
setup{BEGINisolationlevelrepeatableread;
39+
SETforce_parallel_mode=off;
40+
SETdeadlock_timeout='10s';
41+
}
42+
# this lock will be taken in the leader, so it will persist:
43+
step"d1a1"{SELECTlock_share(1,x)FROMbigtLIMIT1; }
44+
# this causes all the parallel workers to take locks:
45+
step"d1a2"{SETforce_parallel_mode=on;
46+
SETparallel_setup_cost=0;
47+
SETparallel_tuple_cost=0;
48+
SETmin_parallel_table_scan_size=0;
49+
SETparallel_leader_participation=off;
50+
SETmax_parallel_workers_per_gather=4;
51+
SELECTsum(lock_share(2,x))FROMbigt; }
52+
step"d1c"{COMMIT; }
53+
54+
session"d2"
55+
setup{BEGINisolationlevelrepeatableread;
56+
SETforce_parallel_mode=off;
57+
SETdeadlock_timeout='10ms';
58+
}
59+
# this lock will be taken in the leader, so it will persist:
60+
step"d2a2"{selectlock_share(2,x)FROMbigtLIMIT1; }
61+
# this causes all the parallel workers to take locks:
62+
step"d2a1"{SETforce_parallel_mode=on;
63+
SETparallel_setup_cost=0;
64+
SETparallel_tuple_cost=0;
65+
SETmin_parallel_table_scan_size=0;
66+
SETparallel_leader_participation=off;
67+
SETmax_parallel_workers_per_gather=4;
68+
SELECTsum(lock_share(1,x))FROMbigt; }
69+
step"d2c"{COMMIT; }
70+
71+
session"e1"
72+
setup{BEGINisolationlevelrepeatableread;
73+
SETforce_parallel_mode=on;
74+
SETdeadlock_timeout='10s';
75+
}
76+
# this lock will be taken in a parallel worker, but we don't need it to persist
77+
step"e1l"{SELECTlock_excl(1,x)FROMbigtLIMIT1; }
78+
step"e1c"{COMMIT; }
79+
80+
session"e2"
81+
setup{BEGINisolationlevelrepeatableread;
82+
SETforce_parallel_mode=on;
83+
SETdeadlock_timeout='10s';
84+
}
85+
# this lock will be taken in a parallel worker, but we don't need it to persist
86+
step"e2l"{SELECTlock_excl(2,x)FROMbigtLIMIT1; }
87+
step"e2c"{COMMIT; }
88+
89+
permutation"d1a1""d2a2""e1l""e2l""d1a2""d2a1""d1c""e1c""d2c""e2c"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp