1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

Add WAL consistency checking facility.

When the new GUC wal_consistency_checking is set to a non-empty value,
it triggers recording of additional full-page images, which are
compared on the standby against the results of applying the WAL record
(without regard to those full-page images).  Allowable differences
such as hints are masked out, and the resulting pages are compared;
any difference results in a FATAL error on the standby.

Kuntal Ghosh, based on earlier patches by Michael Paquier and Heikki
Linnakangas.  Extensively reviewed and revised by Michael Paquier and
by me, with additional reviews and comments from Amit Kapila, Álvaro
Herrera, Simon Riggs, and Peter Eisentraut.
This commit is contained in:
Robert Haas
2017-02-08 15:45:30 -05:00
parent 115cb31597
commit a507b86900
36 changed files with 811 additions and 48 deletions

View File

@@ -12,7 +12,7 @@ subdir = src/backend/access/common
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = heaptuple.o indextuple.o printsimple.o printtup.o reloptions.o \
scankey.o tupconvert.o tupdesc.o
OBJS = bufmask.o heaptuple.o indextuple.o printsimple.o printtup.o \
reloptions.o scankey.o tupconvert.o tupdesc.o
include $(top_srcdir)/src/backend/common.mk

View File

@@ -0,0 +1,128 @@
/*-------------------------------------------------------------------------
*
* bufmask.c
* Routines for buffer masking. Used to mask certain bits
* in a page which can be different when the WAL is generated
* and when the WAL is applied.
*
* Portions Copyright (c) 2016, PostgreSQL Global Development Group
*
* Contains common routines required for masking a page.
*
* IDENTIFICATION
* src/backend/storage/buffer/bufmask.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/bufmask.h"
/*
* mask_page_lsn
*
* In consistency checks, the LSN of the two pages compared will likely be
* different because of concurrent operations when the WAL is generated
* and the state of the page when WAL is applied.
*/
void
mask_page_lsn(Page page)
{
PageHeader phdr = (PageHeader) page;
PageXLogRecPtrSet(phdr->pd_lsn, (uint64) MASK_MARKER);
}
/*
* mask_page_hint_bits
*
* Mask hint bits in PageHeader. We want to ignore differences in hint bits,
* since they can be set without emitting any WAL.
*/
void
mask_page_hint_bits(Page page)
{
PageHeader phdr = (PageHeader) page;
/* Ignore prune_xid (it's like a hint-bit) */
phdr->pd_prune_xid = MASK_MARKER;
/* Ignore PD_PAGE_FULL and PD_HAS_FREE_LINES flags, they are just hints. */
PageClearFull(page);
PageClearHasFreeLinePointers(page);
/*
* During replay, if the page LSN has advanced past our XLOG record's LSN,
* we don't mark the page all-visible. See heap_xlog_visible() for
* details.
*/
PageClearAllVisible(page);
}
/*
* mask_unused_space
*
* Mask the unused space of a page between pd_lower and pd_upper.
*/
void
mask_unused_space(Page page)
{
int pd_lower = ((PageHeader) page)->pd_lower;
int pd_upper = ((PageHeader) page)->pd_upper;
int pd_special = ((PageHeader) page)->pd_special;
/* Sanity check */
if (pd_lower > pd_upper || pd_special < pd_upper ||
pd_lower < SizeOfPageHeaderData || pd_special > BLCKSZ)
{
elog(ERROR, "invalid page pd_lower %u pd_upper %u pd_special %u\n",
pd_lower, pd_upper, pd_special);
}
memset(page + pd_lower, MASK_MARKER, pd_upper - pd_lower);
}
/*
* mask_lp_flags
*
* In some index AMs, line pointer flags can be modified in master without
* emitting any WAL record.
*/
void
mask_lp_flags(Page page)
{
OffsetNumber offnum,
maxoff;
maxoff = PageGetMaxOffsetNumber(page);
for (offnum = FirstOffsetNumber;
offnum <= maxoff;
offnum = OffsetNumberNext(offnum))
{
ItemId itemId = PageGetItemId(page, offnum);
if (ItemIdIsUsed(itemId))
itemId->lp_flags = LP_UNUSED;
}
}
/*
* mask_page_content
*
* In some index AMs, the contents of deleted pages need to be almost
* completely ignored.
*/
void
mask_page_content(Page page)
{
/* Mask Page Content */
memset(page + SizeOfPageHeaderData, MASK_MARKER,
BLCKSZ - SizeOfPageHeaderData);
/* Mask pd_lower and pd_upper */
memset(&((PageHeader) page)->pd_lower, MASK_MARKER,
sizeof(uint16));
memset(&((PageHeader) page)->pd_upper, MASK_MARKER,
sizeof(uint16));
}