1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-25 20:23:07 +03:00

Standardize rmgrdesc recovery conflict XID output.

Standardize on the name snapshotConflictHorizon for all XID fields from
WAL records that generate recovery conflicts when in hot standby mode.
This supersedes the previous latestRemovedXid naming convention.

The new naming convention places emphasis on how the values are actually
used by REDO routines.  How the values are generated during original
execution (details of which vary by record type) is deemphasized.  Users
of tools like pg_waldump can now grep for snapshotConflictHorizon to see
all potential sources of recovery conflicts in a standardized way,
without necessarily having to consider which specific record types might
be involved.

Also bring a couple of WAL record types that didn't follow any kind of
naming convention into line.  These are heapam's VISIBLE record type and
SP-GiST's VACUUM_REDIRECT record type.  Now every WAL record whose REDO
routine calls ResolveRecoveryConflictWithSnapshot() passes through the
snapshotConflictHorizon field from its WAL record.  This is follow-up
work to the refactoring from commit 9e540599 that made FREEZE_PAGE WAL
records use a standard snapshotConflictHorizon style XID cutoff.

No bump in XLOG_PAGE_MAGIC, since the underlying format of affected WAL
records doesn't change.

Author: Peter Geoghegan <pg@bowt.ie>
Reviewed-By: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/CAH2-Wzm2CQUmViUq7Opgk=McVREHSOorYaAjR1ZpLYkRN7_dPw@mail.gmail.com
This commit is contained in:
Peter Geoghegan
2022-11-17 14:55:08 -08:00
parent 6ff5aa1299
commit 1489b1ce72
27 changed files with 179 additions and 150 deletions

View File

@@ -528,17 +528,17 @@ from the index immediately; since index scans only stop "between" pages,
no scan can lose its place from such a deletion. We separate the steps
because we allow LP_DEAD to be set with only a share lock (it's like a
hint bit for a heap tuple), but physically deleting tuples requires an
exclusive lock. We also need to generate a latestRemovedXid value for
exclusive lock. We also need to generate a snapshotConflictHorizon for
each deletion operation's WAL record, which requires additional
coordinating with the tableam when the deletion actually takes place.
(This latestRemovedXid value may be used to generate a recovery conflict
during subsequent REDO of the record by a standby.)
(snapshotConflictHorizon value may be used to generate a conflict during
subsequent REDO of the record by a standby.)
Delaying and batching index tuple deletion like this enables a further
optimization: opportunistic checking of "extra" nearby index tuples
(tuples that are not LP_DEAD-set) when they happen to be very cheap to
check in passing (because we already know that the tableam will be
visiting their table block to generate a latestRemovedXid value). Any
visiting their table block to generate a snapshotConflictHorizon). Any
index tuples that turn out to be safe to delete will also be deleted.
Simple deletion will behave as if the extra tuples that actually turn
out to be delete-safe had their LP_DEAD bits set right from the start.

View File

