Skip to content

Commit 1c9bb02

Browse files
alvherrekaigaiAmit Langote
committed
Fix per-tuple memory leak in partition tuple routing
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
1 parent e3f99e0 commit 1c9bb02

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

src/backend/executor/execPartition.c

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,15 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
193193
Datum values[PARTITION_MAX_KEYS];
194194
bool isnull[PARTITION_MAX_KEYS];
195195
Relation rel;
196-
PartitionDispatch parent;
196+
PartitionDispatch dispatch;
197197
ExprContext *ecxt = GetPerTupleExprContext(estate);
198198
TupleTableSlot *ecxt_scantuple_old = ecxt->ecxt_scantuple;
199+
TupleTableSlot *myslot = NULL;
200+
MemoryContext oldcxt;
201+
HeapTuple tuple;
202+
203+
/* use per-tuple context here to avoid leaking memory */
204+
oldcxt = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
199205

200206
/*
201207
* First check the root table's partition constraint, if any. No point in
@@ -205,24 +211,23 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
205211
ExecPartitionCheck(resultRelInfo, slot, estate, true);
206212

207213
/* start with the root partitioned table */
208-
parent = pd[0];
214+
tuple = ExecFetchSlotTuple(slot);
215+
dispatch = pd[0];
209216
while (true)
210217
{
211-
TupleTableSlot *myslot = parent->tupslot;
212-
TupleConversionMap *map = parent->tupmap;
218+
TupleTableSlot *myslot = dispatch->tupslot;
219+
TupleConversionMap *map = dispatch->tupmap;
213220
int cur_index = -1;
214221

215-
rel = parent->reldesc;
222+
rel = dispatch->reldesc;
216223

217224
/*
218-
* Convert the tuple to this parent's layout so that we can do certain
219-
* things we do below.
225+
* Convert the tuple to this parent's layout, if different from the
226+
* current relation.
220227
*/
228+
myslot = dispatch->tupslot;
221229
if (myslot != NULL && map != NULL)
222230
{
223-
HeapTuple tuple = ExecFetchSlotTuple(slot);
224-
225-
ExecClearTuple(myslot);
226231
tuple = do_convert_tuple(tuple, map);
227232
ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
228233
slot = myslot;
@@ -237,19 +242,19 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
237242
* So update ecxt_scantuple accordingly.
238243
*/
239244
ecxt->ecxt_scantuple = slot;
240-
FormPartitionKeyDatum(parent, slot, estate, values, isnull);
245+
FormPartitionKeyDatum(dispatch, slot, estate, values, isnull);
241246

242247
/*
243248
* Nothing for get_partition_for_tuple() to do if there are no
244249
* partitions to begin with.
245250
*/
246-
if (parent->partdesc->nparts == 0)
251+
if (dispatch->partdesc->nparts == 0)
247252
{
248253
result = -1;
249254
break;
250255
}
251256

252-
cur_index = get_partition_for_tuple(parent, values, isnull);
257+
cur_index = get_partition_for_tuple(dispatch, values, isnull);
253258

254259
/*
255260
* cur_index < 0 means we failed to find a partition of this parent.
@@ -261,15 +266,33 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
261266
result = -1;
262267
break;
263268
}
264-
else if (parent->indexes[cur_index] >= 0)
269+
else if (dispatch->indexes[cur_index] >= 0)
265270
{
266-
result = parent->indexes[cur_index];
271+
result = dispatch->indexes[cur_index];
272+
/* success! */
267273
break;
268274
}
269275
else
270-
parent = pd[-parent->indexes[cur_index]];
276+
{
277+
/* move down one level */
278+
dispatch = pd[-dispatch->indexes[cur_index]];
279+
280+
/*
281+
* Release the dedicated slot, if it was used. Create a copy of
282+
* the tuple first, for the next iteration.
283+
*/
284+
if (slot == myslot)
285+
{
286+
tuple = ExecCopySlotTuple(myslot);
287+
ExecClearTuple(myslot);
288+
}
289+
}
271290
}
272291

292+
/* Release the tuple in the lowest parent's dedicated slot. */
293+
if (slot == myslot)
294+
ExecClearTuple(myslot);
295+
273296
/* A partition was not found. */
274297
if (result < 0)
275298
{
@@ -285,7 +308,9 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
285308
val_desc ? errdetail("Partition key of the failing row contains %s.", val_desc) : 0));
286309
}
287310

311+
MemoryContextSwitchTo(oldcxt);
288312
ecxt->ecxt_scantuple = ecxt_scantuple_old;
313+
289314
return result;
290315
}
291316

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy