PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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/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 126 of file walsummarizer.c.

◆ MS_PER_SLEEP_QUANTUM

#define MS_PER_SLEEP_QUANTUM   200

Definition at line 127 of file walsummarizer.c.

Function Documentation

◆ GetLatestLSN()

static XLogRecPtr GetLatestLSN ( TimeLineID tli)
static

Definition at line 801 of file walsummarizer.c.

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

References 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 506 of file walsummarizer.c.

507{
508 TimeLineID latest_tli;
509 int n;
510 List *tles;
511 XLogRecPtr unsummarized_lsn = InvalidXLogRecPtr;
512 TimeLineID unsummarized_tli = 0;
513 bool should_make_exact = false;
514 List *existing_summaries;
515 ListCell *lc;
516 bool am_wal_summarizer = AmWalSummarizerProcess();
517
518 /* If not summarizing WAL, do nothing. */
519 if (!summarize_wal)
520 return InvalidXLogRecPtr;
521
522 /*
523 * If we are not the WAL summarizer process, then we normally just want to
524 * read the values from shared memory. However, as an exception, if shared
525 * memory hasn't been initialized yet, then we need to do that so that we
526 * can read legal values and not remove any WAL too early.
527 */
528 if (!am_wal_summarizer)
529 {
530 LWLockAcquire(WALSummarizerLock, LW_SHARED);
531
533 {
534 unsummarized_lsn = WalSummarizerCtl->summarized_lsn;
535 if (tli != NULL)
537 if (lsn_is_exact != NULL)
538 *lsn_is_exact = WalSummarizerCtl->lsn_is_exact;
539 LWLockRelease(WALSummarizerLock);
540 return unsummarized_lsn;
541 }
542
543 LWLockRelease(WALSummarizerLock);
544 }
545
546 /*
547 * Find the oldest timeline on which WAL still exists, and the earliest
548 * segment for which it exists.
549 *
550 * Note that we do this every time the WAL summarizer process restarts or
551 * recovers from an error, in case the contents of pg_wal have changed
552 * under us e.g. if some files were removed, either manually - which
553 * shouldn't really happen, but might - or by postgres itself, if
554 * summarize_wal was turned off and then back on again.
555 */
556 (void) GetLatestLSN(&latest_tli);
557 tles = readTimeLineHistory(latest_tli);
558 for (n = list_length(tles) - 1; n >= 0; --n)
559 {
560 TimeLineHistoryEntry *tle = list_nth(tles, n);
561 XLogSegNo oldest_segno;
562
563 oldest_segno = XLogGetOldestSegno(tle->tli);
564 if (oldest_segno != 0)
565 {
566 /* Compute oldest LSN that still exists on disk. */
568 unsummarized_lsn);
569
570 unsummarized_tli = tle->tli;
571 break;
572 }
573 }
574
575 /*
576 * Don't try to summarize anything older than the end LSN of the newest
577 * summary file that exists for this timeline.
578 */
579 existing_summaries =
580 GetWalSummaries(unsummarized_tli,
582 foreach(lc, existing_summaries)
583 {
584 WalSummaryFile *ws = lfirst(lc);
585
586 if (ws->end_lsn > unsummarized_lsn)
587 {
588 unsummarized_lsn = ws->end_lsn;
589 should_make_exact = true;
590 }
591 }
592
593 /* It really should not be possible for us to find no WAL. */
594 if (unsummarized_tli == 0)
596 errcode(ERRCODE_INTERNAL_ERROR),
597 errmsg_internal("no WAL found on timeline %u", latest_tli));
598
599 /*
600 * If we're the WAL summarizer, we always want to store the values we just
601 * computed into shared memory, because those are the values we're going
602 * to use to drive our operation, and so they are the authoritative
603 * values. Otherwise, we only store values into shared memory if shared
604 * memory is uninitialized. Our values are not canonical in such a case,
605 * but it's better to have something than nothing, to guide WAL retention.
606 */
607 LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
608 if (am_wal_summarizer || !WalSummarizerCtl->initialized)
609 {
611 WalSummarizerCtl->summarized_lsn = unsummarized_lsn;
612 WalSummarizerCtl->summarized_tli = unsummarized_tli;
613 WalSummarizerCtl->lsn_is_exact = should_make_exact;
614 WalSummarizerCtl->pending_lsn = unsummarized_lsn;
615 }
616 else
617 unsummarized_lsn = WalSummarizerCtl->summarized_lsn;
618
619 /* Also return the to the caller as required. */
620 if (tli != NULL)
622 if (lsn_is_exact != NULL)
623 *lsn_is_exact = WalSummarizerCtl->lsn_is_exact;
624 LWLockRelease(WALSummarizerLock);
625
626 return unsummarized_lsn;
627}
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:76
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode(int sqlerrcode)
Definition: elog.c:853
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1179
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1899
@ LW_SHARED
Definition: lwlock.h:115
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define AmWalSummarizerProcess()
Definition: miscadmin.h:390
#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
TimeLineID tli
Definition: timeline.h:27
XLogRecPtr summarized_lsn
Definition: walsummarizer.c:85
TimeLineID summarized_tli
Definition: walsummarizer.c:84
XLogRecPtr pending_lsn
Definition: walsummarizer.c:88
XLogRecPtr end_lsn
Definition: walsummary.h:30
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:143
XLogSegNo XLogGetOldestSegno(TimeLineID tli)
Definition: xlog.c:3780
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
uint64 XLogSegNo
Definition: xlogdefs.h:48

References AmWalSummarizerProcess, WalSummaryFile::end_lsn, ereport, errcode(), errmsg_internal(), ERROR, 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, TimeLineHistoryEntry::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 448 of file walsummarizer.c.

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

References 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 1658 of file walsummarizer.c.

1659{
1660 XLogRecPtr redo_pointer = GetRedoRecPtr();
1661 List *wslist;
1662 time_t cutoff_time;
1663
1664 /* If WAL summary removal is disabled, don't do anything. */
1665 if (wal_summary_keep_time == 0)
1666 return;
1667
1668 /*
1669 * If the redo pointer has not advanced, don't do anything.
1670 *
1671 * This has the effect that we only try to remove old WAL summary files
1672 * once per checkpoint cycle.
1673 */
1674 if (redo_pointer == redo_pointer_at_last_summary_removal)
1675 return;
1677
1678 /*
1679 * Files should only be removed if the last modification time precedes the
1680 * cutoff time we compute here.
1681 */
1682 cutoff_time = time(NULL) - wal_summary_keep_time * SECS_PER_MINUTE;
1683
1684 /* Get all the summaries that currently exist. */
1686
1687 /* Loop until all summaries have been considered for removal. */
1688 while (wslist != NIL)
1689 {
1690 ListCell *lc;
1691 XLogSegNo oldest_segno;
1692 XLogRecPtr oldest_lsn = InvalidXLogRecPtr;
1693 TimeLineID selected_tli;
1694
1696
1697 /*
1698 * Pick a timeline for which some summary files still exist on disk,
1699 * and find the oldest LSN that still exists on disk for that
1700 * timeline.
1701 */
1702 selected_tli = ((WalSummaryFile *) linitial(wslist))->tli;
1703 oldest_segno = XLogGetOldestSegno(selected_tli);
1704 if (oldest_segno != 0)
1706 oldest_lsn);
1707
1708
1709 /* Consider each WAL file on the selected timeline in turn. */
1710 foreach(lc, wslist)
1711 {
1712 WalSummaryFile *ws = lfirst(lc);
1713
1715
1716 /* If it's not on this timeline, it's not time to consider it. */
1717 if (selected_tli != ws->tli)
1718 continue;
1719
1720 /*
1721 * If the WAL doesn't exist any more, we can remove it if the file
1722 * modification time is old enough.
1723 */
1724 if (XLogRecPtrIsInvalid(oldest_lsn) || ws->end_lsn <= oldest_lsn)
1725 RemoveWalSummaryIfOlderThan(ws, cutoff_time);
1726
1727 /*
1728 * Whether we removed the file or not, we need not consider it
1729 * again.
1730 */
1731 wslist = foreach_delete_current(wslist, lc);
1732 pfree(ws);
1733 }
1734 }
1735}
#define SECS_PER_MINUTE
Definition: timestamp.h:128
void pfree(void *pointer)
Definition: mcxt.c:1524
#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
TimeLineID tli
Definition: walsummary.h:31
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:6483
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References WalSummaryFile::end_lsn, foreach_delete_current, GetRedoRecPtr(), GetWalSummaries(), InvalidXLogRecPtr, lfirst, linitial, NIL, pfree(), ProcessWalSummarizerInterrupts(), redo_pointer_at_last_summary_removal, RemoveWalSummaryIfOlderThan(), SECS_PER_MINUTE, WalSummaryFile::tli, wal_segment_size, wal_summary_keep_time, XLogGetOldestSegno(), XLogRecPtrIsInvalid, and XLogSegNoOffsetToRecPtr.

Referenced by WalSummarizerMain().

◆ ProcessWalSummarizerInterrupts()

static void ProcessWalSummarizerInterrupts ( void  )
static

Definition at line 859 of file walsummarizer.c.

860{
863
865 {
866 ConfigReloadPending = false;
868 }
869
871 {
873 errmsg_internal("WAL summarizer shutting down"));
874 proc_exit(0);
875 }
876
877 /* Perform logging of memory contexts of this process */
880}
#define DEBUG1
Definition: elog.h:30
volatile sig_atomic_t LogMemoryContextPending
Definition: globals.c:40
volatile sig_atomic_t ProcSignalBarrierPending
Definition: globals.c:39
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:104
void ProcessLogMemoryContextInterrupt(void)
Definition: mcxt.c:1289
void ProcessProcSignalBarrier(void)
Definition: procsignal.c:498

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 1247 of file walsummarizer.c.

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

References BlockRefTableSetLimitBlock(), xl_dbase_create_file_copy_rec::db_id, xl_dbase_create_wal_log_rec::db_id, xl_dbase_drop_rec::db_id, RelFileLocator::dbOid, i, MAIN_FORKNUM, xl_dbase_drop_rec::ntablespaces, RelFileLocator::relNumber, RelFileLocator::spcOid, xl_dbase_create_file_copy_rec::tablespace_id, xl_dbase_create_wal_log_rec::tablespace_id, xl_dbase_drop_rec::tablespace_ids, 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 1498 of file walsummarizer.c.

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

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

Referenced by SummarizeWAL().

◆ summarizer_wait_for_wal()

static void summarizer_wait_for_wal ( void  )
static

Definition at line 1612 of file walsummarizer.c.

1613{
1615 {
1616 /*
1617 * No pages were read since the last sleep, so double the sleep time,
1618 * but not beyond the maximum allowable value.
1619 */
1621 }
1622 else if (pages_read_since_last_sleep > 1)
1623 {
1624 /*
1625 * Multiple pages were read since the last sleep, so reduce the sleep
1626 * time.
1627 *
1628 * A large burst of activity should be able to quickly reduce the
1629 * sleep time to the minimum, but we don't want a handful of extra WAL
1630 * records to provoke a strong reaction. We choose to reduce the sleep
1631 * time by 1 quantum for each page read beyond the first, which is a
1632 * fairly arbitrary way of trying to be reactive without overreacting.
1633 */
1635 sleep_quanta = 1;
1636 else
1638 }
1639
1640 /* Report pending statistics to the cumulative stats system. */
1641 pgstat_report_wal(false);
1642
1643 /* OK, now sleep. */
1644 (void) WaitLatch(MyLatch,
1647 WAIT_EVENT_WAL_SUMMARIZER_WAL);
1649
1650 /* Reset count of pages read. */
1652}
#define Min(x, y)
Definition: c.h:975
struct Latch * MyLatch
Definition: globals.c:62
void ResetLatch(Latch *latch)
Definition: latch.c:372
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
Definition: waiteventset.h:37
#define WL_EXIT_ON_PM_DEATH
Definition: waiteventset.h:39
#define WL_LATCH_SET
Definition: waiteventset.h:34
#define MAX_SLEEP_QUANTA
#define MS_PER_SLEEP_QUANTUM
static long sleep_quanta

References 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 1316 of file walsummarizer.c.

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

References xl_smgr_truncate::blkno, BlockRefTableSetLimitBlock(), xl_smgr_truncate::flags, xl_smgr_create::forkNum, FSM_FORKNUM, MAIN_FORKNUM, xl_smgr_create::rlocator, xl_smgr_truncate::rlocator, 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 907 of file walsummarizer.c.

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

Referenced by WalSummarizerMain().

◆ SummarizeXactRecord()

static void SummarizeXactRecord ( XLogReaderState xlogreader,
BlockRefTable brtab 
)
static

Definition at line 1365 of file walsummarizer.c.

1366{
1367 uint8 info = XLogRecGetInfo(xlogreader) & ~XLR_INFO_MASK;
1368 uint8 xact_info = info & XLOG_XACT_OPMASK;
1369
1370 if (xact_info == XLOG_XACT_COMMIT ||
1371 xact_info == XLOG_XACT_COMMIT_PREPARED)
1372 {
1374 xl_xact_parsed_commit parsed;
1375 int i;
1376
1377 /*
1378 * Don't track modified blocks for any relations that were removed on
1379 * commit.
1380 */
1382 for (i = 0; i < parsed.nrels; ++i)
1383 {
1384 ForkNumber forknum;
1385
1386 for (forknum = 0; forknum <= MAX_FORKNUM; ++forknum)
1387 if (forknum != FSM_FORKNUM)
1388 BlockRefTableSetLimitBlock(brtab, &parsed.xlocators[i],
1389 forknum, 0);
1390 }
1391 }
1392 else if (xact_info == XLOG_XACT_ABORT ||
1393 xact_info == XLOG_XACT_ABORT_PREPARED)
1394 {
1396 xl_xact_parsed_abort parsed;
1397 int i;
1398
1399 /*
1400 * Don't track modified blocks for any relations that were removed on
1401 * abort.
1402 */
1403 ParseAbortRecord(XLogRecGetInfo(xlogreader), xlrec, &parsed);
1404 for (i = 0; i < parsed.nrels; ++i)
1405 {
1406 ForkNumber forknum;
1407
1408 for (forknum = 0; forknum <= MAX_FORKNUM; ++forknum)
1409 if (forknum != FSM_FORKNUM)
1410 BlockRefTableSetLimitBlock(brtab, &parsed.xlocators[i],
1411 forknum, 0);
1412 }
1413 }
1414}
#define MAX_FORKNUM
Definition: relpath.h:70
RelFileLocator * xlocators
Definition: xact.h:422
RelFileLocator * xlocators
Definition: xact.h:389
#define XLOG_XACT_COMMIT_PREPARED
Definition: xact.h:172
#define XLOG_XACT_COMMIT
Definition: xact.h:169
#define XLOG_XACT_OPMASK
Definition: xact.h:179
#define XLOG_XACT_ABORT
Definition: xact.h:171
#define XLOG_XACT_ABORT_PREPARED
Definition: xact.h:173
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(), FSM_FORKNUM, i, MAX_FORKNUM, xl_xact_parsed_commit::nrels, xl_xact_parsed_abort::nrels, ParseAbortRecord(), ParseCommitRecord(), xl_xact_parsed_commit::xlocators, xl_xact_parsed_abort::xlocators, 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 1425 of file walsummarizer.c.

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

References xl_parameter_change::wal_level, xl_end_of_recovery::wal_level, CheckPoint::wal_level, 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 661 of file walsummarizer.c.

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

References CHECK_FOR_INTERRUPTS, ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), ereport, errcode(), errdetail(), errmsg(), errmsg_plural(), ERROR, GetCurrentTimestamp(), InvalidXLogRecPtr, LSN_FORMAT_ARGS, LW_EXCLUSIVE, 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 638 of file walsummarizer.c.

