PostgreSQL Source Code git master
Loading...
Searching...
No Matches
walsummarizer.c File Reference
#include "postgres.h"
#include "access/timeline.h"
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xlogrecovery.h"
#include "access/xlogutils.h"
#include "backup/walsummary.h"
#include "catalog/storage_xlog.h"
#include "commands/dbcommands_xlog.h"
#include "common/blkreftable.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "postmaster/auxprocess.h"
#include "postmaster/interrupt.h"
#include "postmaster/walsummarizer.h"
#include "replication/walreceiver.h"
#include "storage/aio_subsys.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/lwlock.h"
#include "storage/proc.h"
#include "storage/procsignal.h"
#include "storage/shmem.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/wait_event.h"
Include dependency graph for walsummarizer.c:

Go to the source code of this file.

Data Structures

struct  WalSummarizerData
 
struct  SummarizerReadLocalXLogPrivate
 

Macros

#define MAX_SLEEP_QUANTA   150
 
#define MS_PER_SLEEP_QUANTUM   200
 

Functions

static void WalSummarizerShutdown (int code, Datum arg)
 
static XLogRecPtr GetLatestLSN (TimeLineID *tli)
 
static void ProcessWalSummarizerInterrupts (void)
 
static XLogRecPtr SummarizeWAL (TimeLineID tli, XLogRecPtr start_lsn, bool exact, XLogRecPtr switch_lsn, XLogRecPtr maximum_lsn)
 
static void SummarizeDbaseRecord (XLogReaderState *xlogreader, BlockRefTable *brtab)
 
static void SummarizeSmgrRecord (XLogReaderState *xlogreader, BlockRefTable *brtab)
 
static void SummarizeXactRecord (XLogReaderState *xlogreader, BlockRefTable *brtab)
 
static bool SummarizeXlogRecord (XLogReaderState *xlogreader, bool *new_fast_forward)
 
static int summarizer_read_local_xlog_page (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
 
static void summarizer_wait_for_wal (void)
 
static void MaybeRemoveOldWalSummaries (void)
 
Size WalSummarizerShmemSize (void)
 
void WalSummarizerShmemInit (void)
 
void WalSummarizerMain (const void *startup_data, size_t startup_data_len)
 
void GetWalSummarizerState (TimeLineID *summarized_tli, XLogRecPtr *summarized_lsn, XLogRecPtr *pending_lsn, int *summarizer_pid)
 
XLogRecPtr GetOldestUnsummarizedLSN (TimeLineID *tli, bool *lsn_is_exact)
 
void WakeupWalSummarizer (void)
 
void WaitForWalSummarization (XLogRecPtr lsn)
 

Variables

static WalSummarizerDataWalSummarizerCtl
 
static long sleep_quanta = 1
 
static long pages_read_since_last_sleep = 0
 
static XLogRecPtr redo_pointer_at_last_summary_removal = InvalidXLogRecPtr
 
bool summarize_wal = false
 
int wal_summary_keep_time = 10 * HOURS_PER_DAY * MINS_PER_HOUR
 

Macro Definition Documentation

◆ MAX_SLEEP_QUANTA

#define MAX_SLEEP_QUANTA   150

Definition at line 127 of file walsummarizer.c.

◆ MS_PER_SLEEP_QUANTUM

#define MS_PER_SLEEP_QUANTUM   200

Definition at line 128 of file walsummarizer.c.

Function Documentation

◆ GetLatestLSN()

static XLogRecPtr GetLatestLSN ( TimeLineID tli)
static

Definition at line 799 of file walsummarizer.c.

800{
801 if (!RecoveryInProgress())
802 {
803 /* Don't summarize WAL before it's flushed. */
804 return GetFlushRecPtr(tli);
805 }
806 else
807 {
813
814 /*
815 * After the insert TLI has been set and before the control file has
816 * been updated to show the DB in production, RecoveryInProgress()
817 * will return true, because it's not yet safe for all backends to
818 * begin writing WAL. However, replay has already ceased, so from our
819 * point of view, recovery is already over. We should summarize up to
820 * where replay stopped and then prepare to resume at the start of the
821 * insert timeline.
822 */
824 {
825 *tli = insert_tli;
827 }
828
829 /*
830 * What we really want to know is how much WAL has been flushed to
831 * disk, but the only flush position available is the one provided by
832 * the walreceiver, which may not be running, because this could be
833 * crash recovery or recovery via restore_command. So use either the
834 * WAL receiver's flush position or the replay position, whichever is
835 * further ahead, on the theory that if the WAL has been replayed then
836 * it must also have been flushed to disk.
837 */
840 if (flush_lsn > replay_lsn)
841 {
842 *tli = flush_tli;
843 return flush_lsn;
844 }
845 else
846 {
847 *tli = replay_tli;
848 return replay_lsn;
849 }
850 }
851}
static int fb(int x)
XLogRecPtr GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI)
bool RecoveryInProgress(void)
Definition xlog.c:6460
XLogRecPtr GetFlushRecPtr(TimeLineID *insertTLI)
Definition xlog.c:6625
TimeLineID GetWALInsertionTimeLineIfSet(void)
Definition xlog.c:6662
uint64 XLogRecPtr
Definition xlogdefs.h:21
uint32 TimeLineID
Definition xlogdefs.h:63
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)

References fb(), GetFlushRecPtr(), GetWALInsertionTimeLineIfSet(), GetWalRcvFlushRecPtr(), GetXLogReplayRecPtr(), and RecoveryInProgress().

Referenced by GetOldestUnsummarizedLSN(), summarizer_read_local_xlog_page(), and WalSummarizerMain().

◆ GetOldestUnsummarizedLSN()

XLogRecPtr GetOldestUnsummarizedLSN ( TimeLineID tli,
bool lsn_is_exact 
)

Definition at line 504 of file walsummarizer.c.

505{
507 int n;
508 List *tles;
511 bool should_make_exact = false;
513 ListCell *lc;
515
516 /* If not summarizing WAL, do nothing. */
517 if (!summarize_wal)
518 return InvalidXLogRecPtr;
519
520 /*
521 * If we are not the WAL summarizer process, then we normally just want to
522 * read the values from shared memory. However, as an exception, if shared
523 * memory hasn't been initialized yet, then we need to do that so that we
524 * can read legal values and not remove any WAL too early.
525 */
527 {
529
531 {
533 if (tli != NULL)
535 if (lsn_is_exact != NULL)
536 *lsn_is_exact = WalSummarizerCtl->lsn_is_exact;
538 return unsummarized_lsn;
539 }
540
542 }
543
544 /*
545 * Find the oldest timeline on which WAL still exists, and the earliest
546 * segment for which it exists.
547 *
548 * Note that we do this every time the WAL summarizer process restarts or
549 * recovers from an error, in case the contents of pg_wal have changed
550 * under us e.g. if some files were removed, either manually - which
551 * shouldn't really happen, but might - or by postgres itself, if
552 * summarize_wal was turned off and then back on again.
553 */
556 for (n = list_length(tles) - 1; n >= 0; --n)
557 {
560
562 if (oldest_segno != 0)
563 {
564 /* Compute oldest LSN that still exists on disk. */
567
568 unsummarized_tli = tle->tli;
569 break;
570 }
571 }
572
573 /*
574 * Don't try to summarize anything older than the end LSN of the newest
575 * summary file that exists for this timeline.
576 */
580 foreach(lc, existing_summaries)
581 {
583
584 if (ws->end_lsn > unsummarized_lsn)
585 {
586 unsummarized_lsn = ws->end_lsn;
587 should_make_exact = true;
588 }
589 }
590
591 /* It really should not be possible for us to find no WAL. */
592 if (unsummarized_tli == 0)
595 errmsg_internal("no WAL found on timeline %u", latest_tli));
596
597 /*
598 * If we're the WAL summarizer, we always want to store the values we just
599 * computed into shared memory, because those are the values we're going
600 * to use to drive our operation, and so they are the authoritative
601 * values. Otherwise, we only store values into shared memory if shared
602 * memory is uninitialized. Our values are not canonical in such a case,
603 * but it's better to have something than nothing, to guide WAL retention.
604 */
607 {
613 }
614 else
616
617 /* Also return the to the caller as required. */
618 if (tli != NULL)
620 if (lsn_is_exact != NULL)
621 *lsn_is_exact = WalSummarizerCtl->lsn_is_exact;
623
624 return unsummarized_lsn;
625}
List * readTimeLineHistory(TimeLineID targetTLI)
Definition timeline.c:76
int errcode(int sqlerrcode)
Definition elog.c:874
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1176
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
@ LW_SHARED
Definition lwlock.h:113
@ LW_EXCLUSIVE
Definition lwlock.h:112
#define AmWalSummarizerProcess()
Definition miscadmin.h:392
#define lfirst(lc)
Definition pg_list.h:172
static int list_length(const List *l)
Definition pg_list.h:152
static void * list_nth(const List *list, int n)
Definition pg_list.h:299
Definition pg_list.h:54
XLogRecPtr summarized_lsn
TimeLineID summarized_tli
XLogRecPtr pending_lsn
static XLogRecPtr GetLatestLSN(TimeLineID *tli)
static WalSummarizerData * WalSummarizerCtl
bool summarize_wal
List * GetWalSummaries(TimeLineID tli, XLogRecPtr start_lsn, XLogRecPtr end_lsn)
Definition walsummary.c:43
int wal_segment_size
Definition xlog.c:146
XLogSegNo XLogGetOldestSegno(TimeLineID tli)
Definition xlog.c:3811
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
#define InvalidXLogRecPtr
Definition xlogdefs.h:28
uint64 XLogSegNo
Definition xlogdefs.h:52

