8000 Repair memory leakage while ANALYZE-ing complex index expressions. · danielcode/postgres@1d5edff · GitHub
[go: up one dir, main page]

Skip to content

Commit 1d5edff

Browse files
committed
Repair memory leakage while ANALYZE-ing complex index expressions.
The general design of memory management in Postgres is that intermediate results computed by an expression are not freed until the end of the tuple cycle. For expression indexes, ANALYZE has to re-evaluate each expression for each of its sample rows, and it wasn't bothering to free intermediate results until the end of processing of that index. This could lead to very substantial leakage if the intermediate results were large, as in a recent example from Jakub Ouhrabka. Fix by doing ResetExprContext for each sample row. This necessitates adding a datumCopy step to ensure that the final expression value isn't recycled too. Some quick testing suggests that this change adds at worst about 10% to the time needed to analyze a table with an expression index; which is annoying, but seems a tolerable price to pay to avoid unexpected out-of-memory problems. Back-patch to all supported branches.
1 parent 17b38fa commit 1d5edff

File tree

1 file changed

+20
-3
lines changed

1 file changed

+20
-3
lines changed

src/backend/commands/analyze.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,12 @@ compute_index_stats(Relation onerel, double totalrows,
529529
{
530530
HeapTuple heapTuple = rows[rowno];
531531

532+
/*
533+
* Reset the per-tuple context each time, to reclaim any cruft
534+
* left behind by evaluating the predicate or index expressions.
535+
*/
536+
ResetExprContext(econtext);
537+
532538
/* Set up for predicate or expression evaluation */
533539
ExecStoreTuple(heapTuple, slot, InvalidBuffer, false);
534540

@@ -553,15 +559,26 @@ compute_index_stats(Relation onerel, double totalrows,
553559
isnull);
554560

555561
/*
556-
* Save just the columns we care about.
562+
* Save just the columns we care about. We copy the values
563+
* into ind_context from the estate's per-tuple context.
557564
*/
558565
for (i = 0; i < attr_cnt; i++)
559566
{
560567
VacAttrStats *stats = thisdata->vacattrstats[i];
561568
int attnum = stats->attr->attnum;
562569

563-
exprvals[tcnt] = values[attnum - 1];
564-
exprnulls[tcnt] = isnull[attnum - 1];
570+
if (isnull[attnum - 1])
571+
{
572+
exprvals[tcnt] = (Datum) 0;
573+
exprnulls[tcnt] = true;
574+
}
575+
else
576+
{
577+
exprvals[tcnt] = datumCopy(values[attnum - 1],
578+
stats->attrtype->typbyval,
579+
stats->attrtype->typlen);
580+
exprnulls[tcnt] = false;
581+
}
565582
tcnt++;
566583
}
567584
}

0 commit comments

Comments
 (0)
0