639{
640 ProcNumber pgprocno;
641
642 if (WalSummarizerCtl == NULL)
643 return;
644
645 LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
647 LWLockRelease(WALSummarizerLock);
648
649 if (pgprocno != INVALID_PROC_NUMBER)
651}
void SetLatch(Latch *latch)
Definition: latch.c:288
int ProcNumber
Definition: procnumber.h:24
PROC_HDR * ProcGlobal
Definition: proc.c:78
Latch procLatch
Definition: proc.h:170
PGPROC * allProcs
Definition: proc.h:372

References PROC_HDR::allProcs, INVALID_PROC_NUMBER, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcGlobal, PGPROC::procLatch, SetLatch(), WalSummarizerData::summarizer_pgprocno, and WalSummarizerCtl.

Referenced by CreateCheckPoint().

◆ WalSummarizerMain()

void WalSummarizerMain ( const void *  startup_data,
size_t  startup_data_len 
)

Definition at line 212 of file walsummarizer.c.

213{
214 sigjmp_buf local_sigjmp_buf;
215 MemoryContext context;
216
217 /*
218 * Within this function, 'current_lsn' and 'current_tli' refer to the
219 * point from which the next WAL summary file should start. 'exact' is
220 * true if 'current_lsn' is known to be the start of a WAL record or WAL
221 * segment, and false if it might be in the middle of a record someplace.
222 *
223 * 'switch_lsn' and 'switch_tli', if set, are the LSN at which we need to
224 * switch to a new timeline and the timeline to which we need to switch.
225 * If not set, we either haven't figured out the answers yet or we're
226 * already on the latest timeline.
227 */
228 XLogRecPtr current_lsn;
229 TimeLineID current_tli;
230 bool exact;
231 XLogRecPtr switch_lsn = InvalidXLogRecPtr;
232 TimeLineID switch_tli = 0;
233
234 Assert(startup_data_len == 0);
235
238
240 (errmsg_internal("WAL summarizer started")));
241
242 /*
243 * Properly accept or ignore signals the postmaster might send us
244 *
245 * We have no particular use for SIGINT at the moment, but seems
246 * reasonable to treat like SIGTERM.
247 */
251 /* SIGQUIT handler was already set up by InitPostmasterChild */
252 pqsignal(SIGALRM, SIG_IGN);
253 pqsignal(SIGPIPE, SIG_IGN);
255 pqsignal(SIGUSR2, SIG_IGN); /* not used */
256
257 /* Advertise ourselves. */
259 LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
261 LWLockRelease(WALSummarizerLock);
262
263 /* Create and switch to a memory context that we can reset on error. */
265 "Wal Summarizer",
267 MemoryContextSwitchTo(context);
268
269 /*
270 * Reset some signals that are accepted by postmaster but not here
271 */
272 pqsignal(SIGCHLD, SIG_DFL);
273
274 /*
275 * If an exception is encountered, processing resumes here.
276 */
277 if (sigsetjmp(local_sigjmp_buf, 1) != 0)
278 {
279 /* Since not using PG_TRY, must reset error stack by hand */
280 error_context_stack = NULL;
281
282 /* Prevent interrupts while cleaning up */
284
285 /* Report the error to the server log */
287
288 /* Release resources we might have acquired. */
293 AtEOXact_Files(false);
294 AtEOXact_HashTables(false);
295
296 /*
297 * Now return to normal top-level context and clear ErrorContext for
298 * next time.
299 */
300 MemoryContextSwitchTo(context);
302
303 /* Flush any leaked data in the top-level context */
304 MemoryContextReset(context);
305
306 /* Now we can allow interrupts again */
308
309 /*
310 * Sleep for 10 seconds before attempting to resume operations in
311 * order to avoid excessive logging.
312 *
313 * Many of the likely error conditions are things that will repeat
314 * every time. For example, if the WAL can't be read or the summary
315 * can't be written, only administrator action will cure the problem.
316 * So a really fast retry time doesn't seem to be especially
317 * beneficial, and it will clutter the logs.
318 */
319 (void) WaitLatch(NULL,
321 10000,
322 WAIT_EVENT_WAL_SUMMARIZER_ERROR);
323 }
324
325 /* We can now handle ereport(ERROR) */
326 PG_exception_stack = &local_sigjmp_buf;
327
328 /*
329 * Unblock signals (they were blocked when the postmaster forked us)
330 */
331 sigprocmask(SIG_SETMASK, &UnBlockSig, NULL);
332
333 /*
334 * Fetch information about previous progress from shared memory, and ask
335 * GetOldestUnsummarizedLSN to reset pending_lsn to summarized_lsn. We
336 * might be recovering from an error, and if so, pending_lsn might have
337 * advanced past summarized_lsn, but any WAL we read previously has been
338 * lost and will need to be reread.
339 *
340 * If we discover that WAL summarization is not enabled, just exit.
341 */
342 current_lsn = GetOldestUnsummarizedLSN(&current_tli, &exact);
343 if (XLogRecPtrIsInvalid(current_lsn))
344 proc_exit(0);
345
346 /*
347 * Loop forever
348 */
349 for (;;)
350 {
351 XLogRecPtr latest_lsn;
352 TimeLineID latest_tli;
353 XLogRecPtr end_of_summary_lsn;
354
355 /* Flush any leaked data in the top-level context */
356 MemoryContextReset(context);
357
358 /* Process any signals received recently. */
360
361 /* If it's time to remove any old WAL summaries, do that now. */
363
364 /* Find the LSN and TLI up to which we can safely summarize. */
365 latest_lsn = GetLatestLSN(&latest_tli);
366
367 /*
368 * If we're summarizing a historic timeline and we haven't yet
369 * computed the point at which to switch to the next timeline, do that
370 * now.
371 *
372 * Note that if this is a standby, what was previously the current
373 * timeline could become historic at any time.
374 *
375 * We could try to make this more efficient by caching the results of
376 * readTimeLineHistory when latest_tli has not changed, but since we
377 * only have to do this once per timeline switch, we probably wouldn't
378 * save any significant amount of work in practice.
379 */
380 if (current_tli != latest_tli && XLogRecPtrIsInvalid(switch_lsn))
381 {
382 List *tles = readTimeLineHistory(latest_tli);
383
384 switch_lsn = tliSwitchPoint(current_tli, tles, &switch_tli);
386 errmsg_internal("switch point from TLI %u to TLI %u is at %X/%X",
387 current_tli, switch_tli, LSN_FORMAT_ARGS(switch_lsn)));
388 }
389
390 /*
391 * If we've reached the switch LSN, we can't summarize anything else
392 * on this timeline. Switch to the next timeline and go around again,
393 * backing up to the exact switch point if we passed it.
394 */
395 if (!XLogRecPtrIsInvalid(switch_lsn) && current_lsn >= switch_lsn)
396 {
397 /* Restart summarization from switch point. */
398 current_tli = switch_tli;
399 current_lsn = switch_lsn;
400
401 /* Next timeline and switch point, if any, not yet known. */
402 switch_lsn = InvalidXLogRecPtr;
403 switch_tli = 0;
404
405 /* Update (really, rewind, if needed) state in shared memory. */
406 LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
407 WalSummarizerCtl->summarized_lsn = current_lsn;
408 WalSummarizerCtl->summarized_tli = current_tli;
410 WalSummarizerCtl->pending_lsn = current_lsn;
411 LWLockRelease(WALSummarizerLock);
412
413 continue;
414 }
415
416 /* Summarize WAL. */
417 end_of_summary_lsn = SummarizeWAL(current_tli,
418 current_lsn, exact,
419 switch_lsn, latest_lsn);
420 Assert(!XLogRecPtrIsInvalid(end_of_summary_lsn));
421 Assert(end_of_summary_lsn >= current_lsn);
422
423 /*
424 * Update state for next loop iteration.
425 *
426 * Next summary file should start from exactly where this one ended.
427 */
428 current_lsn = end_of_summary_lsn;
429 exact = true;
430
431 /* Update state in shared memory. */
432 LWLockAcquire(WALSummarizerLock, LW_EXCLUSIVE);
433 WalSummarizerCtl->summarized_lsn = end_of_summary_lsn;
434 WalSummarizerCtl->summarized_tli = current_tli;
436 WalSummarizerCtl->pending_lsn = end_of_summary_lsn;
437 LWLockRelease(WALSummarizerLock);
438
439 /* Wake up anyone waiting for more summary files to be written. */
441 }
442}
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:1912
void EmitErrorReport(void)
Definition: elog.c:1687
ErrorContextCallback * error_context_stack
Definition: elog.c:94
void FlushErrorState(void)
Definition: elog.c:1867
sigjmp_buf * PG_exception_stack
Definition: elog.c:96
void AtEOXact_Files(bool isCommit)
Definition: fd.c:3187
ProcNumber MyProcNumber
Definition: globals.c:89
void SignalHandlerForShutdownRequest(SIGNAL_ARGS)
Definition: interrupt.c:105
void SignalHandlerForConfigReload(SIGNAL_ARGS)
Definition: interrupt.c:61
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
void LWLockReleaseAll(void)
Definition: lwlock.c:1950
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:135
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:133
@ B_WAL_SUMMARIZER
Definition: miscadmin.h:365
BackendType MyBackendType
Definition: miscinit.c:64
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define pqsignal
Definition: port.h:521
uintptr_t Datum
Definition: postgres.h:69
void procsignal_sigusr1_handler(SIGNAL_ARGS)
Definition: procsignal.c:673
void ReleaseAuxProcessResources(bool isCommit)
Definition: resowner.c:1002
static void pgstat_report_wait_end(void)
Definition: wait_event.h:101
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(), B_WAL_SUMMARIZER, ConditionVariableBroadcast(), ConditionVariableCancelSleep(), DEBUG1, EmitErrorReport(), ereport, errmsg_internal(), error_context_stack, FlushErrorState(), GetLatestLSN(), GetOldestUnsummarizedLSN(), HOLD_INTERRUPTS, InvalidXLogRecPtr, LSN_FORMAT_ARGS, WalSummarizerData::lsn_is_exact, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), LWLockReleaseAll(), MaybeRemoveOldWalSummaries(), MemoryContextReset(), MemoryContextSwitchTo(), MyBackendType, MyProcNumber, on_shmem_exit(), WalSummarizerData::pending_lsn, PG_exception_stack, 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 XLogRecPtrIsInvalid.

