On 2018/07/28 10:54, David Rowley wrote:
> On 27 July 2018 at 19:11, Amit Langote <langote_amit...@lab.ntt.co.jp> wrote:
>> I've attached a delta patch to make the above changes.  I'm leaving the
>> hash table rename up to you though.
> 
> Thanks for the delta patch. I took all of it, just rewrote a comment slightly.
> 
> I also renamed the hash table to your suggestion and changed a few more 
> things.
> 
> Attached a delta based on v2 and the full v3 patch.
> 
> This includes another small change to make
> PartitionDispatchData->indexes an array that's allocated in the same
> memory as the PartitionDispatchData. This will save a palloc() call
> and also should be a bit more cache friendly.
> 
> This also required a rebase on master again due to 3e32109049.

Thanks for the updated patch.

I couldn't find much to complain about in the latest v3, except I noticed
a few instances of the word "setup" where I think what's really meant is
"set up".

+     * must be setup, but any sub-partitioned tables can be setup lazily as

+                 * A ResultRelInfo has not been setup for this partition yet,


By the way, when going over the updated code, I noticed that the code
around child_parent_tupconv_maps could use some refactoring too.
Especially, I noticed that ExecSetupChildParentMapForLeaf() allocates
child-to-parent map array needed for transition tuple capture even if not
needed by any of the leaf partitions.  I'm attaching here a patch that
applies on top of your v3 to show what I'm thinking we could do.

Thanks,
Amit
From 6ce1654aa929c7f8112c430914af7f464474ed31 Mon Sep 17 00:00:00 2001
From: amit <amitlangot...@gmail.com>
Date: Mon, 30 Jul 2018 14:05:17 +0900
Subject: [PATCH 2/2] Some refactoring around child_parent_tupconv_maps

Just like parent_child_tupconv_maps, we should allocate it only if
needed.  Also, if none of the partitions ended up needing a map, we
should not have allocated the child_parent_tupconv_maps array, only
the child_parent_map_not_required one.  So, get rid of
ExecSetupChildParentMapForLeaf(), which currently does initial,
possibly useless, allocation of both of the above mentioned arrays.
Instead, have TupConvMapForLeaf() allocate the needed array, just
like ExecInitRoutingInfo does, when it needs to store a
parent-to-child map.

Finally, rename the function TupConvMapForLeaf to
LeafToParentTupConvMapForTC for clarity; TC stands for "Transition
Capture".
---
 src/backend/commands/copy.c            |  19 +-----
 src/backend/executor/execPartition.c   | 102 ++++++++++++++++-----------------
 src/backend/executor/nodeModifyTable.c |   4 +-
 src/include/executor/execPartition.h   |  12 ++--
 4 files changed, 59 insertions(+), 78 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6fc1e2b41c..6d0e9229e0 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -2503,22 +2503,9 @@ CopyFrom(CopyState cstate)
         * CopyFrom tuple routing.
         */
        if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
-       {
-               PartitionTupleRouting *proute;
-
-               proute = cstate->partition_tuple_routing =
+               cstate->partition_tuple_routing =
                        ExecSetupPartitionTupleRouting(NULL, cstate->rel);
 
-               /*
-                * If we are capturing transition tuples, they may need to be
-                * converted from partition format back to partitioned table 
format
-                * (this is only ever necessary if a BEFORE trigger modifies the
-                * tuple).
-                */
-               if (cstate->transition_capture != NULL)
-                       ExecSetupChildParentMapForLeaf(proute);
-       }
-
        /*
         * It's more efficient to prepare a bunch of tuples for insertion, and
         * insert them in one heap_multi_insert() call, than call heap_insert()
@@ -2666,8 +2653,8 @@ CopyFrom(CopyState cstate)
                                         */
                                        
cstate->transition_capture->tcs_original_insert_tuple = NULL;
                                        cstate->transition_capture->tcs_map =
-                                               TupConvMapForLeaf(proute, 
saved_resultRelInfo,
-                                                                               
  leaf_part_index);
+                                               
LeafToParentTupConvMapForTC(proute, saved_resultRelInfo,
+                                                                               
                        leaf_part_index);
                                }
                                else
                                {
diff --git a/src/backend/executor/execPartition.c 
b/src/backend/executor/execPartition.c
index 2a18a30b3e..d183e8b758 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -400,7 +400,7 @@ ExecExpandRoutingArrays(PartitionTupleRouting *proute)
                           sizeof(TupleConversionMap *) * (new_size - 
old_size));
        }
 
-       if (proute->child_parent_map_not_required != NULL)
+       if (proute->child_parent_tupconv_maps != NULL)
        {
                proute->child_parent_tupconv_maps = (TupleConversionMap **)
                        repalloc(proute->child_parent_tupconv_maps,
@@ -940,73 +940,67 @@ ExecInitPartitionDispatchInfo(PartitionTupleRouting 
*proute, Oid partoid,
 }
 
 /*
- * ExecSetupChildParentMapForLeaf -- Initialize the per-leaf-partition
- * child-to-root tuple conversion map array.
- *
- * This map is required for capturing transition tuples when the target table
- * is a partitioned table. For a tuple that is routed by an INSERT or UPDATE,
- * we need to convert it from the leaf partition to the target table
- * descriptor.
- */
-void
-ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute)
-{
-       int                     size;
-
-       Assert(proute != NULL);
-
-       size = proute->partitions_allocsize;
-
-       /*
-        * These array elements get filled up with maps on an on-demand basis.
-        * Initially just set all of them to NULL.
-        */
-       proute->child_parent_tupconv_maps =
-               (TupleConversionMap **) palloc0(sizeof(TupleConversionMap *) * 
size);
-
-       /* Same is the case for this array. All the values are set to false */
-       proute->child_parent_map_not_required = (bool *) palloc0(sizeof(bool) *
-                                                                               
                                         size);
-}
-
-/*
- * TupConvMapForLeaf -- Get the tuple conversion map for a given leaf partition
- * index.
+ * LeafToParentTupConvMapForTC -- Get the tuple conversion map to convert
+ * tuples of a leaf partition to the root parent's rowtype for storing in the
+ * transition capture tuplestore
  */
 TupleConversionMap *
-TupConvMapForLeaf(PartitionTupleRouting *proute,
-                                 ResultRelInfo *rootRelInfo, int leaf_index)
+LeafToParentTupConvMapForTC(PartitionTupleRouting *proute,
+                                                       ResultRelInfo 
*rootRelInfo,
+                                                       int leaf_index)
 {
-       TupleConversionMap **map;
+       TupleConversionMap *map;
        TupleDesc       tupdesc;
 
-       /* If nobody else set up the per-leaf maps array, do so ourselves. */
-       if (proute->child_parent_tupconv_maps == NULL)
-               ExecSetupChildParentMapForLeaf(proute);
+       Assert(leaf_index < proute->partitions_allocsize);
 
-       /* If it's already known that we don't need a map, return NULL. */
-       else if (proute->child_parent_map_not_required[leaf_index])
+       /* Did we already find out that we don't need a map for this partition? 
*/
+       if (proute->child_parent_map_not_required &&
+               proute->child_parent_map_not_required[leaf_index])
                return NULL;
 
-       /* If we've already got a map, return it. */
-       map = &proute->child_parent_tupconv_maps[leaf_index];
-       if (*map != NULL)
-               return *map;
-
-       /* No map yet; try to create one. */
        tupdesc = 
RelationGetDescr(proute->partitions[leaf_index]->ri_RelationDesc);
-       *map =
+       map =
                convert_tuples_by_name(tupdesc,
                                                           
RelationGetDescr(rootRelInfo->ri_RelationDesc),
                                                           gettext_noop("could 
not convert row type"));
 
-       /*
-        * If it turns out no map is needed, remember that so we don't try 
making
-        * one again next time.
-        */
-       proute->child_parent_map_not_required[leaf_index] = (*map == NULL);
+       if (map)
+       {
+               /* If the per-leaf maps array has not been set up, do so 
ourselves. */
+               if (proute->child_parent_tupconv_maps == NULL)
+               {
+                       int             size = proute->partitions_allocsize;
 
-       return *map;
+                       /*
+                        * These array elements get filled up with maps on an 
on-demand
+                        * basis.  Initially just set all of them to NULL.
+                        */
+                       proute->child_parent_tupconv_maps =
+                               (TupleConversionMap **) 
palloc0(sizeof(TupleConversionMap *) *
+                                                                               
                size);
+               }
+
+               proute->child_parent_tupconv_maps[leaf_index] = map;
+       }
+       else
+       {
+               if (proute->child_parent_map_not_required == NULL)
+               {
+                       int             size = proute->partitions_allocsize;
+
+                       /*
+                        * Values for other partitions will be filled whenever 
they're
+                        * selected by routing.
+                        */
+                       proute->child_parent_map_not_required =
+                               (bool *) palloc0(sizeof(bool) * size);
+               }
+
+               proute->child_parent_map_not_required[leaf_index] = true;
+       }
+
+       return map;
 }
 
 /*
diff --git a/src/backend/executor/nodeModifyTable.c 
b/src/backend/executor/nodeModifyTable.c
index 4f7cea7668..7d658ddad2 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -1758,7 +1758,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
                         */
                        
mtstate->mt_transition_capture->tcs_original_insert_tuple = NULL;
                        mtstate->mt_transition_capture->tcs_map =
-                               TupConvMapForLeaf(proute, targetRelInfo, 
partidx);
+                               LeafToParentTupConvMapForTC(proute, 
targetRelInfo, partidx);
                }
                else
                {
@@ -1773,7 +1773,7 @@ ExecPrepareTupleRouting(ModifyTableState *mtstate,
        if (mtstate->mt_oc_transition_capture != NULL)
        {
                mtstate->mt_oc_transition_capture->tcs_map =
-                       TupConvMapForLeaf(proute, targetRelInfo, partidx);
+                       LeafToParentTupConvMapForTC(proute, targetRelInfo, 
partidx);
        }
 
        /*
diff --git a/src/include/executor/execPartition.h 
b/src/include/executor/execPartition.h
index d921ab6ca0..487a131343 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -125,9 +125,9 @@ typedef struct PartitionDispatchData *PartitionDispatch;
  *                                                     the same size as 
'partitions'.
  *
  * child_parent_map_not_required       Stores if we don't need a conversion
- *                                                     map for a partition so 
that TupConvMapForLeaf
- *                                                     can return without 
having to re-check if it needs
- *                                                     to build a map.
+ *                                                     map for a partition so 
that
+ *                                                     
LeafToParentTupConvMapForTC can return without
+ *                                                     having to re-check if 
it needs to build a map.
  *
  * subplan_resultrel_hash      Hash table to store subplan index by Oid.
  *
@@ -244,9 +244,9 @@ extern void ExecInitRoutingInfo(ModifyTableState *mtstate,
                                        PartitionTupleRouting *proute,
                                        ResultRelInfo *partRelInfo,
                                        int partidx);
-extern void ExecSetupChildParentMapForLeaf(PartitionTupleRouting *proute);
-extern TupleConversionMap *TupConvMapForLeaf(PartitionTupleRouting *proute,
-                                 ResultRelInfo *rootRelInfo, int leaf_index);
+extern TupleConversionMap *LeafToParentTupConvMapForTC(PartitionTupleRouting 
*proute,
+                                                       ResultRelInfo 
*rootRelInfo,
+                                                       int leaf_index);
 extern HeapTuple ConvertPartitionTupleSlot(TupleConversionMap *map,
                                                  HeapTuple tuple,
                                                  TupleTableSlot *new_slot,
-- 
2.11.0

Reply via email to