mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-03-07 19:47:50 +08:00
Fix query-duration memory leak with GIN rescans.
The requiredEntries / additionalEntries arrays were not freed in freeScanKeys() like other per-key stuff. It's not obvious, but startScanKey() was only ever called after the keys have been initialized with ginNewScanKey(). That's why it doesn't need to worry about freeing existing arrays. The ginIsNewKey() test in gingetbitmap was never true, because ginrescan free's the existing keys, and it's not OK to call gingetbitmap twice in a row without calling ginrescan in between. To make that clear, remove the unnecessary ginIsNewKey(). And just to be extra sure that nothing funny happens if there is an existing key after all, call freeScanKeys() to free it if it exists. This makes the code more straightforward. (I'm seeing other similar leaks in testing a query that rescans an GIN index scan, but that's a different issue. This just fixes the obvious leak with those two arrays.) Backpatch to 9.4, where GIN fast scan was added.
This commit is contained in:
parent
cff1bd2a3c
commit
68fa75f318
@ -560,6 +560,10 @@ startScan(IndexScanDesc scan)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we have the estimates for the entry frequencies, finish
|
||||
* initializing the scan keys.
|
||||
*/
|
||||
for (i = 0; i < so->nkeys; i++)
|
||||
startScanKey(ginstate, so, so->keys + i);
|
||||
}
|
||||
@ -1763,7 +1767,6 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
|
||||
}
|
||||
|
||||
|
||||
#define GinIsNewKey(s) ( ((GinScanOpaque) scan->opaque)->keys == NULL )
|
||||
#define GinIsVoidRes(s) ( ((GinScanOpaque) scan->opaque)->isVoidRes )
|
||||
|
||||
Datum
|
||||
@ -1771,6 +1774,7 @@ gingetbitmap(PG_FUNCTION_ARGS)
|
||||
{
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
TIDBitmap *tbm = (TIDBitmap *) PG_GETARG_POINTER(1);
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
int64 ntids;
|
||||
ItemPointerData iptr;
|
||||
bool recheck;
|
||||
@ -1778,8 +1782,8 @@ gingetbitmap(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* Set up the scan keys, and check for unsatisfiable query.
|
||||
*/
|
||||
if (GinIsNewKey(scan))
|
||||
ginNewScanKey(scan);
|
||||
ginFreeScanKeys(so); /* there should be no keys yet, but just to be sure */
|
||||
ginNewScanKey(scan);
|
||||
|
||||
if (GinIsVoidRes(scan))
|
||||
PG_RETURN_INT64(0);
|
||||
|
@ -163,6 +163,10 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
|
||||
key->curItemMatches = false;
|
||||
key->recheckCurItem = false;
|
||||
key->isFinished = false;
|
||||
key->nrequired = 0;
|
||||
key->nadditional = 0;
|
||||
key->requiredEntries = NULL;
|
||||
key->additionalEntries = NULL;
|
||||
|
||||
ginInitConsistentFunction(ginstate, key);
|
||||
|
||||
@ -223,8 +227,8 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
freeScanKeys(GinScanOpaque so)
|
||||
void
|
||||
ginFreeScanKeys(GinScanOpaque so)
|
||||
{
|
||||
uint32 i;
|
||||
|
||||
@ -237,6 +241,10 @@ freeScanKeys(GinScanOpaque so)
|
||||
|
||||
pfree(key->scanEntry);
|
||||
pfree(key->entryRes);
|
||||
if (key->requiredEntries)
|
||||
pfree(key->requiredEntries);
|
||||
if (key->additionalEntries)
|
||||
pfree(key->additionalEntries);
|
||||
}
|
||||
|
||||
pfree(so->keys);
|
||||
@ -416,7 +424,7 @@ ginrescan(PG_FUNCTION_ARGS)
|
||||
/* remaining arguments are ignored */
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
freeScanKeys(so);
|
||||
ginFreeScanKeys(so);
|
||||
|
||||
if (scankey && scan->numberOfKeys > 0)
|
||||
{
|
||||
@ -434,7 +442,7 @@ ginendscan(PG_FUNCTION_ARGS)
|
||||
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
|
||||
GinScanOpaque so = (GinScanOpaque) scan->opaque;
|
||||
|
||||
freeScanKeys(so);
|
||||
ginFreeScanKeys(so);
|
||||
|
||||
MemoryContextDelete(so->tempCtx);
|
||||
|
||||
|
@ -899,6 +899,7 @@ extern Datum ginrescan(PG_FUNCTION_ARGS);
|
||||
extern Datum ginmarkpos(PG_FUNCTION_ARGS);
|
||||
extern Datum ginrestrpos(PG_FUNCTION_ARGS);
|
||||
extern void ginNewScanKey(IndexScanDesc scan);
|
||||
extern void ginFreeScanKeys(GinScanOpaque so);
|
||||
|
||||
/* ginget.c */
|
||||
extern Datum gingetbitmap(PG_FUNCTION_ARGS);
|
||||
|
Loading…
Reference in New Issue
Block a user