References AmWalSummarizerProcess, ereport, errcode(), errmsg_internal(), ERROR, fb(), GetLatestLSN(), GetWalSummaries(), WalSummarizerData::initialized, InvalidXLogRecPtr, lfirst, list_length(), list_nth(), WalSummarizerData::lsn_is_exact, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), WalSummarizerData::pending_lsn, readTimeLineHistory(), summarize_wal, WalSummarizerData::summarized_lsn, WalSummarizerData::summarized_tli, wal_segment_size, WalSummarizerCtl, XLogGetOldestSegno(), and XLogSegNoOffsetToRecPtr.

Referenced by KeepLogSeg(), and WalSummarizerMain().

◆ GetWalSummarizerState()

void GetWalSummarizerState ( TimeLineID summarized_tli,
XLogRecPtr summarized_lsn,
XLogRecPtr pending_lsn,
int summarizer_pid 
)

Definition at line 446 of file walsummarizer.c.

448{
451 {
452 /*
453 * If initialized is false, the rest of the structure contents are
454 * undefined.
455 */
456 *summarized_tli = 0;
457 *summarized_lsn = InvalidXLogRecPtr;
458 *pending_lsn = InvalidXLogRecPtr;
459 *summarizer_pid = -1;
460 }
461 else
462 {
463 int summarizer_pgprocno = WalSummarizerCtl->summarizer_pgprocno;
464
465 *summarized_tli = WalSummarizerCtl->summarized_tli;
466 *summarized_lsn = WalSummarizerCtl->summarized_lsn;
467 if (summarizer_pgprocno == INVALID_PROC_NUMBER)
468 {
469 /*
470 * If the summarizer has exited, the fact that it had processed
471 * beyond summarized_lsn is irrelevant now.
472 */
473 *pending_lsn = WalSummarizerCtl->summarized_lsn;
474 *summarizer_pid = -1;
475 }
476 else
477 {
478 *pending_lsn = WalSummarizerCtl->pending_lsn;
479
480 /*
481 * We're not fussed about inexact answers here, since they could
482 * become stale instantly, so we don't bother taking the lock, but
483 * make sure that invalid PID values are normalized to -1.
484 */
485 *summarizer_pid = GetPGProcByNumber(summarizer_pgprocno)->pid;
486 if (*summarizer_pid <= 0)
487 *summarizer_pid = -1;
488 }
489 }
491}
#define GetPGProcByNumber(n)
Definition proc.h:504
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
ProcNumber summarizer_pgprocno

References fb(), GetPGProcByNumber, WalSummarizerData::initialized, INVALID_PROC_NUMBER, InvalidXLogRecPtr, LW_SHARED, LWLockAcquire(), LWLockRelease(), WalSummarizerData::pending_lsn, WalSummarizerData::summarized_lsn, WalSummarizerData::summarized_tli, WalSummarizerData::summarizer_pgprocno, and WalSummarizerCtl.

Referenced by pg_get_wal_summarizer_state().

◆ MaybeRemoveOldWalSummaries()

static void MaybeRemoveOldWalSummaries ( void  )
static

Definition at line 1655 of file walsummarizer.c.

1656{
1658 List *wslist;
1660
1661 /* If WAL summary removal is disabled, don't do anything. */
1662 if (wal_summary_keep_time == 0)
1663 return;
1664
1665 /*
1666 * If the redo pointer has not advanced, don't do anything.
1667 *
1668 * This has the effect that we only try to remove old WAL summary files
1669 * once per checkpoint cycle.
1670 */
1672 return;
1674
1675 /*
1676 * Files should only be removed if the last modification time precedes the
1677 * cutoff time we compute here.
1678 */
1680
1681 /* Get all the summaries that currently exist. */
1683
1684 /* Loop until all summaries have been considered for removal. */
1685 while (wslist != NIL)
1686 {
1687 ListCell *lc;
1691
1693
1694 /*
1695 * Pick a timeline for which some summary files still exist on disk,
1696 * and find the oldest LSN that still exists on disk for that
1697 * timeline.
1698 */
1701 if (oldest_segno != 0)
1703 oldest_lsn);
1704
1705
1706 /* Consider each WAL file on the selected timeline in turn. */
1707 foreach(lc, wslist)
1708 {
1710
1712
1713 /* If it's not on this timeline, it's not time to consider it. */
1714 if (selected_tli != ws->tli)
1715 continue;
1716
1717 /*
1718 * If the WAL doesn't exist any more, we can remove it if the file
1719 * modification time is old enough.
1720 */
1721 if (!XLogRecPtrIsValid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
1723
1724 /*
1725 * Whether we removed the file or not, we need not consider it
1726 * again.
1727 */
1729 pfree(ws);
1730 }
1731 }
1732}
#define SECS_PER_MINUTE
Definition timestamp.h:128
void pfree(void *pointer)
Definition mcxt.c:1616
#define NIL
Definition pg_list.h:68
#define foreach_delete_current(lst, var_or_cell)
Definition pg_list.h:391
#define linitial(l)
Definition pg_list.h:178
static XLogRecPtr redo_pointer_at_last_summary_removal
static void ProcessWalSummarizerInterrupts(void)
int wal_summary_keep_time
void RemoveWalSummaryIfOlderThan(WalSummaryFile *ws, time_t cutoff_time)
Definition walsummary.c:230
XLogRecPtr GetRedoRecPtr(void)
Definition xlog.c:6563
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29

References fb(), foreach_delete_current, GetRedoRecPtr(), GetWalSummaries(), InvalidXLogRecPtr, lfirst, linitial, NIL, pfree(), ProcessWalSummarizerInterrupts(), redo_pointer_at_last_summary_removal, RemoveWalSummaryIfOlderThan(), SECS_PER_MINUTE, wal_segment_size, wal_summary_keep_time, XLogGetOldestSegno(), XLogRecPtrIsValid, and XLogSegNoOffsetToRecPtr.

Referenced by WalSummarizerMain().

◆ ProcessWalSummarizerInterrupts()

static void ProcessWalSummarizerInterrupts ( void  )
static

Definition at line 857 of file walsummarizer.c.

