Skip to content

Commit 54cde0c

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 ecfe59e commit 54cde0c

File tree

3 files changed

+37
-31
lines changed

3 files changed

+37
-31
lines changed

src/backend/catalog/partition.c

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

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

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

10631066
/*

src/backend/executor/execMain.c

+7-3
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

+1-2
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ extern Expr *get_partition_qual_relid(Oid relid);
8888

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

0 commit comments

Comments
 (0)