Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 69e8c7c

Browse filesBrowse files
committed
Limit memory usage of pg_walinspect functions.
GetWALRecordsInfo() and pg_get_wal_fpi_info() can leak memory across WAL record iterations. Fix this by using a temporary memory context that's reset for each WAL record iteraion. Also a use temporary context for loops in GetXLogSummaryStats(). The number of iterations is a small constant, so the previous behavior was not a leak, but fix for clarity (but no need to backport). Backport GetWALRecordsInfo() change to version 15. pg_get_wal_fpi_info() didn't exist in version 15. Reported-by: Peter Geoghegan Author: Bharath Rupireddy Discussion: https://www.postgresql.org/message-id/CAH2-WznLEJjn7ghmKOABOEZYuJvkTk%3DGKU3m0%2B-XBAH%2BerPiJQ%40mail.gmail.com Backpatch-through: 15
1 parent c6c3b3b commit 69e8c7c
Copy full SHA for 69e8c7c

File tree

1 file changed

+53
-5
lines changed
Filter options

1 file changed

+53
-5
lines changed

‎contrib/pg_walinspect/pg_walinspect.c

Copy file name to clipboardExpand all lines: contrib/pg_walinspect/pg_walinspect.c
+53-5Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
304304
XLogRecPtr start_lsn;
305305
XLogRecPtr end_lsn;
306306
XLogReaderState *xlogreader;
307+
MemoryContext old_cxt;
308+
MemoryContext tmp_cxt;
307309

308310
start_lsn = PG_GETARG_LSN(0);
309311
end_lsn = PG_GETARG_LSN(1);
@@ -314,14 +316,26 @@ pg_get_wal_fpi_info(PG_FUNCTION_ARGS)
314316

315317
xlogreader = InitXLogReaderState(start_lsn);
316318

319+
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
320+
"pg_get_wal_fpi_info temporary cxt",
321+
ALLOCSET_DEFAULT_SIZES);
322+
317323
while (ReadNextXLogRecord(xlogreader) &&
318324
xlogreader->EndRecPtr <= end_lsn)
319325
{
326+
/* Use the tmp context so we can clean up after each tuple is done */
327+
old_cxt = MemoryContextSwitchTo(tmp_cxt);
328+
320329
GetWALFPIInfo(fcinfo, xlogreader);
321330

331+
/* clean up and switch back */
332+
MemoryContextSwitchTo(old_cxt);
333+
MemoryContextReset(tmp_cxt);
334+
322335
CHECK_FOR_INTERRUPTS();
323336
}
324337

338+
MemoryContextDelete(tmp_cxt);
325339
pfree(xlogreader->private_data);
326340
XLogReaderFree(xlogreader);
327341

@@ -440,23 +454,37 @@ GetWALRecordsInfo(FunctionCallInfo fcinfo, XLogRecPtr start_lsn,
440454
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
441455
Datum values[PG_GET_WAL_RECORDS_INFO_COLS] = {0};
442456
bool nulls[PG_GET_WAL_RECORDS_INFO_COLS] = {0};
457+
MemoryContext old_cxt;
458+
MemoryContext tmp_cxt;
443459

444460
InitMaterializedSRF(fcinfo, 0);
445461

446462
xlogreader = InitXLogReaderState(start_lsn);
447463

464+
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
465+
"GetWALRecordsInfo temporary cxt",
466+
ALLOCSET_DEFAULT_SIZES);
467+
448468
while (ReadNextXLogRecord(xlogreader) &&
449469
xlogreader->EndRecPtr <= end_lsn)
450470
{
471+
/* Use the tmp context so we can clean up after each tuple is done */
472+
old_cxt = MemoryContextSwitchTo(tmp_cxt);
473+
451474
GetWALRecordInfo(xlogreader, values, nulls,
452475
PG_GET_WAL_RECORDS_INFO_COLS);
453476

454477
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
455478
values, nulls);
456479

480+
/* clean up and switch back */
481+
MemoryContextSwitchTo(old_cxt);
482+
MemoryContextReset(tmp_cxt);
483+
457484
CHECK_FOR_INTERRUPTS();
458485
}
459486

487+
MemoryContextDelete(tmp_cxt);
460488
pfree(xlogreader->private_data);
461489
XLogReaderFree(xlogreader);
462490

@@ -560,11 +588,13 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
560588
Datum *values, bool *nulls, uint32 ncols,
561589
bool stats_per_record)
562590
{
563-
uint64 total_count = 0;
564-
uint64 total_rec_len = 0;
565-
uint64 total_fpi_len = 0;
566-
uint64 total_len = 0;
567-
int ri;
591+
MemoryContext old_cxt;
592+
MemoryContext tmp_cxt;
593+
uint64 total_count = 0;
594+
uint64 total_rec_len = 0;
595+
uint64 total_fpi_len = 0;
596+
uint64 total_len = 0;
597+
int ri;
568598

569599
/*
570600
* Each row shows its percentages of the total, so make a first pass to
@@ -581,6 +611,10 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
581611
}
582612
total_len = total_rec_len + total_fpi_len;
583613

614+
tmp_cxt = AllocSetContextCreate(CurrentMemoryContext,
615+
"GetXLogSummaryStats temporary cxt",
616+
ALLOCSET_DEFAULT_SIZES);
617+
584618
for (ri = 0; ri <= RM_MAX_ID; ri++)
585619
{
586620
uint64 count;
@@ -614,6 +648,8 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
614648
if (count == 0)
615649
continue;
616650

651+
old_cxt = MemoryContextSwitchTo(tmp_cxt);
652+
617653
/* the upper four bits in xl_info are the rmgr's */
618654
id = desc.rm_identify(rj << 4);
619655
if (id == NULL)
@@ -626,6 +662,10 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
626662

627663
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
628664
values, nulls);
665+
666+
/* clean up and switch back */
667+
MemoryContextSwitchTo(old_cxt);
668+
MemoryContextReset(tmp_cxt);
629669
}
630670
}
631671
else
@@ -635,14 +675,22 @@ GetXLogSummaryStats(XLogStats *stats, ReturnSetInfo *rsinfo,
635675
fpi_len = stats->rmgr_stats[ri].fpi_len;
636676
tot_len = rec_len + fpi_len;
637677

678+
old_cxt = MemoryContextSwitchTo(tmp_cxt);
679+
638680
FillXLogStatsRow(desc.rm_name, count, total_count, rec_len,
639681
total_rec_len, fpi_len, total_fpi_len, tot_len,
640682
total_len, values, nulls, ncols);
641683

642684
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
643685
values, nulls);
686+
687+
/* clean up and switch back */
688+
MemoryContextSwitchTo(old_cxt);
689+
MemoryContextReset(tmp_cxt);
644690
}
645691
}
692+
693+
MemoryContextDelete(tmp_cxt);
646694
}
647695

648696
/*

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.