@@ -41,7 +41,7 @@ static BTMetaPageData *_bt_getmeta(Relation rel, Buffer metabuf);
static void _bt_log_reuse_page(Relation rel, BlockNumber blkno,
FullTransactionId safexid);
static void _bt_delitems_delete(Relation rel, Buffer buf,
TransactionId latestRemovedXid,
TransactionId snapshotConflictHorizon,
OffsetNumber *deletable, int ndeletable,
BTVacuumPosting *updatable, int nupdatable);
static char *_bt_delitems_update(BTVacuumPosting *updatable, int nupdatable,
@@ -838,7 +838,7 @@ _bt_log_reuse_page(Relation rel, BlockNumber blkno, FullTransactionId safexid)
/* XLOG stuff */
xlrec_reuse.locator = rel->rd_locator;
xlrec_reuse.block = blkno;
xlrec_reuse.latestRemovedFullXid = safexid;
xlrec_reuse.snapshotConflictHorizon = safexid;
XLogBeginInsert();
XLogRegisterData((char *) &xlrec_reuse, SizeOfBtreeReusePage);
@@ -1156,7 +1156,7 @@ _bt_pageinit(Page page, Size size)
* (a version that lacks the TIDs that are to be deleted).
*
* We record VACUUMs and b-tree deletes differently in WAL. Deletes must
* generate their own latestRemovedXid by accessing the table directly,
* generate their own snapshotConflictHorizon directly from the tableam,
* whereas VACUUMs rely on the initial VACUUM table scan performing
* WAL-logging that takes care of the issue for the table's indexes
* indirectly. Also, we remove the VACUUM cycle ID from pages, which b-tree
@@ -1287,13 +1287,14 @@ _bt_delitems_vacuum(Relation rel, Buffer buf,
* (a version that lacks the TIDs that are to be deleted).
*
* This is nearly the same as _bt_delitems_vacuum as far as what it does to
* the page, but it needs its own latestRemovedXid from caller (caller gets
* this from tableam). This is used by the REDO routine to generate recovery
* the page, but it needs its own snapshotConflictHorizon (caller gets this
* from tableam). This is used by the REDO routine to generate recovery
* conflicts. The other difference is that only _bt_delitems_vacuum will
* clear page's VACUUM cycle ID.
*/
static void
_bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid,
_bt_delitems_delete(Relation rel, Buffer buf,
TransactionId snapshotConflictHorizon,
OffsetNumber *deletable, int ndeletable,
BTVacuumPosting *updatable, int nupdatable)
{
@@ -1357,7 +1358,7 @@ _bt_delitems_delete(Relation rel, Buffer buf, TransactionId latestRemovedXid,
XLogRecPtr recptr;
xl_btree_delete xlrec_delete;
xlrec_delete.latestRemovedXid = latestRemovedXid;
xlrec_delete.snapshotConflictHorizon = snapshotConflictHorizon;
xlrec_delete.ndeleted = ndeletable;
xlrec_delete.nupdated = nupdatable;
@@ -1529,7 +1530,7 @@ _bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel,
TM_IndexDeleteOp *delstate)
{
Page page = BufferGetPage(buf);
TransactionId latestRemovedXid;
TransactionId snapshotConflictHorizon;
OffsetNumber postingidxoffnum = InvalidOffsetNumber;
int ndeletable = 0,
nupdatable = 0;
@@ -1537,11 +1538,11 @@ _bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel,
BTVacuumPosting updatable[MaxIndexTuplesPerPage];
/* Use tableam interface to determine which tuples to delete first */
latestRemovedXid = table_index_delete_tuples(heapRel, delstate);
snapshotConflictHorizon = table_index_delete_tuples(heapRel, delstate);
/* Should not WAL-log latestRemovedXid unless it's required */
if (!XLogStandbyInfoActive() || !RelationNeedsWAL(rel))
latestRemovedXid = InvalidTransactionId;
/* Should not WAL-log snapshotConflictHorizon unless it's required */
if (!XLogStandbyInfoActive())
snapshotConflictHorizon = InvalidTransactionId;
/*
* Construct a leaf-page-wise description of what _bt_delitems_delete()
@@ -1683,8 +1684,8 @@ _bt_delitems_delete_check(Relation rel, Buffer buf, Relation heapRel,
}
/* Physically delete tuples (or TIDs) using deletable (or updatable) */
_bt_delitems_delete(rel, buf, latestRemovedXid, deletable, ndeletable,
updatable, nupdatable);
_bt_delitems_delete(rel, buf, snapshotConflictHorizon,
deletable, ndeletable, updatable, nupdatable);
/* be tidy */
for (int i = 0; i < nupdatable; i++)

View File

@@ -668,7 +668,8 @@ btree_xlog_delete(XLogReaderState *record)
XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid, rlocator);
ResolveRecoveryConflictWithSnapshot(xlrec->snapshotConflictHorizon,
rlocator);
}
/*
@@ -991,7 +992,7 @@ btree_xlog_newroot(XLogReaderState *record)
* xl_btree_reuse_page record at the point that a page is actually recycled
* and reused for an entirely unrelated page inside _bt_split(). These
* records include the same safexid value from the original deleted page,
* stored in the record's latestRemovedFullXid field.
* stored in the record's snapshotConflictHorizon field.
*
* The GlobalVisCheckRemovableFullXid() test in BTPageIsRecyclable() is used
* to determine if it's safe to recycle a page. This mirrors our own test:
@@ -1005,7 +1006,7 @@ btree_xlog_reuse_page(XLogReaderState *record)
xl_btree_reuse_page *xlrec = (xl_btree_reuse_page *) XLogRecGetData(record);
if (InHotStandby)
ResolveRecoveryConflictWithSnapshotFullXid(xlrec->latestRemovedFullXid,
ResolveRecoveryConflictWithSnapshotFullXid(xlrec->snapshotConflictHorizon,
xlrec->locator);
}