◆ WalSummarizerShmemInit()

void WalSummarizerShmemInit ( void  )

Definition at line 181 of file walsummarizer.c.

182{
183 bool found;
184
186 ShmemInitStruct("Wal Summarizer Ctl", WalSummarizerShmemSize(),
187 &found);
188
189 if (!found)
190 {
191 /*
192 * First time through, so initialize.
193 *
194 * We're just filling in dummy values here -- the real initialization
195 * will happen when GetOldestUnsummarizedLSN() is called for the first
196 * time.
197 */
205 }
206}
void ConditionVariableInit(ConditionVariable *cv)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
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 172 of file walsummarizer.c.

173{
174 return sizeof(WalSummarizerData);
175}

Referenced by CalculateShmemSize(), and WalSummarizerShmemInit().

◆ WalSummarizerShutdown()

static void WalSummarizerShutdown ( int  code,
Datum  arg 
)
static

Variable Documentation

◆ pages_read_since_last_sleep

long pages_read_since_last_sleep = 0
static

Definition at line 133 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 138 of file walsummarizer.c.

Referenced by MaybeRemoveOldWalSummaries().

◆ sleep_quanta

long sleep_quanta = 1
static

Definition at line 116 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 144 of file walsummarizer.c.

Referenced by MaybeRemoveOldWalSummaries().

◆ WalSummarizerCtl