858{
861
863 {
864 ConfigReloadPending = false;
866 }
867
869 {
871 errmsg_internal("WAL summarizer shutting down"));
872 proc_exit(0);
873 }
874
875 /* Perform logging of memory contexts of this process */
878}
#define DEBUG1
Definition elog.h:30
volatile sig_atomic_t LogMemoryContextPending
Definition globals.c:41
volatile sig_atomic_t ProcSignalBarrierPending
Definition globals.c:40
void ProcessConfigFile(GucContext context)
Definition guc-file.l:120
@ PGC_SIGHUP
Definition guc.h:75
volatile sig_atomic_t ShutdownRequestPending
Definition interrupt.c:28
volatile sig_atomic_t ConfigReloadPending
Definition interrupt.c:27
void proc_exit(int code)
Definition ipc.c:105
void ProcessLogMemoryContextInterrupt(void)
Definition mcxt.c:1340
void ProcessProcSignalBarrier(void)
Definition procsignal.c:501

References ConfigReloadPending, DEBUG1, ereport, errmsg_internal(), LogMemoryContextPending, PGC_SIGHUP, proc_exit(), ProcessConfigFile(), ProcessLogMemoryContextInterrupt(), ProcessProcSignalBarrier(), ProcSignalBarrierPending, ShutdownRequestPending, and summarize_wal.

Referenced by MaybeRemoveOldWalSummaries(), summarizer_read_local_xlog_page(), SummarizeWAL(), and WalSummarizerMain().

◆ SummarizeDbaseRecord()

static void SummarizeDbaseRecord ( XLogReaderState xlogreader,
BlockRefTable brtab 
)
static

Definition at line 1244 of file walsummarizer.c.

1245{
1247
1248 /*
1249 * We use relfilenode zero for a given database OID and tablespace OID to
1250 * indicate that all relations with that pair of IDs have been recreated
1251 * if they exist at all. Effectively, we're setting a limit block of 0 for
1252 * all such relfilenodes.
1253 *
1254 * Technically, this special handling is only needed in the case of
1255 * XLOG_DBASE_CREATE_FILE_COPY, because that can create a whole bunch of
1256 * relation files in a directory without logging anything specific to each
1257 * one. If we didn't mark the whole DB OID/TS OID combination in some way,
1258 * then a tablespace that was dropped after the reference backup and
1259 * recreated using the FILE_COPY method prior to the incremental backup
1260 * would look just like one that was never touched at all, which would be
1261 * catastrophic.
1262 *
1263 * But it seems best to adopt this treatment for all records that drop or
1264 * create a DB OID/TS OID combination. That's similar to how we treat the
1265 * limit block for individual relations, and it's an extra layer of safety
1266 * here. We can never lose data by marking more stuff as needing to be
1267 * backed up in full.
1268 */
1269 if (info == XLOG_DBASE_CREATE_FILE_COPY)
1270 {
1272 RelFileLocator rlocator;
1273
1274 xlrec =
1276 rlocator.spcOid = xlrec->tablespace_id;
1277 rlocator.dbOid = xlrec->db_id;
1278 rlocator.relNumber = 0;
1279 BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
1280 }
1281 else if (info == XLOG_DBASE_CREATE_WAL_LOG)
1282 {
1284 RelFileLocator rlocator;
1285
1287 rlocator.spcOid = xlrec->tablespace_id;
1288 rlocator.dbOid = xlrec->db_id;
1289 rlocator.relNumber = 0;
1290 BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
1291 }
1292 else if (info == XLOG_DBASE_DROP)
1293 {
1295 RelFileLocator rlocator;
1296 int i;
1297
1299 rlocator.dbOid = xlrec->db_id;
1300 rlocator.relNumber = 0;
1301 for (i = 0; i < xlrec->ntablespaces; ++i)
1302 {
1303 rlocator.spcOid = xlrec->tablespace_ids[i];
1304 BlockRefTableSetLimitBlock(brtab, &rlocator, MAIN_FORKNUM, 0);
1305 }
1306 }
1307}
void BlockRefTableSetLimitBlock(BlockRefTable *brtab, const RelFileLocator *rlocator, ForkNumber forknum, BlockNumber limit_block)
uint8_t uint8
Definition c.h:556
#define XLOG_DBASE_CREATE_WAL_LOG
#define XLOG_DBASE_DROP
#define XLOG_DBASE_CREATE_FILE_COPY
int i
Definition isn.c:77
@ MAIN_FORKNUM
Definition relpath.h:58
RelFileNumber relNumber
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:409
#define XLogRecGetData(decoder)
Definition xlogreader.h:414
static XLogReaderState * xlogreader

References BlockRefTableSetLimitBlock(), RelFileLocator::dbOid, fb(), i, MAIN_FORKNUM, RelFileLocator::relNumber, RelFileLocator::spcOid, XLOG_DBASE_CREATE_FILE_COPY, XLOG_DBASE_CREATE_WAL_LOG, XLOG_DBASE_DROP, xlogreader, XLogRecGetData, and XLogRecGetInfo.

Referenced by SummarizeWAL().

◆ summarizer_read_local_xlog_page()

static int summarizer_read_local_xlog_page ( XLogReaderState state,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetRecPtr,
char cur_page 
)
static

Definition at line 1495 of file walsummarizer.c.

1498{
1499 int count;
1501 SummarizerReadLocalXLogPrivate *private_data;
1502
1504
1505 private_data = (SummarizerReadLocalXLogPrivate *)
1506 state->private_data;
1507
1508 while (1)
1509 {
1511 {
1512 /*
1513 * more than one block available; read only that block, have
1514 * caller come back if they need more.
1515 */
1516 count = XLOG_BLCKSZ;
1517 break;
1518 }
1519 else if (targetPagePtr + reqLen > private_data->read_upto)
1520 {
1521 /* We don't seem to have enough data. */
1522 if (private_data->historic)
1523 {
1524 /*
1525 * This is a historic timeline, so there will never be any
1526 * more data than we have currently.
1527 */
1528 private_data->end_of_wal = true;
1529 return -1;
1530 }
1531 else
1532 {
1535
1536 /*
1537 * This is - or at least was up until very recently - the
1538 * current timeline, so more data might show up. Delay here
1539 * so we don't tight-loop.
1540 */
1543
1544 /* Recheck end-of-WAL. */
1546 if (private_data->tli == latest_tli)
1547 {
1548 /* Still the current timeline, update max LSN. */
1549 Assert(latest_lsn >= private_data->read_upto);
1550 private_data->read_upto = latest_lsn;
1551 }
1552 else
1553 {
1556
1557 /*
1558 * The timeline we're scanning is no longer the latest
1559 * one. Figure out when it ended.
1560 */
1561 private_data->historic = true;
1562 switchpoint = tliSwitchPoint(private_data->tli, tles,
1563 NULL);
1564
1565 /*
1566 * Allow reads up to exactly the switch point.
1567 *
1568 * It's possible that this will cause read_upto to move
1569 * backwards, because we might have been promoted before
1570 * reaching the end of the previous timeline. In that
1571 * case, the next loop iteration will likely conclude that
1572 * we've reached end of WAL.
1573 */
1574 private_data->read_upto = switchpoint;
1575
1576 /* Debugging output. */
1578 errmsg_internal("timeline %u became historic, can read up to %X/%08X",
1579 private_data->tli, LSN_FORMAT_ARGS(private_data->read_upto)));
1580 }
1581
1582 /* Go around and try again. */
1583 }
1584 }
1585 else
1586 {
1587 /* enough bytes available to satisfy the request */
1588 count = private_data->read_upto - targetPagePtr;
1589 break;
1590 }
1591 }
1592
1593 if (!WALRead(state, cur_page, targetPagePtr, count,
1594 private_data->tli, &errinfo))
1596
1597 /* Track that we read a page, for sleep time calculation. */
1599
1600 /* number of valid bytes in the buffer */
1601 return count;
1602}
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition timeline.c:572
#define Assert(condition)
Definition c.h:885
static long pages_read_since_last_sleep
static void summarizer_wait_for_wal(void)
#define LSN_FORMAT_ARGS(lsn)
Definition xlogdefs.h:47
bool WALRead(XLogReaderState *state, char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALReadError *errinfo)
void WALReadRaiseError(WALReadError *errinfo)
Definition xlogutils.c:1011

