Skip to content

Commit e087b5b

Browse files
committed
Fix per-relation memory leakage in autovacuum.
PgStat_StatTabEntry and AutoVacOpts structs were leaked until the end of the autovacuum worker's run, which is bad news if there are a lot of relations in the database. Note: pfree'ing the PgStat_StatTabEntry structs here seems a bit risky, because pgstat_fetch_stat_tabentry_ext does not guarantee anything about whether its result is long-lived. It appears okay so long as autovacuum forces PGSTAT_FETCH_CONSISTENCY_NONE, but I think that API could use a re-think. Also ensure that the VacuumRelation structure passed to vacuum() is in recoverable storage. Back-patch to v15 where we started to manage table statistics this way. (The AutoVacOpts leakage is probably older, but I'm not excited enough to worry about just that part.) Author: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/285483.1746756246@sss.pgh.pa.us Backpatch-through: 15
1 parent ee58de1 commit e087b5b

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

src/backend/postmaster/autovacuum.c

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,6 +2211,12 @@ do_autovacuum(void)
22112211
}
22122212
}
22132213
}
2214+
2215+
/* Release stuff to avoid per-relation leakage */
2216+
if (relopts)
2217+
pfree(relopts);
2218+
if (tabentry)
2219+
pfree(tabentry);
22142220
}
22152221

22162222
table_endscan(relScan);
@@ -2227,7 +2233,8 @@ do_autovacuum(void)
22272233
Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
22282234
PgStat_StatTabEntry *tabentry;
22292235
Oid relid;
2230-
AutoVacOpts *relopts = NULL;
2236+
AutoVacOpts *relopts;
2237+
bool free_relopts = false;
22312238
bool dovacuum;
22322239
bool doanalyze;
22332240
bool wraparound;
@@ -2245,7 +2252,9 @@ do_autovacuum(void)
22452252
* main rel
22462253
*/
22472254
relopts = extract_autovac_opts(tuple, pg_class_desc);
2248-
if (relopts == NULL)
2255+
if (relopts)
2256+
free_relopts = true;
2257+
else
22492258
{
22502259
av_relation *hentry;
22512260
bool found;
@@ -2266,6 +2275,12 @@ do_autovacuum(void)
22662275
/* ignore analyze for toast tables */
22672276
if (dovacuum)
22682277
table_oids = lappend_oid(table_oids, relid);
2278+
2279+
/* Release stuff to avoid leakage */
2280+
if (free_relopts)
2281+
pfree(relopts);
2282+
if (tabentry)
2283+
pfree(tabentry);
22692284
}
22702285

22712286
table_endscan(relScan);
@@ -2637,6 +2652,8 @@ do_autovacuum(void)
26372652
pg_atomic_test_set_flag(&MyWorkerInfo->wi_dobalance);
26382653
}
26392654

2655+
list_free(table_oids);
2656+
26402657
/*
26412658
* Perform additional work items, as requested by backends.
26422659
*/
@@ -2818,8 +2835,8 @@ perform_work_item(AutoVacuumWorkItem *workitem)
28182835
/*
28192836
* extract_autovac_opts
28202837
*
2821-
* Given a relation's pg_class tuple, return the AutoVacOpts portion of
2822-
* reloptions, if set; otherwise, return NULL.
2838+
* Given a relation's pg_class tuple, return a palloc'd copy of the
2839+
* AutoVacOpts portion of reloptions, if set; otherwise, return NULL.
28232840
*
28242841
* Note: callers do not have a relation lock on the table at this point,
28252842
* so the table could have been dropped, and its catalog rows gone, after
@@ -2868,6 +2885,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
28682885
autovac_table *tab = NULL;
28692886
bool wraparound;
28702887
AutoVacOpts *avopts;
2888+
bool free_avopts = false;
28712889

28722890
/* fetch the relation's relcache entry */
28732891
classTup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(relid));
@@ -2880,8 +2898,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
28802898
* main table reloptions if the toast table itself doesn't have.
28812899
*/
28822900
avopts = extract_autovac_opts(classTup, pg_class_desc);
2883-
if (classForm->relkind == RELKIND_TOASTVALUE &&
2884-
avopts == NULL && table_toast_map != NULL)
2901+
if (avopts)
2902+
free_avopts = true;
2903+
else if (classForm->relkind == RELKIND_TOASTVALUE &&
2904+
table_toast_map != NULL)
28852905
{
28862906
av_relation *hentry;
28872907
bool found;
@@ -2983,6 +3003,8 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
29833003
avopts->vacuum_cost_delay >= 0));
29843004
}
29853005

3006+
if (free_avopts)
3007+
pfree(avopts);
29863008
heap_freetuple(classTup);
29873009
return tab;
29883010
}
@@ -3014,6 +3036,10 @@ recheck_relation_needs_vacanalyze(Oid relid,
30143036
effective_multixact_freeze_max_age,
30153037
dovacuum, doanalyze, wraparound);
30163038

3039+
/* Release tabentry to avoid leakage */
3040+
if (tabentry)
3041+
pfree(tabentry);
3042+
30173043
/* ignore ANALYZE for toast tables */
30183044
if (classForm->relkind == RELKIND_TOASTVALUE)
30193045
*doanalyze = false;
@@ -3236,18 +3262,22 @@ autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
32363262
VacuumRelation *rel;
32373263
List *rel_list;
32383264
MemoryContext vac_context;
3265+
MemoryContext old_context;
32393266

32403267
/* Let pgstat know what we're doing */
32413268
autovac_report_activity(tab);
32423269

3270+
/* Create a context that vacuum() can use as cross-transaction storage */
3271+
vac_context = AllocSetContextCreate(CurrentMemoryContext,
3272+
"Vacuum",
3273+
ALLOCSET_DEFAULT_SIZES);
3274+
32433275
/* Set up one VacuumRelation target, identified by OID, for vacuum() */
3276+
old_context = MemoryContextSwitchTo(vac_context);
32443277
rangevar = makeRangeVar(tab->at_nspname, tab->at_relname, -1);
32453278
rel = makeVacuumRelation(rangevar, tab->at_relid, NIL);
32463279
rel_list = list_make1(rel);
3247-
3248-
vac_context = AllocSetContextCreate(CurrentMemoryContext,
3249-
"Vacuum",
3250-
ALLOCSET_DEFAULT_SIZES);
3280+
MemoryContextSwitchTo(old_context);
32513281

32523282
vacuum(rel_list, &tab->at_params, bstrategy, vac_context, true);
32533283

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