mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Fix memory leak when de-toasting compressed values in VACUUM FULL/CLUSTER
VACUUM FULL and CLUSTER can be used to enforce the use of the existing compression method of a toastable column if a value currently stored is compressed with a method that does not match the column's defined method. The code in charge of decompressing and recompressing toast values at rewrite left around the detoasted values, causing an accumulation of memory allocated in TopTransactionContext. When processing large relations, this could cause the system to run out of memory. The detoasted values are not needed once their tuple is rewritten, and this commit ensures that the necessary cleanup happens. Issue introduced by bbe0a81d. The comments of the area are reordered a bit while on it. Reported-by: Andres Freund Analyzed-by: Andres Freund Author: Michael Paquier Reviewed-by: Dilip Kumar Discussion: https://postgr.es/m/20210521211929.pcehg6f23icwstdb@alap3.anarazel.de
This commit is contained in:
parent
0c6b92d9c6
commit
fb0f5f0172
@ -2463,24 +2463,27 @@ reform_and_rewrite_tuple(HeapTuple tuple,
|
||||
TupleDesc newTupDesc = RelationGetDescr(NewHeap);
|
||||
HeapTuple copiedTuple;
|
||||
int i;
|
||||
bool values_free[MaxTupleAttributeNumber];
|
||||
|
||||
memset(values_free, 0, newTupDesc->natts * sizeof(bool));
|
||||
|
||||
heap_deform_tuple(tuple, oldTupDesc, values, isnull);
|
||||
|
||||
/* Be sure to null out any dropped columns */
|
||||
for (i = 0; i < newTupDesc->natts; i++)
|
||||
{
|
||||
/* Be sure to null out any dropped columns */
|
||||
if (TupleDescAttr(newTupDesc, i)->attisdropped)
|
||||
isnull[i] = true;
|
||||
|
||||
/*
|
||||
* Use this opportunity to force recompression of any data that's
|
||||
* compressed with some TOAST compression method other than the one
|
||||
* configured for the column. We don't actually need to perform the
|
||||
* compression here; we just need to decompress. That will trigger
|
||||
* recompression later on.
|
||||
*/
|
||||
else if (!isnull[i] && TupleDescAttr(newTupDesc, i)->attlen == -1)
|
||||
{
|
||||
/*
|
||||
* Use this opportunity to force recompression of any data that's
|
||||
* compressed with some TOAST compression method other than the
|
||||
* one configured for the column. We don't actually need to
|
||||
* perform the compression here; we just need to decompress. That
|
||||
* will trigger recompression later on.
|
||||
*/
|
||||
|
||||
struct varlena *new_value;
|
||||
ToastCompressionId cmid;
|
||||
char cmethod;
|
||||
@ -2507,7 +2510,10 @@ reform_and_rewrite_tuple(HeapTuple tuple,
|
||||
|
||||
/* if compression method doesn't match then detoast the value */
|
||||
if (TupleDescAttr(newTupDesc, i)->attcompression != cmethod)
|
||||
{
|
||||
values[i] = PointerGetDatum(detoast_attr(new_value));
|
||||
values_free[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2516,6 +2522,13 @@ reform_and_rewrite_tuple(HeapTuple tuple,
|
||||
/* The heap rewrite module does the rest */
|
||||
rewrite_heap_tuple(rwstate, tuple, copiedTuple);
|
||||
|
||||
/* Free any value detoasted previously */
|
||||
for (i = 0; i < newTupDesc->natts; i++)
|
||||
{
|
||||
if (values_free[i])
|
||||
pfree(DatumGetPointer(values[i]));
|
||||
}
|
||||
|
||||
heap_freetuple(copiedTuple);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user