References Assert, DEBUG1, SummarizerReadLocalXLogPrivate::end_of_wal, ereport, errmsg_internal(), fb(), GetLatestLSN(), SummarizerReadLocalXLogPrivate::historic, LSN_FORMAT_ARGS, pages_read_since_last_sleep, ProcessWalSummarizerInterrupts(), SummarizerReadLocalXLogPrivate::read_upto, readTimeLineHistory(), summarizer_wait_for_wal(), SummarizerReadLocalXLogPrivate::tli, tliSwitchPoint(), WALRead(), and WALReadRaiseError().

Referenced by SummarizeWAL().

◆ summarizer_wait_for_wal()

static void summarizer_wait_for_wal ( void  )
static

Definition at line 1609 of file walsummarizer.c.

1610{
1612 {
1613 /*
1614 * No pages were read since the last sleep, so double the sleep time,
1615 * but not beyond the maximum allowable value.
1616 */
1618 }
1619 else if (pages_read_since_last_sleep > 1)
1620 {
1621 /*
1622 * Multiple pages were read since the last sleep, so reduce the sleep
1623 * time.
1624 *
1625 * A large burst of activity should be able to quickly reduce the
1626 * sleep time to the minimum, but we don't want a handful of extra WAL
1627 * records to provoke a strong reaction. We choose to reduce the sleep
1628 * time by 1 quantum for each page read beyond the first, which is a
1629 * fairly arbitrary way of trying to be reactive without overreacting.
1630 */
1632 sleep_quanta = 1;
1633 else
1635 }
1636
1637 /* Report pending statistics to the cumulative stats system. */
1638 pgstat_report_wal(false);
1639
1640 /* OK, now sleep. */
1646
1647 /* Reset count of pages read. */
1649}
#define Min(x, y)
Definition c.h:1019
struct Latch * MyLatch
Definition globals.c:63
void ResetLatch(Latch *latch)
Definition latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition latch.c:172
void pgstat_report_wal(bool force)
Definition pgstat_wal.c:46
#define WL_TIMEOUT
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET
#define MAX_SLEEP_QUANTA
#define MS_PER_SLEEP_QUANTUM
static long sleep_quanta

References fb(), MAX_SLEEP_QUANTA, Min, MS_PER_SLEEP_QUANTUM, MyLatch, pages_read_since_last_sleep, pgstat_report_wal(), ResetLatch(), sleep_quanta, WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, and WL_TIMEOUT.

Referenced by summarizer_read_local_xlog_page().

◆ SummarizeSmgrRecord()

static void SummarizeSmgrRecord ( XLogReaderState xlogreader,
BlockRefTable brtab 
)
static

Definition at line 1313 of file walsummarizer.c.

1314{
1316
1317 if (info == XLOG_SMGR_CREATE)
1318 {
1320
1321 /*
1322 * If a new relation fork is created on disk, there is no point
1323 * tracking anything about which blocks have been modified, because
1324 * the whole thing will be new. Hence, set the limit block for this
1325 * fork to 0.
1326 *
1327 * Ignore the FSM fork, which is not fully WAL-logged.
1328 */
1330
1331 if (xlrec->forkNum != FSM_FORKNUM)
1332 BlockRefTableSetLimitBlock(brtab, &xlrec->rlocator,
1333 xlrec->forkNum, 0);
1334 }
1335 else if (info == XLOG_SMGR_TRUNCATE)
1336 {
1338
1340
1341 /*
1342 * If a relation fork is truncated on disk, there is no point in
1343 * tracking anything about block modifications beyond the truncation
1344 * point.
1345 *
1346 * We ignore SMGR_TRUNCATE_FSM here because the FSM isn't fully
1347 * WAL-logged and thus we can't track modified blocks for it anyway.
1348 */
1349 if ((xlrec->flags & SMGR_TRUNCATE_HEAP) != 0)
1350 BlockRefTableSetLimitBlock(brtab, &xlrec->rlocator,
1351 MAIN_FORKNUM, xlrec->blkno);
1352 if ((xlrec->flags & SMGR_TRUNCATE_VM) != 0)
1353 BlockRefTableSetLimitBlock(brtab, &xlrec->rlocator,
1355 }
1356}
@ FSM_FORKNUM
Definition relpath.h:59
@ VISIBILITYMAP_FORKNUM
Definition relpath.h:60
#define SMGR_TRUNCATE_VM
#define XLOG_SMGR_CREATE
#define XLOG_SMGR_TRUNCATE
#define SMGR_TRUNCATE_HEAP

References BlockRefTableSetLimitBlock(), fb(), FSM_FORKNUM, MAIN_FORKNUM, SMGR_TRUNCATE_HEAP, SMGR_TRUNCATE_VM, VISIBILITYMAP_FORKNUM, XLOG_SMGR_CREATE, XLOG_SMGR_TRUNCATE, xlogreader, XLogRecGetData, and XLogRecGetInfo.

Referenced by SummarizeWAL().

◆ SummarizeWAL()

static XLogRecPtr SummarizeWAL ( TimeLineID  tli,
XLogRecPtr  start_lsn,
bool  exact,
XLogRecPtr  switch_lsn,
XLogRecPtr  maximum_lsn 
)
static

Definition at line 905 of file walsummarizer.c.

907{
908 SummarizerReadLocalXLogPrivate *private_data;
912 char temp_path[MAXPGPATH];
913 char final_path[MAXPGPATH];
914 WalSummaryIO io;
916 bool fast_forward = true;
917
918 /* Initialize private data for xlogreader. */
920 private_data->tli = tli;
921 private_data->historic = XLogRecPtrIsValid(switch_lsn);
922 private_data->read_upto = maximum_lsn;
923
924 /* Create xlogreader. */
927 .segment_open = &wal_segment_open,
928 .segment_close = &wal_segment_close),
929 private_data);
930 if (xlogreader == NULL)
933 errmsg("out of memory"),
934 errdetail("Failed while allocating a WAL reading processor.")));
935
936 /*
937 * When exact = false, we're starting from an arbitrary point in the WAL
938 * and must search forward for the start of the next record.
939 *
940 * When exact = true, start_lsn should be either the LSN where a record
941 * begins, or the LSN of a page where the page header is immediately
942 * followed by the start of a new record. XLogBeginRead should tolerate
943 * either case.
944 *
945 * We need to allow for both cases because the behavior of xlogreader
946 * varies. When a record spans two or more xlog pages, the ending LSN
947 * reported by xlogreader will be the starting LSN of the following
948 * record, but when an xlog page boundary falls between two records, the
949 * end LSN for the first will be reported as the first byte of the
950 * following page. We can't know until we read that page how large the
951 * header will be, but we'll have to skip over it to find the next record.
952 */
953 if (exact)
954 {
955 /*
956 * Even if start_lsn is the beginning of a page rather than the
957 * beginning of the first record on that page, we should still use it
958 * as the start LSN for the summary file. That's because we detect
959 * missing summary files by looking for cases where the end LSN of one
960 * file is less than the start LSN of the next file. When only a page
961 * header is skipped, nothing has been missed.
962 */
963 XLogBeginRead(xlogreader, start_lsn);
964 summary_start_lsn = start_lsn;
965 }
966 else
967 {
970 {
971 /*
972 * If we hit end-of-WAL while trying to find the next valid
973 * record, we must be on a historic timeline that has no valid
974 * records that begin after start_lsn and before end of WAL.
975 */
976 if (private_data->end_of_wal)
977 {
979 errmsg_internal("could not read WAL from timeline %u at %X/%08X: end of WAL at %X/%08X",
980 tli,
981 LSN_FORMAT_ARGS(start_lsn),
982 LSN_FORMAT_ARGS(private_data->read_upto)));
983
984 /*
985 * The timeline ends at or after start_lsn, without containing
986 * any records. Thus, we must make sure the main loop does not
987 * iterate. If start_lsn is the end of the timeline, then we
988 * won't actually emit an empty summary file, but otherwise,
989 * we must, to capture the fact that the LSN range in question
990 * contains no interesting WAL records.
991 */
992 summary_start_lsn = start_lsn;
993 summary_end_lsn = private_data->read_upto;
995 }
996 else
998 errmsg("could not find a valid record after %X/%08X",
999 LSN_FORMAT_ARGS(start_lsn)));
1000 }
1001
1002 /* We shouldn't go backward. */
1003 Assert(summary_start_lsn >= start_lsn);
1004 }
1005
1006 /*
1007 * Main loop: read xlog records one by one.
1008 */
1009 while (1)
1010 {
1011 int block_id;
1012 char *errormsg;
1013 XLogRecord *record;
1014 uint8 rmid;
1015
1017
1018 /* We shouldn't go backward. */
1020
1021 /* Now read the next record. */
1022 record = XLogReadRecord(xlogreader, &errormsg);
1023 if (record == NULL)
1024 {
1025 if (private_data->end_of_wal)
1026 {
1027 /*
1028 * This timeline must be historic and must end before we were
1029 * able to read a complete record.
1030 */
1032 errmsg_internal("could not read WAL from timeline %u at %X/%08X: end of WAL at %X/%08X",
1033 tli,
1035 LSN_FORMAT_ARGS(private_data->read_upto)));
1036 /* Summary ends at end of WAL. */
1037 summary_end_lsn = private_data->read_upto;
1038 break;
1039 }
1040 if (errormsg)
1041 ereport(ERROR,
1043 errmsg("could not read WAL from timeline %u at %X/%08X: %s",
1045 errormsg)));
1046 else
1047 ereport(ERROR,
1049 errmsg("could not read WAL from timeline %u at %X/%08X",
1051 }
1052
1053 /* We shouldn't go backward. */
1055
1058 {
1059 /*
1060 * Whoops! We've read a record that *starts* after the switch LSN,
1061 * contrary to our goal of reading only until we hit the first
1062 * record that ends at or after the switch LSN. Pretend we didn't
1063 * read it after all by bailing out of this loop right here,
1064 * before we do anything with this record.
1065 *
1066 * This can happen because the last record before the switch LSN
1067 * might be continued across multiple pages, and then we might
1068 * come to a page with XLP_FIRST_IS_OVERWRITE_CONTRECORD set. In
1069 * that case, the record that was continued across multiple pages
1070 * is incomplete and will be disregarded, and the read will
1071 * restart from the beginning of the page that is flagged
1072 * XLP_FIRST_IS_OVERWRITE_CONTRECORD.
1073 *
1074 * If this case occurs, we can fairly say that the current summary
1075 * file ends at the switch LSN exactly. The first record on the
1076 * page marked XLP_FIRST_IS_OVERWRITE_CONTRECORD will be
1077 * discovered when generating the next summary file.
1078 */
1080 break;
1081 }
1082
1083 /*
1084 * Certain types of records require special handling. Redo points and
1085 * shutdown checkpoints trigger creation of new summary files and can
1086 * also cause us to enter or exit "fast forward" mode. Other types of
1087 * records can require special updates to the block reference table.
1088 */
1089 rmid = XLogRecGetRmid(xlogreader);
1090 if (rmid == RM_XLOG_ID)
1091 {
1092 bool new_fast_forward;
1093
1094 /*
1095 * If we've already processed some WAL records when we hit a redo
1096 * point or shutdown checkpoint, then we stop summarization before
1097 * including this record in the current file, so that it will be
1098 * the first record in the next file.
1099 *
1100 * When we hit one of those record types as the first record in a
1101 * file, we adjust our notion of whether we're fast-forwarding.
1102 * Any WAL generated with wal_level=minimal must be skipped
1103 * without actually generating any summary file, because an
1104 * incremental backup that crosses such WAL would be unsafe.
1105 */
1107 {
1109 {
1111 break;
1112 }
1113 else
1114 fast_forward = new_fast_forward;
1115 }
1116 }
1117 else if (!fast_forward)
1118 {
1119 /*
1120 * This switch handles record types that require extra updates to
1121 * the contents of the block reference table.
1122 */
1123 switch (rmid)
1124 {
1125 case RM_DBASE_ID:
1127 break;
1128 case RM_SMGR_ID:
1130 break;
1131 case RM_XACT_ID:
1133 break;
1134 }
1135 }
1136
1137 /*
1138 * If we're in fast-forward mode, we don't really need to do anything.
1139 * Otherwise, feed block references from xlog record to block
1140 * reference table.
1141 */
1142 if (!fast_forward)
1143 {
1145 block_id++)
1146 {
1147 RelFileLocator rlocator;
1148 ForkNumber forknum;
1149 BlockNumber blocknum;
1150
1152 &forknum, &blocknum, NULL))
1153 continue;
1154
1155 /*
1156 * As we do elsewhere, ignore the FSM fork, because it's not
1157 * fully WAL-logged.
1158 */
1159 if (forknum != FSM_FORKNUM)
1160 BlockRefTableMarkBlockModified(brtab, &rlocator, forknum,
1161 blocknum);
1162 }
1163 }
1164
1165 /* Update our notion of where this summary file ends. */
1167
1168 /* Also update shared memory. */
1173
1174 /*
1175 * If we have a switch LSN and have reached it, stop before reading
1176 * the next record.
1177 */
1180 break;
1181 }
1182
1183 /* Destroy xlogreader. */
1186
1187 /*
1188 * If a timeline switch occurs, we may fail to make any progress at all
1189 * before exiting the loop above. If that happens, we don't write a WAL
1190 * summary file at all. We can also skip writing a file if we're in
1191 * fast-forward mode.
1192 */
1193 if (summary_end_lsn > summary_start_lsn && !fast_forward)
1194 {
1195 /* Generate temporary and final path name. */
1197 XLOGDIR "/summaries/temp.summary");
1199 XLOGDIR "/summaries/%08X%08X%08X%08X%08X.summary",
1200 tli,
1203
1204 /* Open the temporary file for writing. */
1205 io.filepos = 0;
1207 if (io.file < 0)
1208 ereport(ERROR,
1210 errmsg("could not create file \"%s\": %m", temp_path)));
1211
1212 /* Write the data. */
1214
1215 /* Close temporary file and shut down xlogreader. */
1216 FileClose(io.file);
1217
1218 /* Tell the user what we did. */
1220 errmsg_internal("summarized WAL on TLI %u from %X/%08X to %X/%08X",
1221 tli,
1224
1225 /* Durably rename the new summary into place. */
1227 }
1228
1229 /* If we skipped a non-zero amount of WAL, log a debug message. */
1230 if (summary_end_lsn > summary_start_lsn && fast_forward)
1232 errmsg_internal("skipped summarizing WAL on TLI %u from %X/%08X to %X/%08X",
1233 tli,
1236
1237 return summary_end_lsn;
1238}
void BlockRefTableMarkBlockModified(BlockRefTable *brtab, const RelFileLocator *rlocator, ForkNumber forknum, BlockNumber blknum)
void WriteBlockRefTable(BlockRefTable *brtab, io_callback_fn write_callback, void *write_callback_arg)
void(*) BlockRefTable CreateEmptyBlockRefTable)(void)
uint32 BlockNumber
Definition block.h:31
int errcode_for_file_access(void)
Definition elog.c:897
int errmsg(const char *fmt,...)
Definition elog.c:1093
int errdetail(const char *fmt,...) pg_attribute_printf(1
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition fd.c:782
void FileClose(File file)
Definition fd.c:1965
File PathNameOpenFile(const char *fileName, int fileFlags)
Definition fd.c:1562
#define palloc0_object(type)
Definition fe_memutils.h:75
#define MAXPGPATH
#define snprintf
Definition port.h:260
ForkNumber
Definition relpath.h:56
off_t filepos
Definition walsummary.h:24
XLogRecPtr EndRecPtr
Definition xlogreader.h:206
XLogRecPtr ReadRecPtr
Definition xlogreader.h:205
void * private_data
Definition xlogreader.h:195
static bool SummarizeXlogRecord(XLogReaderState *xlogreader, bool *new_fast_forward)
static void SummarizeXactRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static void SummarizeDbaseRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
static int summarizer_read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
static void SummarizeSmgrRecord(XLogReaderState *xlogreader, BlockRefTable *brtab)
int WriteWalSummary(void *wal_summary_io, void *data, int length)
Definition walsummary.c:294
#define XLOGDIR
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition xlogreader.c:107
XLogRecord * XLogReadRecord(XLogReaderState *state, char **errormsg)
Definition xlogreader.c:390
void XLogReaderFree(XLogReaderState *state)
Definition xlogreader.c:162
XLogRecPtr XLogFindNextRecord(XLogReaderState *state, XLogRecPtr RecPtr)
void XLogBeginRead(XLogReaderState *state, XLogRecPtr RecPtr)
Definition xlogreader.c:232
#define XLogRecGetRmid(decoder)
Definition xlogreader.h:410
#define XL_ROUTINE(...)
Definition xlogreader.h:117
#define XLogRecMaxBlockId(decoder)
Definition xlogreader.h:417
void wal_segment_close(XLogReaderState *state)
Definition xlogutils.c:831
void wal_segment_open(XLogReaderState *state, XLogSegNo nextSegNo, TimeLineID *tli_p)
Definition xlogutils.c:806

References Assert, BlockRefTableMarkBlockModified(), DEBUG1, durable_rename(), SummarizerReadLocalXLogPrivate::end_of_wal, XLogReaderState::EndRecPtr, ereport, errcode(), errcode_for_file_access(), errdetail(), errmsg(), errmsg_internal(), ERROR, fb(), WalSummaryIO::file, FileClose(), WalSummaryIO::filepos, FSM_FORKNUM, SummarizerReadLocalXLogPrivate::historic, LSN_FORMAT_ARGS, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MAXPGPATH, palloc0_object, PathNameOpenFile(), WalSummarizerData::pending_lsn, pfree(), XLogReaderState::private_data, ProcessWalSummarizerInterrupts(), SummarizerReadLocalXLogPrivate::read_upto, XLogReaderState::ReadRecPtr, snprintf, WalSummarizerData::summarized_lsn, SummarizeDbaseRecord(), summarizer_read_local_xlog_page(), SummarizeSmgrRecord(), SummarizeXactRecord(), SummarizeXlogRecord(), SummarizerReadLocalXLogPrivate::tli, wal_segment_close(), wal_segment_open(), wal_segment_size, WalSummarizerCtl, WriteBlockRefTable(), WriteWalSummary(), XL_ROUTINE, XLogBeginRead(), XLOGDIR, XLogFindNextRecord(), xlogreader, XLogReaderAllocate(), XLogReaderFree(), XLogReadRecord(), XLogRecGetBlockTagExtended(), XLogRecGetRmid, XLogRecMaxBlockId, and XLogRecPtrIsValid.

Referenced by WalSummarizerMain().

◆ SummarizeXactRecord()

static void SummarizeXactRecord ( XLogReaderState xlogreader,
BlockRefTable brtab 
)
static

Definition at line 1362 of file walsummarizer.c.

1363{
1366
1367 if (xact_info == XLOG_XACT_COMMIT ||
1369 {
1372 int i;
1373
1374 /*
1375 * Don't track modified blocks for any relations that were removed on
1376 * commit.
1377 */
1379 for (i = 0; i < parsed.nrels; ++i)
1380 {
1381 ForkNumber forknum;
1382
1383 for (forknum = 0; forknum <= MAX_FORKNUM; ++forknum)
1384 if (forknum != FSM_FORKNUM)
1385 BlockRefTableSetLimitBlock(brtab, &parsed.xlocators[i],
1386 forknum, 0);
1387 }
1388 }
1389 else if (xact_info == XLOG_XACT_ABORT ||
1391 {
1394 int i;
1395
1396 /*
1397 * Don't track modified blocks for any relations that were removed on
1398 * abort.
1399 */
1401 for (i = 0; i < parsed.nrels; ++i)
1402 {
1403 ForkNumber forknum;
1404
1405 for (forknum = 0; forknum <= MAX_FORKNUM; ++forknum)
1406 if (forknum != FSM_FORKNUM)
1407 BlockRefTableSetLimitBlock(brtab, &parsed.xlocators[i],
1408 forknum, 0);
1409 }
1410 }
1411}
#define MAX_FORKNUM
Definition relpath.h:70
#define XLOG_XACT_COMMIT_PREPARED
Definition xact.h:173
#define XLOG_XACT_COMMIT
Definition xact.h:170
#define XLOG_XACT_OPMASK
Definition xact.h:180
#define XLOG_XACT_ABORT
Definition xact.h:172
#define XLOG_XACT_ABORT_PREPARED
Definition xact.h:174
void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
Definition xactdesc.c:35
void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
Definition xactdesc.c:141

References BlockRefTableSetLimitBlock(), fb(), FSM_FORKNUM, i, MAX_FORKNUM, ParseAbortRecord(), ParseCommitRecord(), XLOG_XACT_ABORT, XLOG_XACT_ABORT_PREPARED, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, xlogreader, XLogRecGetData, and XLogRecGetInfo.

Referenced by SummarizeWAL().

◆ SummarizeXlogRecord()

static bool SummarizeXlogRecord ( XLogReaderState xlogreader,
bool new_fast_forward 
)
static

Definition at line 1422 of file walsummarizer.c.

1423{
1425 int record_wal_level;
1426
1427 if (info == XLOG_CHECKPOINT_REDO)
1428 {
1429 /* Payload is wal_level at the time record was written. */
1431 }
1432 else if (info == XLOG_CHECKPOINT_SHUTDOWN)
1433 {
1435
1436 /* Extract wal_level at time record was written from payload. */
1438 record_wal_level = rec_ckpt.wal_level;
1439 }
1440 else if (info == XLOG_PARAMETER_CHANGE)
1441 {
1443
1444 /* Extract wal_level at time record was written from payload. */
1446 sizeof(xl_parameter_change));
1447 record_wal_level = xlrec.wal_level;
1448 }
1449 else if (info == XLOG_END_OF_RECOVERY)
1450 {
1452
1453 /* Extract wal_level at time record was written from payload. */
1455 record_wal_level = xlrec.wal_level;
1456 }
1457 else
1458 {
1459 /* No special handling required. Return false. */
1460 return false;
1461 }
1462
1463 /*
1464 * Redo can only begin at an XLOG_CHECKPOINT_REDO or
1465 * XLOG_CHECKPOINT_SHUTDOWN record, so we want WAL summarization to begin
1466 * at those points. Hence, when those records are encountered, return
1467 * true, so that we stop just before summarizing either of those records.
1468 *
1469 * We also reach here if we just saw XLOG_END_OF_RECOVERY or
1470 * XLOG_PARAMETER_CHANGE. These are not places where recovery can start,
1471 * but they're still relevant here. A new timeline can begin with
1472 * XLOG_END_OF_RECOVERY, so we need to confirm the WAL level at that
1473 * point; and a restart can provoke XLOG_PARAMETER_CHANGE after an
1474 * intervening change to postgresql.conf, which might force us to stop
1475 * summarizing.
1476 */
1478 return true;
1479}
#define XLOG_CHECKPOINT_REDO
Definition pg_control.h:83
#define XLOG_CHECKPOINT_SHUTDOWN
Definition pg_control.h:69
#define XLOG_PARAMETER_CHANGE
Definition pg_control.h:75
#define XLOG_END_OF_RECOVERY
Definition pg_control.h:78
@ WAL_LEVEL_MINIMAL
Definition xlog.h:75

References fb(), WAL_LEVEL_MINIMAL, XLOG_CHECKPOINT_REDO, XLOG_CHECKPOINT_SHUTDOWN, XLOG_END_OF_RECOVERY, XLOG_PARAMETER_CHANGE, xlogreader, XLogRecGetData, and XLogRecGetInfo.

Referenced by SummarizeWAL().

◆ WaitForWalSummarization()

void WaitForWalSummarization ( XLogRecPtr  lsn)

Definition at line 659 of file walsummarizer.c.

660{
665 int deadcycles = 0;
666
668
669 while (1)
670 {
671 long timeout_in_ms = 10000;
672 XLogRecPtr summarized_lsn;
673 XLogRecPtr pending_lsn;
674
676
677 /* If WAL summarization is disabled while we're waiting, give up. */
678 if (!summarize_wal)
679 return;
680
681 /*
682 * If the LSN summarized on disk has reached the target value, stop.
683 */
685 summarized_lsn = WalSummarizerCtl->summarized_lsn;
686 pending_lsn = WalSummarizerCtl->pending_lsn;
688
689 /* If WAL summarization has progressed sufficiently, stop waiting. */
690 if (summarized_lsn >= lsn)
691 break;
692
693 /* Recheck current time. */
695
696 /* Have we finished the current cycle of waiting? */
699 {
700 long elapsed_seconds;
701
702 /* Begin new wait cycle. */
705
706 /*
707 * Keep track of the number of cycles during which there has been
708 * no progression of pending_lsn. If pending_lsn is not advancing,
709 * that means that not only are no new files appearing on disk,
710 * but we're not even incorporating new records into the in-memory
711 * state.
712 */
713 if (pending_lsn > prior_pending_lsn)
714 {
715 prior_pending_lsn = pending_lsn;
716 deadcycles = 0;
717 }
718 else
719 ++deadcycles;
720
721 /*
722 * If we've managed to wait for an entire minute without the WAL
723 * summarizer absorbing a single WAL record, error out; probably
724 * something is wrong.
725 *
726 * We could consider also erroring out if the summarizer is taking
727 * too long to catch up, but it's not clear what rate of progress
728 * would be acceptable and what would be too slow. So instead, we
729 * just try to error out in the case where there's no progress at
730 * all. That seems likely to catch a reasonable number of the
731 * things that can go wrong in practice (e.g. the summarizer
732 * process is completely hung, say because somebody hooked up a
733 * debugger to it or something) without giving up too quickly when
734 * the system is just slow.
735 */
736 if (deadcycles >= 6)
739 errmsg("WAL summarization is not progressing"),
740 errdetail("Summarization is needed through %X/%08X, but is stuck at %X/%08X on disk and %X/%08X in memory.",
741 LSN_FORMAT_ARGS(lsn),
742 LSN_FORMAT_ARGS(summarized_lsn),
743 LSN_FORMAT_ARGS(pending_lsn))));
744
745
746 /*
747 * Otherwise, just let the user know what's happening.
748 */
751 current_time) / 1000;
754 errmsg_plural("still waiting for WAL summarization through %X/%08X after %ld second",
755 "still waiting for WAL summarization through %X/%08X after %ld seconds",
757 LSN_FORMAT_ARGS(lsn),
759 errdetail("Summarization has reached %X/%08X on disk and %X/%08X in memory.",
760 LSN_FORMAT_ARGS(summarized_lsn),
761 LSN_FORMAT_ARGS(pending_lsn))));
762 }
763
764 /*
765 * Align the wait time to prevent drift. This doesn't really matter,
766 * but we'd like the warnings about how long we've been waiting to say
767 * 10 seconds, 20 seconds, 30 seconds, 40 seconds ... without ever
768 * drifting to something that is not a multiple of ten.
769 */
772
773 /* Wait and see. */
777 }
778
780}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition timestamp.c:1757
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1645
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
int64 TimestampTz
Definition timestamp.h:39
#define WARNING
Definition elog.h:36
int int int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
ConditionVariable summary_file_cv
#define TimestampTzPlusMilliseconds(tz, ms)
Definition timestamp.h:85

