Commit 9eefba18 authored by Robert Haas's avatar Robert Haas

Delay lock acquisition for partitions until we route a tuple to them.

Instead of locking all partitions to which we might route a tuple at
executor startup, just lock them as we use them.  In some cases such a
partition might get locked at executor startup anyway because it
appears in the query's range table for some other reason, but in other
cases this is a bit savings.

This changes the order in which partitions are locked in some cases,
which might conceivably create deadlock hazards that don't exist
today, but per discussion, it seems like such cases should be rare
enough that we can neglect them in favor of improving performance.

David Rowley, reviewed and tested by Tomas Vondra, Sho Kato, John
Naylor, Tom Lane, and me.

Discussion: http://postgr.es/m/CAKJS1f-=FnMqmQP6qitkD+xEddxw22ySLP-0xFk3JAqUX2yfMw@mail.gmail.com
parent 7aa00d24
...@@ -191,9 +191,6 @@ static void find_matching_subplans_recurse(PartitionPruningData *prunedata, ...@@ -191,9 +191,6 @@ static void find_matching_subplans_recurse(PartitionPruningData *prunedata,
* tuple routing for partitioned tables, encapsulates it in * tuple routing for partitioned tables, encapsulates it in
* PartitionTupleRouting, and returns it. * PartitionTupleRouting, and returns it.
* *
* Note that all the relations in the partition tree are locked using the
* RowExclusiveLock mode upon return from this function.
*
* Callers must use the returned PartitionTupleRouting during calls to * Callers must use the returned PartitionTupleRouting during calls to
* ExecFindPartition(). The actual ResultRelInfo for a partition is only * ExecFindPartition(). The actual ResultRelInfo for a partition is only
* allocated when the partition is found for the first time. * allocated when the partition is found for the first time.
...@@ -208,9 +205,6 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel) ...@@ -208,9 +205,6 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
PartitionTupleRouting *proute; PartitionTupleRouting *proute;
ModifyTable *node = mtstate ? (ModifyTable *) mtstate->ps.plan : NULL; ModifyTable *node = mtstate ? (ModifyTable *) mtstate->ps.plan : NULL;
/* Lock all the partitions. */
(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
/* /*
* Here we attempt to expend as little effort as possible in setting up * Here we attempt to expend as little effort as possible in setting up
* the PartitionTupleRouting. Each partition's ResultRelInfo is built on * the PartitionTupleRouting. Each partition's ResultRelInfo is built on
...@@ -487,8 +481,9 @@ ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate, ...@@ -487,8 +481,9 @@ ExecHashSubPlanResultRelsByOid(ModifyTableState *mtstate,
/* /*
* ExecInitPartitionInfo * ExecInitPartitionInfo
* Initialize ResultRelInfo and other information for a partition * Lock the partition and initialize ResultRelInfo. Also setup other
* and store it in the next empty slot in the proute->partitions array. * information for the partition and store it in the next empty slot in
* the proute->partitions array.
* *
* Returns the ResultRelInfo * Returns the ResultRelInfo
*/ */
...@@ -510,11 +505,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, ...@@ -510,11 +505,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
oldcxt = MemoryContextSwitchTo(proute->memcxt); oldcxt = MemoryContextSwitchTo(proute->memcxt);
/* partrel = table_open(dispatch->partdesc->oids[partidx], RowExclusiveLock);
* We locked all the partitions in ExecSetupPartitionTupleRouting
* including the leaf partitions.
*/
partrel = table_open(dispatch->partdesc->oids[partidx], NoLock);
leaf_part_rri = makeNode(ResultRelInfo); leaf_part_rri = makeNode(ResultRelInfo);
InitResultRelInfo(leaf_part_rri, InitResultRelInfo(leaf_part_rri,
...@@ -964,11 +955,12 @@ ExecInitRoutingInfo(ModifyTableState *mtstate, ...@@ -964,11 +955,12 @@ ExecInitRoutingInfo(ModifyTableState *mtstate,
/* /*
* ExecInitPartitionDispatchInfo * ExecInitPartitionDispatchInfo
* Initialize PartitionDispatch for a partitioned table and store it in * Lock the partitioned table (if not locked already) and initialize
* the next available slot in the proute->partition_dispatch_info array. * PartitionDispatch for a partitioned table and store it in the next
* Also, record the index into this array in the parent_pd->indexes[] * available slot in the proute->partition_dispatch_info array. Also,
* array in the partidx element so that we can properly retrieve the * record the index into this array in the parent_pd->indexes[] array in
* newly created PartitionDispatch later. * the partidx element so that we can properly retrieve the newly created
* PartitionDispatch later.
*/ */
static PartitionDispatch static PartitionDispatch
ExecInitPartitionDispatchInfo(PartitionTupleRouting *proute, Oid partoid, ExecInitPartitionDispatchInfo(PartitionTupleRouting *proute, Oid partoid,
...@@ -982,8 +974,13 @@ ExecInitPartitionDispatchInfo(PartitionTupleRouting *proute, Oid partoid, ...@@ -982,8 +974,13 @@ ExecInitPartitionDispatchInfo(PartitionTupleRouting *proute, Oid partoid,
oldcxt = MemoryContextSwitchTo(proute->memcxt); oldcxt = MemoryContextSwitchTo(proute->memcxt);
/*
* Only sub-partitioned tables need to be locked here. The root
* partitioned table will already have been locked as it's referenced in
* the query's rtable.
*/
if (partoid != RelationGetRelid(proute->partition_root)) if (partoid != RelationGetRelid(proute->partition_root))
rel = table_open(partoid, NoLock); rel = table_open(partoid, RowExclusiveLock);
else else
rel = proute->partition_root; rel = proute->partition_root;
partdesc = RelationGetPartitionDesc(rel); partdesc = RelationGetPartitionDesc(rel);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment