]> granicus.if.org Git - postgresql/commitdiff
Fix per-tuple memory leak in partition tuple routing
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 1 Aug 2018 19:06:47 +0000 (15:06 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Wed, 1 Aug 2018 20:05:00 +0000 (16:05 -0400)
Some operations were being done in a longer-lived memory context,
causing intra-query leaks.  It's not noticeable unless you're doing a
large COPY, but if you are, it eats enough memory to cause a problem.

Co-authored-by: Kohei KaiGai <kaigai@heterodb.com>
Co-authored-by: Amit Langote <Langote_Amit_f8@lab.ntt.co.jp>
Co-authored-by: Álvaro Herrera <alvherre@alvh.no-ip.org>
Discussion: https://postgr.es/m/CAOP8fzYtVFWZADq4c=KoTAqgDrHWfng+AnEPEZccyxqxPVbbWQ@mail.gmail.com

src/backend/executor/execPartition.c

index 7a4665cc4ee39a7078ee41f95a9092f5abe89a04..b61c0fcc30019c33a98b620f497884a81557ad98 100644 (file)
@@ -193,9 +193,15 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
        Datum           values[PARTITION_MAX_KEYS];
        bool            isnull[PARTITION_MAX_KEYS];
        Relation        rel;
-       PartitionDispatch parent;
+       PartitionDispatch dispatch;
        ExprContext *ecxt = GetPerTupleExprContext(estate);
        TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
+       TupleTableSlot *myslot = NULL;
+       MemoryContext   oldcxt;
+       HeapTuple               tuple;
+
+       /* use per-tuple context here to avoid leaking memory */
+       oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
 
        /*
         * First check the root table's partition constraint, if any.  No point in
@@ -205,26 +211,24 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
                ExecPartitionCheck(resultRelInfo, slot, estate, true);
 
        /* start with the root partitioned table */
-       parent = pd[0];
+       tuple = ExecFetchSlotTuple(slot);
+       dispatch = pd[0];
        while (true)
        {
                PartitionDesc partdesc;
-               TupleTableSlot *myslot = parent->tupslot;
-               TupleConversionMap *map = parent->tupmap;
+               TupleConversionMap *map = dispatch->tupmap;
                int                     cur_index = -1;
 
-               rel = parent->reldesc;
+               rel = dispatch->reldesc;
                partdesc = RelationGetPartitionDesc(rel);
 
                /*
-                * Convert the tuple to this parent's layout so that we can do certain
-                * things we do below.
+                * Convert the tuple to this parent's layout, if different from the
+                * current relation.
                 */
+               myslot = dispatch->tupslot;
                if (myslot != NULL && map != NULL)
                {
-                       HeapTuple       tuple = ExecFetchSlotTuple(slot);
-
-                       ExecClearTuple(myslot);
                        tuple = do_convert_tuple(tuple, map);
                        ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
                        slot = myslot;
@@ -239,7 +243,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
                 * So update ecxt_scantuple accordingly.
                 */
                ecxt->ecxt_scantuple = slot;
-               FormPartitionKeyDatum(parent, slot, estate, values, isnull);
+               FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
 
                /*
                 * Nothing for get_partition_for_tuple() to do if there are no
@@ -263,15 +267,33 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
                        result = -1;
                        break;
                }
-               else if (parent->indexes[cur_index] >= 0)
+               else if (dispatch->indexes[cur_index] >= 0)
                {
-                       result = parent->indexes[cur_index];
+                       result = dispatch->indexes[cur_index];
+                       /* success! */
                        break;
                }
                else
-                       parent = pd[-parent->indexes[cur_index]];
+               {
+                       /* move down one level */
+                       dispatch = pd[-dispatch->indexes[cur_index]];
+
+                       /*
+                        * Release the dedicated slot, if it was used.  Create a copy of
+                        * the tuple first, for the next iteration.
+                        */
+                       if (slot == myslot)
+                       {
+                               tuple = ExecCopySlotTuple(myslot);
+                               ExecClearTuple(myslot);
+                       }
+               }
        }
 
+       /* Release the tuple in the lowest parent's dedicated slot. */
+       if (slot == myslot)
+               ExecClearTuple(myslot);
+
        /* A partition was not found. */
        if (result < 0)
        {
@@ -287,7 +309,9 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
                                 val_desc ? errdetail("Partition key of the failing row contains %s.", val_desc) : 0));
        }
 
+       MemoryContextSwitchTo(oldcxt);
        ecxt->ecxt_scantuple = ecxt_scantuple_old;
+
        return result;
 }