References CHECK_FOR_INTERRUPTS, ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), ereport, errcode(), errdetail(), errmsg(), errmsg_plural(), ERROR, fb(), GetCurrentTimestamp(), InvalidXLogRecPtr, LSN_FORMAT_ARGS, LW_SHARED, LWLockAcquire(), LWLockRelease(), WalSummarizerData::pending_lsn, summarize_wal, WalSummarizerData::summarized_lsn, WalSummarizerData::summary_file_cv, TimestampDifferenceMilliseconds(), TimestampTzPlusMilliseconds, WalSummarizerCtl, and WARNING.

Referenced by CleanupAfterArchiveRecovery(), and PrepareForIncrementalBackup().

◆ WakeupWalSummarizer()

void WakeupWalSummarizer ( void  )

Definition at line 636 of file walsummarizer.c.

637{
638 ProcNumber pgprocno;
639
640 if (WalSummarizerCtl == NULL)
641 return;
642
646
647 if (pgprocno != INVALID_PROC_NUMBER)
648 SetLatch(&GetPGProcByNumber(pgprocno)->procLatch);
649}
void SetLatch(Latch *latch)
Definition latch.c:290
int ProcNumber
Definition procnumber.h:24

References fb(), GetPGProcByNumber, INVALID_PROC_NUMBER, LW_SHARED, LWLockAcquire(), LWLockRelease(), SetLatch(), WalSummarizerData::summarizer_pgprocno, and WalSummarizerCtl.

