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)