mirror of
https://github.com/postgres/postgres.git
synced 2025-07-05 07:21:24 +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:
@ -38,6 +38,7 @@
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/bufmask.h"
|
||||
#include "access/heapam.h"
|
||||
#include "access/heapam_xlog.h"
|
||||
#include "access/hio.h"
|
||||
@ -9142,3 +9143,81 @@ heap_sync(Relation rel)
|
||||
heap_close(toastrel, AccessShareLock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mask a heap page before performing consistency checks on it.
|
||||
*/
|
||||
void
|
||||
heap_mask(char *pagedata, BlockNumber blkno)
|
||||
{
|
||||
Page page = (Page) pagedata;
|
||||
OffsetNumber off;
|
||||
|
||||
mask_page_lsn(page);
|
||||
|
||||
mask_page_hint_bits(page);
|
||||
mask_unused_space(page);
|
||||
|
||||
for (off = 1; off <= PageGetMaxOffsetNumber(page); off++)
|
||||
{
|
||||
ItemId iid = PageGetItemId(page, off);
|
||||
char *page_item;
|
||||
|
||||
page_item = (char *) (page + ItemIdGetOffset(iid));
|
||||
|
||||
if (ItemIdIsNormal(iid))
|
||||
{
|
||||
|
||||
HeapTupleHeader page_htup = (HeapTupleHeader) page_item;
|
||||
|
||||
/*
|
||||
* If xmin of a tuple is not yet frozen, we should ignore
|
||||
* differences in hint bits, since they can be set without
|
||||
* emitting WAL.
|
||||
*/
|
||||
if (!HeapTupleHeaderXminFrozen(page_htup))
|
||||
page_htup->t_infomask &= ~HEAP_XACT_MASK;
|
||||
else
|
||||
{
|
||||
/* Still we need to mask xmax hint bits. */
|
||||
page_htup->t_infomask &= ~HEAP_XMAX_INVALID;
|
||||
page_htup->t_infomask &= ~HEAP_XMAX_COMMITTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* During replay, we set Command Id to FirstCommandId. Hence, mask
|
||||
* it. See heap_xlog_insert() for details.
|
||||
*/
|
||||
page_htup->t_choice.t_heap.t_field3.t_cid = MASK_MARKER;
|
||||
|
||||
/*
|
||||
* For a speculative tuple, heap_insert() does not set ctid in the
|
||||
* caller-passed heap tuple itself, leaving the ctid field to
|
||||
* contain a speculative token value - a per-backend monotonically
|
||||
* increasing identifier. Besides, it does not WAL-log ctid under
|
||||
* any circumstances.
|
||||
*
|
||||
* During redo, heap_xlog_insert() sets t_ctid to current block
|
||||
* number and self offset number. It doesn't care about any
|
||||
* speculative insertions in master. Hence, we set t_ctid to
|
||||
* current block number and self offset number to ignore any
|
||||
* inconsistency.
|
||||
*/
|
||||
if (HeapTupleHeaderIsSpeculative(page_htup))
|
||||
ItemPointerSet(&page_htup->t_ctid, blkno, off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore any padding bytes after the tuple, when the length of the
|
||||
* item is not MAXALIGNed.
|
||||
*/
|
||||
if (ItemIdHasStorage(iid))
|
||||
{
|
||||
int len = ItemIdGetLength(iid);
|
||||
int padlen = MAXALIGN(len) - len;
|
||||
|
||||
if (padlen > 0)
|
||||
memset(page_item + len, MASK_MARKER, padlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user