Referenced by CreateCheckPoint().

◆ WalSummarizerMain()

void WalSummarizerMain ( const void startup_data,
size_t  startup_data_len 
)

Definition at line 213 of file walsummarizer.c.

214{
216 MemoryContext context;
217
218 /*
219 * Within this function, 'current_lsn' and 'current_tli' refer to the
220 * point from which the next WAL summary file should start. 'exact' is
221 * true if 'current_lsn' is known to be the start of a WAL record or WAL
222 * segment, and false if it might be in the middle of a record someplace.
223 *
224 * 'switch_lsn' and 'switch_tli', if set, are the LSN at which we need to
225 * switch to a new timeline and the timeline to which we need to switch.
226 * If not set, we either haven't figured out the answers yet or we're
227 * already on the latest timeline.
228 */
231 bool exact;
234
236
238
240 (errmsg_internal("WAL summarizer started")));
241
242 /*
243 * Properly accept or ignore signals the postmaster might send us
244 */
246 pqsignal(SIGINT, SIG_IGN); /* no query to cancel */
248 /* SIGQUIT handler was already set up by InitPostmasterChild */
252 pqsignal(SIGUSR2, SIG_IGN); /* not used */
253
254 /* Advertise ourselves. */
259
260 /* Create and switch to a memory context that we can reset on error. */
262 "Wal Summarizer",
264 MemoryContextSwitchTo(context);
265
266 /*
267 * Reset some signals that are accepted by postmaster but not here
268 */
270
271 /*
272 * If an exception is encountered, processing resumes here.
273 */
274 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
275 {
276 /* Since not using PG_TRY, must reset error stack by hand */
278
279 /* Prevent interrupts while cleaning up */
281
282 /* Report the error to the server log */
284
285 /* Release resources we might have acquired. */
291 AtEOXact_Files(false);
292 AtEOXact_HashTables(false);
293
294 /*
295 * Now return to normal top-level context and clear ErrorContext for
296 * next time.
297 */
298 MemoryContextSwitchTo(context);
300
301 /* Flush any leaked data in the top-level context */
302 MemoryContextReset(context);
303
304 /* Now we can allow interrupts again */
306
307 /*
308 * Sleep for 10 seconds before attempting to resume operations in
309 * order to avoid excessive logging.
310 *
311 * Many of the likely error conditions are things that will repeat
312 * every time. For example, if the WAL can't be read or the summary
313 * can't be written, only administrator action will cure the problem.
314 * So a really fast retry time doesn't seem to be especially
315 * beneficial, and it will clutter the logs.
316 */
319 10000,
321 }
322
323 /* We can now handle ereport(ERROR) */
325
326 /*
327 * Unblock signals (they were blocked when the postmaster forked us)
328 */
330
331 /*
332 * Fetch information about previous progress from shared memory, and ask
333 * GetOldestUnsummarizedLSN to reset pending_lsn to summarized_lsn. We
334 * might be recovering from an error, and if so, pending_lsn might have
335 * advanced past summarized_lsn, but any WAL we read previously has been
336 * lost and will need to be reread.
337 *
338 * If we discover that WAL summarization is not enabled, just exit.
339 */
342 proc_exit(0);
343
344 /*
345 * Loop forever
346 */
347 for (;;)
348 {
352
353 /* Flush any leaked data in the top-level context */
354 MemoryContextReset(context);
355
356 /* Process any signals received recently. */
358
359 /* If it's time to remove any old WAL summaries, do that now. */
361
362 /* Find the LSN and TLI up to which we can safely summarize. */
364
365 /*
366 * If we're summarizing a historic timeline and we haven't yet
367 * computed the point at which to switch to the next timeline, do that
368 * now.
369 *
370 * Note that if this is a standby, what was previously the current
371 * timeline could become historic at any time.
372 *
373 * We could try to make this more efficient by caching the results of
374 * readTimeLineHistory when latest_tli has not changed, but since we
375 * only have to do this once per timeline switch, we probably wouldn't
376 * save any significant amount of work in practice.
377 */
379 {
381
384 errmsg_internal("switch point from TLI %u to TLI %u is at %X/%08X",
386 }
387
388 /*
389 * If we've reached the switch LSN, we can't summarize anything else
390 * on this timeline. Switch to the next timeline and go around again,
391 * backing up to the exact switch point if we passed it.
392 */
394 {
395 /* Restart summarization from switch point. */
398
399 /* Next timeline and switch point, if any, not yet known. */
401 switch_tli = 0;
402
403 /* Update (really, rewind, if needed) state in shared memory. */
410
411 continue;
412 }
413
414 /* Summarize WAL. */
420
421 /*
422 * Update state for next loop iteration.
423 *
424 * Next summary file should start from exactly where this one ended.
425 */
427 exact = true;
428
429 /* Update state in shared memory. */
436
437 /* Wake up anyone waiting for more summary files to be written. */
439 }
440}
void pgaio_error_cleanup(void)
Definition aio.c:1165
void AuxiliaryProcessMainCommon(void)
Definition auxprocess.c:39
sigset_t UnBlockSig
Definition pqsignal.c:22
void ConditionVariableBroadcast(ConditionVariable *cv)
void AtEOXact_HashTables(bool isCommit)
Definition dynahash.c:1931
void EmitErrorReport(void)
Definition elog.c:1882
ErrorContextCallback * error_context_stack
Definition elog.c:99
void FlushErrorState(void)
Definition elog.c:2062
sigjmp_buf * PG_exception_stack
Definition elog.c:101
void AtEOXact_Files(bool isCommit)
Definition fd.c:3213
ProcNumber MyProcNumber
Definition globals.c:90
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
Definition interrupt.c:104
void SignalHandlerForConfigReload(SIGNAL_ARGS)
Definition interrupt.c:61
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
void LWLockReleaseAll(void)
Definition lwlock.c:1892
void MemoryContextReset(MemoryContext context)
Definition mcxt.c:403
MemoryContext TopMemoryContext
Definition mcxt.c:166
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition memutils.h:160
#define RESUME_INTERRUPTS()
Definition miscadmin.h:136
#define HOLD_INTERRUPTS()
Definition miscadmin.h:134
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#define pqsignal
Definition port.h:547
uint64_t Datum
Definition postgres.h:70
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition procsignal.c:679
void ReleaseAuxProcessResources(bool isCommit)
Definition resowner.c:1016
static void pgstat_report_wait_end(void)
Definition wait_event.h:85
static XLogRecPtr SummarizeWAL(TimeLineID tli, XLogRecPtr start_lsn, bool exact, XLogRecPtr switch_lsn, XLogRecPtr maximum_lsn)
static void WalSummarizerShutdown(int code, Datum arg)
static void MaybeRemoveOldWalSummaries(void)
XLogRecPtr GetOldestUnsummarizedLSN(TimeLineID *tli, bool *lsn_is_exact)
#define SIGCHLD
Definition win32_port.h:168
#define SIGHUP
Definition win32_port.h:158
#define SIGPIPE
Definition win32_port.h:163
#define SIGUSR1
Definition win32_port.h:170
#define SIGALRM
Definition win32_port.h:164
#define SIGUSR2
Definition win32_port.h:171

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, AtEOXact_Files(), AtEOXact_HashTables(), AuxiliaryProcessMainCommon(), ConditionVariableBroadcast(), ConditionVariableCancelSleep(), DEBUG1, EmitErrorReport(), ereport, errmsg_internal(), error_context_stack, fb(), FlushErrorState(), GetLatestLSN(), GetOldestUnsummarizedLSN(), HOLD_INTERRUPTS, InvalidXLogRecPtr, LSN_FORMAT_ARGS, WalSummarizerData::lsn_is_exact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LWLockReleaseAll(), MaybeRemoveOldWalSummaries(), MemoryContextReset(), MemoryContextSwitchTo(), MyProcNumber, on_shmem_exit(), WalSummarizerData::pending_lsn, PG_exception_stack, pgaio_error_cleanup(), pgstat_report_wait_end(), pqsignal, proc_exit(), ProcessWalSummarizerInterrupts(), procsignal_sigusr1_handler(), readTimeLineHistory(), ReleaseAuxProcessResources(), RESUME_INTERRUPTS, SIGALRM, SIGCHLD, SIGHUP, SignalHandlerForConfigReload(), SignalHandlerForShutdownRequest(), SIGPIPE, SIGUSR1, SIGUSR2, WalSummarizerData::summarized_lsn, WalSummarizerData::summarized_tli, WalSummarizerData::summarizer_pgprocno, SummarizeWAL(), WalSummarizerData::summary_file_cv, tliSwitchPoint(), TopMemoryContext, UnBlockSig, WaitLatch(), WalSummarizerCtl, WalSummarizerShutdown(), WL_EXIT_ON_PM_DEATH, WL_TIMEOUT, and XLogRecPtrIsValid.

