Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7c0ca29

Browse files
committed
Don't lock tables in RelationGetPartitionDispatchInfo.
Instead, lock them in the caller using find_all_inheritors so that they get locked in the standard order, minimizing deadlock risks. Also in RelationGetPartitionDispatchInfo, avoid opening tables which are not partitioned; there's no need. Amit Langote, reviewed by Ashutosh Bapat and Amit Khandekar Discussion: http://postgr.es/m/[email protected]
1 parent de1ca69 commit 7c0ca29

File tree

3 files changed

+37
-31
lines changed

3 files changed

+37
-31
lines changed

src/backend/catalog/partition.c

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,12 +1000,16 @@ get_partition_qual_relid(Oid relid)
10001000
* RelationGetPartitionDispatchInfo
10011001
* Returns information necessary to route tuples down a partition tree
10021002
*
1003-
* All the partitions will be locked with lockmode, unless it is NoLock.
1004-
* A list of the OIDs of all the leaf partitions of rel is returned in
1005-
* *leaf_part_oids.
1003+
* The number of elements in the returned array (that is, the number of
1004+
* PartitionDispatch objects for the partitioned tables in the partition tree)
1005+
* is returned in *num_parted and a list of the OIDs of all the leaf
1006+
* partitions of rel is returned in *leaf_part_oids.
1007+
*
1008+
* All the relations in the partition tree (including 'rel') must have been
1009+
* locked (using at least the AccessShareLock) by the caller.
10061010
*/
10071011
PartitionDispatch *
1008-
RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
1012+
RelationGetPartitionDispatchInfo(Relation rel,
10091013
int *num_parted, List **leaf_part_oids)
10101014
{
10111015
PartitionDispatchData **pd;
@@ -1020,14 +1024,18 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
10201024
offset;
10211025

10221026
/*
1023-
* Lock partitions and make a list of the partitioned ones to prepare
1024-
* their PartitionDispatch objects below.
1027+
* We rely on the relcache to traverse the partition tree to build both
1028+
* the leaf partition OIDs list and the array of PartitionDispatch objects
1029+
* for the partitioned tables in the tree. That means every partitioned
1030+
* table in the tree must be locked, which is fine since we require the
1031+
* caller to lock all the partitions anyway.
10251032
*
1026-
* Cannot use find_all_inheritors() here, because then the order of OIDs
1027-
* in parted_rels list would be unknown, which does not help, because we
1028-
* assign indexes within individual PartitionDispatch in an order that is
1029-
* predetermined (determined by the order of OIDs in individual partition
1030-
* descriptors).
1033+
* For every partitioned table in the tree, starting with the root
1034+
* partitioned table, add its relcache entry to parted_rels, while also
1035+
* queuing its partitions (in the order in which they appear in the
1036+
* partition descriptor) to be looked at later in the same loop. This is
1037+
* a bit tricky but works because the foreach() macro doesn't fetch the
1038+
* next list element until the bottom of the loop.
10311039
*/
10321040
*num_parted = 1;
10331041
parted_rels = list_make1(rel);
@@ -1036,29 +1044,24 @@ RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
10361044
APPEND_REL_PARTITION_OIDS(rel, all_parts, all_parents);
10371045
forboth(lc1, all_parts, lc2, all_parents)
10381046
{
1039-
Relation partrel = heap_open(lfirst_oid(lc1), lockmode);
1047+
Oid partrelid = lfirst_oid(lc1);
10401048
Relation parent = lfirst(lc2);
1041-
PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
10421049

1043-
/*
1044-
* If this partition is a partitioned table, add its children to the
1045-
* end of the list, so that they are processed as well.
1046-
*/
1047-
if (partdesc)
1050+
if (get_rel_relkind(partrelid) == RELKIND_PARTITIONED_TABLE)
10481051
{
1052+
/*
1053+
* Already locked by the caller. Note that it is the
1054+
* responsibility of the caller to close the below relcache entry,
1055+
* once done using the information being collected here (for
1056+
* example, in ExecEndModifyTable).
1057+
*/
1058+
Relation partrel = heap_open(partrelid, NoLock);
1059+
10491060
(*num_parted)++;
10501061
parted_rels = lappend(parted_rels, partrel);
10511062
parted_rel_parents = lappend(parted_rel_parents, parent);
10521063
APPEND_REL_PARTITION_OIDS(partrel, all_parts, all_parents);
10531064
}
1054-
else
1055-
heap_close(partrel, NoLock);
1056-
1057-
/*
1058-
* We keep the partitioned ones open until we're done using the
1059-
* information being collected here (for example, see
1060-
* ExecEndModifyTable).
1061-
*/
10621065
}
10631066

10641067
/*

src/backend/executor/execMain.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "access/xact.h"
4444
#include "catalog/namespace.h"
4545
#include "catalog/partition.h"
46+
#include "catalog/pg_inherits_fn.h"
4647
#include "catalog/pg_publication.h"
4748
#include "commands/matview.h"
4849
#include "commands/trigger.h"
@@ -3249,9 +3250,12 @@ ExecSetupPartitionTupleRouting(Relation rel,
32493250
int i;
32503251
ResultRelInfo *leaf_part_rri;
32513252

3252-
/* Get the tuple-routing information and lock partitions */
3253-
*pd = RelationGetPartitionDispatchInfo(rel, RowExclusiveLock, num_parted,
3254-
&leaf_parts);
3253+
/*
3254+
* Get the information about the partition tree after locking all the
3255+
* partitions.
3256+
*/
3257+
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
3258+
*pd = RelationGetPartitionDispatchInfo(rel, num_parted, &leaf_parts);
32553259
*num_partitions = list_length(leaf_parts);
32563260
*partitions = (ResultRelInfo *) palloc(*num_partitions *
32573261
sizeof(ResultRelInfo));

src/include/catalog/partition.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ extern Expr *get_partition_qual_relid(Oid relid);
8787

8888
/* For tuple routing */
8989
extern PartitionDispatch *RelationGetPartitionDispatchInfo(Relation rel,
90-
int lockmode, int *num_parted,
91-
List **leaf_part_oids);
90+
int *num_parted, List **leaf_part_oids);
9291
extern void FormPartitionKeyDatum(PartitionDispatch pd,
9392
TupleTableSlot *slot,
9493
EState *estate,

0 commit comments

Comments
 (0)