Skip to content

Commit d88976c

Browse files
committed
Use a separate memory context for GIN scan keys.
It was getting tedious to track and release all the different things that form a scan key. We were leaking at least the queryCategories array, and possibly more, on a rescan. That was visible if a GIN index was used in a nested loop join. This also protects from leaks in extractQuery method. No backpatching, given the lack of complaints from the field. Maybe later, after this has received more field testing.
1 parent 57fe246 commit d88976c

File tree

3 files changed

+29
-21
lines changed

3 files changed

+29
-21
lines changed

src/backend/access/gin/ginget.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ startScanKey(GinState *ginstate, GinScanOpaque so, GinScanKey key)
497497
}
498498
/* i is now the last required entry. */
499499

500-
MemoryContextSwitchTo(oldCtx);
500+
MemoryContextSwitchTo(so->keyCtx);
501501

502502
key->nrequired = i + 1;
503503
key->nadditional = key->nentries - key->nrequired;
@@ -515,11 +515,14 @@ startScanKey(GinState *ginstate, GinScanOpaque so, GinScanKey key)
515515
}
516516
else
517517
{
518+
MemoryContextSwitchTo(so->keyCtx);
519+
518520
key->nrequired = 1;
519521
key->nadditional = 0;
520522
key->requiredEntries = palloc(1 * sizeof(GinScanEntry));
521523
key->requiredEntries[0] = key->scanEntry[0];
522524
}
525+
MemoryContextSwitchTo(oldCtx);
523526
}
524527

525528
static void

src/backend/access/gin/ginscan.c

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ ginbeginscan(PG_FUNCTION_ARGS)
4444
ALLOCSET_DEFAULT_MINSIZE,
4545
ALLOCSET_DEFAULT_INITSIZE,
4646
ALLOCSET_DEFAULT_MAXSIZE);
47+
so->keyCtx = AllocSetContextCreate(CurrentMemoryContext,
48+
"Gin scan key context",
49+
ALLOCSET_DEFAULT_MINSIZE,
50+
ALLOCSET_DEFAULT_INITSIZE,
51+
ALLOCSET_DEFAULT_MAXSIZE);
4752
initGinState(&so->ginstate, scan->indexRelation);
4853

4954
scan->opaque = so;
@@ -227,6 +232,9 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
227232
}
228233
}
229234

235+
/*
236+
* Release current scan keys, if any.
237+
*/
230238
void
231239
ginFreeScanKeys(GinScanOpaque so)
232240
{
@@ -235,38 +243,22 @@ ginFreeScanKeys(GinScanOpaque so)
235243
if (so->keys == NULL)
236244
return;
237245

238-
for (i = 0; i < so->nkeys; i++)
239-
{
240-
GinScanKey key = so->keys + i;
241-
242-
pfree(key->scanEntry);
243-
pfree(key->entryRes);
244-
if (key->requiredEntries)
245-
pfree(key->requiredEntries);
246-
if (key->additionalEntries)
247-
pfree(key->additionalEntries);
248-
}
249-
250-
pfree(so->keys);
251-
so->keys = NULL;
252-
so->nkeys = 0;
253-
254246
for (i = 0; i < so->totalentries; i++)
255247
{
256248
GinScanEntry entry = so->entries[i];
257249

258250
if (entry->buffer != InvalidBuffer)
259251
ReleaseBuffer(entry->buffer);
260-
if (entry->list)
261-
pfree(entry->list);
262252
if (entry->matchIterator)
263253
tbm_end_iterate(entry->matchIterator);
264254
if (entry->matchBitmap)
265255
tbm_free(entry->matchBitmap);
266-
pfree(entry);
267256
}
268257

269-
pfree(so->entries);
258+
MemoryContextResetAndDeleteChildren(so->keyCtx);
259+
260+
so->keys = NULL;
261+
so->nkeys = 0;
270262
so->entries = NULL;
271263
so->totalentries = 0;
272264
}
@@ -278,6 +270,14 @@ ginNewScanKey(IndexScanDesc scan)
278270
GinScanOpaque so = (GinScanOpaque) scan->opaque;
279271
int i;
280272
bool hasNullQuery = false;
273+
MemoryContext oldCtx;
274+
275+
/*
276+
* Allocate all the scan key information in the key context. (If
277+
* extractQuery leaks anything there, it won't be reset until the end of
278+
* scan or rescan, but that's OK.)
279+
*/
280+
oldCtx = MemoryContextSwitchTo(so->keyCtx);
281281

282282
/* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
283283
so->keys = (GinScanKey)
@@ -412,6 +412,8 @@ ginNewScanKey(IndexScanDesc scan)
412412
RelationGetRelationName(scan->indexRelation))));
413413
}
414414

415+
MemoryContextSwitchTo(oldCtx);
416+
415417
pgstat_count_index_scan(scan->indexRelation);
416418
}
417419

@@ -445,6 +447,7 @@ ginendscan(PG_FUNCTION_ARGS)
445447
ginFreeScanKeys(so);
446448

447449
MemoryContextDelete(so->tempCtx);
450+
MemoryContextDelete(so->keyCtx);
448451

449452
pfree(so);
450453

src/include/access/gin_private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,8 @@ typedef struct GinScanOpaqueData
888888
uint32 totalentries;
889889
uint32 allocentries; /* allocated length of entries[] */
890890

891+
MemoryContext keyCtx; /* used to hold key and entry data */
892+
891893
bool isVoidRes; /* true if query is unsatisfiable */
892894
} GinScanOpaqueData;
893895

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