Skip to content

Commit 1681a70

Browse files
committed
Fix memory leak in _gin_parallel_merge
To insert the merged GIN entries in _gin_parallel_merge, the leader calls ginEntryInsert(). This may allocate memory, e.g. for a new leaf tuple. This was allocated in the PortalContext, and kept until the end of the index build. For most GIN indexes the amount of leaked memory is negligible, but for custom opclasses with large keys it may cause OOMs. Fixed by calling ginEntryInsert() in a temporary memory context, reset after each insert. Other ginEntryInsert() callers do this too, except that the context is reset after batches of inserts. More frequent resets don't seem to hurt performance, it may even help it a bit. Report and fix by Vinod Sridharan. Author: Vinod Sridharan <vsridh90@gmail.com> Reviewed-by: Tomas Vondra <tomas@vondra.me> Discussion: https://postgr.es/m/CAFMdLD4p0VBd8JG=Nbi=BKv6rzFAiGJ_sXSFrw-2tNmNZFO5Kg@mail.gmail.com
1 parent e83a8ae commit 1681a70

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

src/backend/access/gin/gininsert.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1669,6 +1669,8 @@ _gin_parallel_merge(GinBuildState *state)
16691669
*/
16701670
while ((tup = tuplesort_getgintuple(state->bs_sortstate, &tuplen, true)) != NULL)
16711671
{
1672+
MemoryContext oldCtx;
1673+
16721674
CHECK_FOR_INTERRUPTS();
16731675

16741676
/*
@@ -1685,10 +1687,15 @@ _gin_parallel_merge(GinBuildState *state)
16851687
*/
16861688
AssertCheckItemPointers(buffer);
16871689

1690+
oldCtx = MemoryContextSwitchTo(state->tmpCtx);
1691+
16881692
ginEntryInsert(&state->ginstate,
16891693
buffer->attnum, buffer->key, buffer->category,
16901694
buffer->items, buffer->nitems, &state->buildStats);
16911695

1696+
MemoryContextSwitchTo(oldCtx);
1697+
MemoryContextReset(state->tmpCtx);
1698+
16921699
/* discard the existing data */
16931700
GinBufferReset(buffer);
16941701
}
@@ -1711,10 +1718,15 @@ _gin_parallel_merge(GinBuildState *state)
17111718
*/
17121719
AssertCheckItemPointers(buffer);
17131720

1721+
oldCtx = MemoryContextSwitchTo(state->tmpCtx);
1722+
17141723
ginEntryInsert(&state->ginstate,
17151724
buffer->attnum, buffer->key, buffer->category,
17161725
buffer->items, buffer->nfrozen, &state->buildStats);
17171726

1727+
MemoryContextSwitchTo(oldCtx);
1728+
MemoryContextReset(state->tmpCtx);
1729+
17181730
/* truncate the data we've just discarded */
17191731
GinBufferTrim(buffer);
17201732
}

0 commit comments

Comments
 (0)