◆ WalSummarizerShmemInit()

void WalSummarizerShmemInit ( void  )

Definition at line 182 of file walsummarizer.c.

183{
184 bool found;
185
187 ShmemInitStruct("Wal Summarizer Ctl", WalSummarizerShmemSize(),
188 &found);
189
190 if (!found)
191 {
192 /*
193 * First time through, so initialize.
194 *
195 * We're just filling in dummy values here -- the real initialization
196 * will happen when GetOldestUnsummarizedLSN() is called for the first
197 * time.
198 */
206 }
207}
void ConditionVariableInit(ConditionVariable *cv)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:378
Size WalSummarizerShmemSize(void)

References ConditionVariableInit(), WalSummarizerData::initialized, INVALID_PROC_NUMBER, InvalidXLogRecPtr, WalSummarizerData::lsn_is_exact, WalSummarizerData::pending_lsn, ShmemInitStruct(), WalSummarizerData::summarized_lsn, WalSummarizerData::summarized_tli, WalSummarizerData::summarizer_pgprocno, WalSummarizerData::summary_file_cv, WalSummarizerCtl, and WalSummarizerShmemSize().

Referenced by CreateOrAttachShmemStructs().

◆ WalSummarizerShmemSize()

Size WalSummarizerShmemSize ( void  )

Definition at line 173 of file walsummarizer.c.

174{
175 return sizeof(WalSummarizerData);
176}

Referenced by CalculateShmemSize(), and WalSummarizerShmemInit().

◆ WalSummarizerShutdown()

Variable Documentation

◆ pages_read_since_last_sleep

long pages_read_since_last_sleep = 0
static

Definition at line 134 of file walsummarizer.c.

Referenced by summarizer_read_local_xlog_page(), and summarizer_wait_for_wal().

◆ redo_pointer_at_last_summary_removal

XLogRecPtr redo_pointer_at_last_summary_removal = InvalidXLogRecPtr
static

Definition at line 139 of file walsummarizer.c.

Referenced by MaybeRemoveOldWalSummaries().

◆ sleep_quanta

long sleep_quanta = 1
static

Definition at line 117 of file walsummarizer.c.

Referenced by summarizer_wait_for_wal().

◆ summarize_wal

◆ wal_summary_keep_time

int wal_summary_keep_time = 10 * HOURS_PER_DAY * MINS_PER_HOUR

Definition at line 145 of file walsummarizer.c.

Referenced by MaybeRemoveOldWalSummaries().

◆ WalSummarizerCtl