From 08777add4640278cb85aebf0059fdefb620494cf Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Wed, 12 Nov 2025 17:37:04 +0000 Subject: [PATCH 1/9] Add the hooks for disabling FPI --- src/backend/access/transam/xlog.c | 7 ++++++- src/backend/access/transam/xloginsert.c | 23 ++++++++++++++++++++++- src/include/access/xloginsert.h | 11 +++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index b7089850c8c..cc37652a831 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -867,6 +867,10 @@ XLogInsertRecord(XLogRecData *rdata, * our local copy but not force a recomputation. (If doPageWrites was * just turned off, we could recompute the record without full pages, * but we choose not to bother.) + * + * However, if force_disable_full_page_write is true, we skip the + * recomputation check since we're deliberately disabling full page + * writes for this record via the FPI control hook. */ if (RedoRecPtr != Insert->RedoRecPtr) { @@ -877,7 +881,8 @@ XLogInsertRecord(XLogRecData *rdata, if (doPageWrites && (!prevDoPageWrites || - (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr))) + (!force_disable_full_page_write && + fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr))) { /* * Oops, some buffer now needs to be backed up that the caller diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index c06101a7f43..fd94392b013 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -93,6 +93,12 @@ int max_replication_apply_lag; int max_replication_flush_lag; int max_replication_write_lag; +/* NEON: Hook to control Full Page Image (FPI) writes */ +xlog_fpi_control_hook_type xlog_fpi_control_hook = NULL; + +/* NEON: Global flag to force disable FPI for current WAL record */ +bool force_disable_full_page_write = false; + static registered_buffer *registered_buffers; static int max_registered_buffers; /* allocated size */ static int max_registered_block_id = 0; /* highest block_id + 1 currently @@ -529,6 +535,13 @@ XLogInsert(RmgrId rmid, uint8 info) */ GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites); + /* + * NEON: Check if we should force disable FPI for this WAL record. + */ + force_disable_full_page_write = false; + if (xlog_fpi_control_hook != NULL) + force_disable_full_page_write = xlog_fpi_control_hook(rmid); + rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn, &num_fpi, &topxid_included); @@ -629,9 +642,17 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, */ XLogRecPtr page_lsn = PageGetLSN(regbuf->page); - needs_backup = (page_lsn <= RedoRecPtr); + if (force_disable_full_page_write) + needs_backup = false; + else + needs_backup = (page_lsn <= RedoRecPtr); + if (!needs_backup) { + /* + * Set fpw_lsn to signal that this record should be + * recomputed if doPageWrites changes. + */ if (*fpw_lsn == InvalidXLogRecPtr || page_lsn < *fpw_lsn) *fpw_lsn = page_lsn; } diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index a63f3a07fb2..0c593c4ee67 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -43,6 +43,17 @@ extern int max_replication_apply_lag; extern int max_replication_flush_lag; extern int max_replication_write_lag; +/* NEON: Hook to control Full Page Image (FPI) writes + * Returns true to DISABLE FPI, false to keep FPI enabled + * Parameters: + * rmid - Resource manager ID (e.g., RM_HEAP_ID, RM_BTREE_ID) + */ +typedef bool (*xlog_fpi_control_hook_type)(RmgrId rmid); +extern PGDLLIMPORT xlog_fpi_control_hook_type xlog_fpi_control_hook; + +/* NEON: Flag set per-record to force disable FPI (set by neon_should_disable_fpi hook) */ +extern bool force_disable_full_page_write; + /* prototypes for public functions in xloginsert.c: */ extern void XLogBeginInsert(void); extern void XLogSetRecordFlags(uint8 flags); From 9eedcecac69ef15e79eaa7ce25a865f83cafc02e Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Fri, 14 Nov 2025 04:12:24 +0000 Subject: [PATCH 2/9] add debug logging --- src/backend/access/transam/xloginsert.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index fd94392b013..16b48534bf7 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -539,8 +539,11 @@ XLogInsert(RmgrId rmid, uint8 info) * NEON: Check if we should force disable FPI for this WAL record. */ force_disable_full_page_write = false; - if (xlog_fpi_control_hook != NULL) + if (xlog_fpi_control_hook != NULL) { force_disable_full_page_write = xlog_fpi_control_hook(rmid); + elog(DEBUG1, "FPI control hook called: rmid=%u, force_disable=%d, doPageWrites=%d", + rmid, force_disable_full_page_write, doPageWrites); + } rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn, &num_fpi, &topxid_included); From c6b17f754f0963499abbe015d642591f4eb05810 Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Tue, 25 Nov 2025 00:59:13 +0000 Subject: [PATCH 3/9] add reloptions --- src/backend/access/common/reloptions.c | 13 ++- src/backend/access/heap/heapam.c | 53 ++++++++++-- src/backend/access/nbtree/nbtinsert.c | 17 +++- src/backend/access/transam/xloginsert.c | 20 ++--- src/backend/commands/tablecmds.c | 61 +++++++++++++ src/backend/utils/cache/relcache.c | 109 ++++++++++++++++++++++++ src/include/access/xloginsert.h | 2 + src/include/utils/rel.h | 17 ++++ 8 files changed, 268 insertions(+), 24 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index c6a2d13be8d..434ff8dc213 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -166,6 +166,15 @@ static relopt_bool boolRelOpts[] = }, true }, + { + { + "reduce_fpi", + "Reduces full page images in WAL for this table", + RELOPT_KIND_HEAP, /* regular tables only - indexes/toast derive from parent */ + ShareUpdateExclusiveLock /* applies only to subsequent WAL writes, like fillfactor */ + }, + false + }, /* list terminator */ {{NULL}} }; @@ -1889,7 +1898,9 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, vacuum_truncate)} + offsetof(StdRdOptions, vacuum_truncate)}, + {"reduce_fpi", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, reduce_fpi)} }; return (bytea *) build_reloptions(reloptions, validate, kind, diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 41200e9db11..f92fdae42aa 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2200,6 +2200,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, * write the whole page to the xlog, we don't need to store * xl_heap_header in the xlog. */ + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags); XLogRegisterBufData(0, (char *) &xlhdr, SizeOfNeonHeapHeader); /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */ @@ -3115,7 +3117,10 @@ heap_delete(Relation relation, ItemPointer tid, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); /* * Log replica identity of the deleted tuple if there is one @@ -3887,7 +3892,10 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self); xlrec.xmax = xmax_lock_old_tuple; @@ -5220,7 +5228,10 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, *buffer, bufflags); xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self); xlrec.xmax = xid; @@ -5973,7 +5984,10 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, Page page = BufferGetPage(buf); XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(rel)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buf, bufflags); xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self); xlrec.xmax = new_xmax; @@ -6135,7 +6149,10 @@ heap_finish_speculative(Relation relation, ItemPointer tid) XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM); @@ -6292,7 +6309,10 @@ heap_abort_speculative(Relation relation, ItemPointer tid) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); /* No replica identity & replication origin logged */ @@ -6536,7 +6556,10 @@ heap_inplace_update_and_unlock(Relation relation, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -6639,7 +6662,10 @@ heap_inplace_update(Relation relation, HeapTuple tuple) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); + int bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(relation)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buffer, bufflags); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -8861,6 +8887,8 @@ log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer, flags = REGBUF_STANDARD; if (!XLogHintBitIsNeeded()) flags |= REGBUF_NO_IMAGE; + if (RelationGetReduceFPI(rel)) + flags |= REGBUF_REDUCE_FPI; XLogRegisterBuffer(1, heap_buffer, flags); recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE); @@ -9001,10 +9029,17 @@ log_heap_update(Relation reln, Buffer oldbuf, bufflags |= REGBUF_WILL_INIT; if (need_tuple_data) bufflags |= REGBUF_KEEP_DATA; + if (RelationGetReduceFPI(reln)) + bufflags |= REGBUF_REDUCE_FPI; XLogRegisterBuffer(0, newbuf, bufflags); if (oldbuf != newbuf) - XLogRegisterBuffer(1, oldbuf, REGBUF_STANDARD); + { + int oldbufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(reln)) + oldbufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(1, oldbuf, oldbufflags); + } XLogRegisterData((char *) &xlrec, SizeOfNeonHeapUpdate); diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 146b19991be..53476ebb10f 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -1317,6 +1317,7 @@ _bt_insertonpg(Relation rel, uint8 xlinfo; XLogRecPtr recptr; uint16 upostingoff; + uint8 bufflags; xlrec.offnum = newitemoff; @@ -1341,7 +1342,10 @@ _bt_insertonpg(Relation rel, { /* Internal page insert, which finishes a split on cbuf */ xlinfo = XLOG_BTREE_INSERT_UPPER; - XLogRegisterBuffer(1, cbuf, REGBUF_STANDARD); + bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(rel)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(1, cbuf, bufflags); if (BufferIsValid(metabuf)) { @@ -1357,14 +1361,19 @@ _bt_insertonpg(Relation rel, xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages; xlmeta.allequalimage = metad->btm_allequalimage; - XLogRegisterBuffer(2, metabuf, - REGBUF_WILL_INIT | REGBUF_STANDARD); + bufflags = REGBUF_WILL_INIT | REGBUF_STANDARD; + if (RelationGetReduceFPI(rel)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(2, metabuf, bufflags); XLogRegisterBufData(2, (char *) &xlmeta, sizeof(xl_btree_metadata)); } } - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); + bufflags = REGBUF_STANDARD; + if (RelationGetReduceFPI(rel)) + bufflags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(0, buf, bufflags); if (postingoff == 0) { /* Just log itup from caller */ diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 16b48534bf7..54b46c138c1 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -638,17 +638,17 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, needs_backup = false; else { - /* - * We assume page LSN is first data on *every* page that can be - * passed to XLogInsert, whether it has the standard page layout - * or not. - */ - XLogRecPtr page_lsn = PageGetLSN(regbuf->page); + /* + * We assume page LSN is first data on *every* page that can be + * passed to XLogInsert, whether it has the standard page layout + * or not. + */ + XLogRecPtr page_lsn = PageGetLSN(regbuf->page); - if (force_disable_full_page_write) - needs_backup = false; - else - needs_backup = (page_lsn <= RedoRecPtr); + if (force_disable_full_page_write && (regbuf->flags & REGBUF_REDUCE_FPI)) + needs_backup = false; + else + needs_backup = (page_lsn <= RedoRecPtr); if (!needs_backup) { diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3ba65a33a12..730afc482d9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -15180,6 +15180,67 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, ReleaseSysCache(tuple); + /* + * If this is a heap relation and reduce_fpi was changed, invalidate + * relcache for all indexes and toast relations so they pick up the new + * value in their rd_reduce_fpi field. + */ + if (rel->rd_rel->relkind == RELKIND_RELATION) + { + List *changed_options = untransformRelOptions(newOptions); + ListCell *cell; + bool reduce_fpi_changed = false; + + /* Check if reduce_fpi was in the ALTER statement */ + foreach(cell, defList) + { + DefElem *defel = (DefElem *) lfirst(cell); + + if (strcmp(defel->defname, "reduce_fpi") == 0) + { + reduce_fpi_changed = true; + break; + } + } + + if (reduce_fpi_changed) + { + List *indexoidlist; + ListCell *indexoidscan; + + /* Invalidate all indexes on this relation */ + indexoidlist = RelationGetIndexList(rel); + foreach(indexoidscan, indexoidlist) + { + Oid indexoid = lfirst_oid(indexoidscan); + + CacheInvalidateRelcacheByRelid(indexoid); + } + list_free(indexoidlist); + + /* Invalidate toast table and its indexes */ + if (OidIsValid(rel->rd_rel->reltoastrelid)) + { + Oid toastrelid = rel->rd_rel->reltoastrelid; + Relation toastrel; + + CacheInvalidateRelcacheByRelid(toastrelid); + + /* Also invalidate toast table's indexes */ + toastrel = table_open(toastrelid, AccessShareLock); + indexoidlist = RelationGetIndexList(toastrel); + foreach(indexoidscan, indexoidlist) + { + Oid indexoid = lfirst_oid(indexoidscan); + + CacheInvalidateRelcacheByRelid(indexoid); + } + list_free(indexoidlist); + table_close(toastrel, AccessShareLock); + } + } + } + /* repeat the whole exercise for the toast table, if there's one */ if (OidIsValid(rel->rd_rel->reltoastrelid)) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index f5f0d60d33c..b1064c2e8dc 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -511,6 +511,112 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple) } } +/* + * RelationInitReduceFPI + * Initialize rd_reduce_fpi flag for a relation + * + * For heap: reads from StdRdOptions.reduce_fpi reloption. + * For index: derives from parent heap's rd_reduce_fpi. + * For toast: derives from parent heap's rd_reduce_fpi. + * + * Must be called after rd_rel, rd_index, and rd_options are set. + */ +static void +RelationInitReduceFPI(Relation relation) +{ + relation->rd_reduce_fpi = false; + + switch (relation->rd_rel->relkind) + { + case RELKIND_RELATION: + { + if (relation->rd_options) + { + StdRdOptions *opts = (StdRdOptions *) relation->rd_options; + relation->rd_reduce_fpi = opts->reduce_fpi; + } + break; + } + + case RELKIND_INDEX: + { + /* + * Index: derive from parent relation. + * + * This handles both: + * 1. Main table's indexes: index->indrelid points to table, + * which already has rd_reduce_fpi set from its reloption. + * 2. Toast table's indexes: index->indrelid points to toast table, + * which already has rd_reduce_fpi derived from its parent table + * (see RELKIND_TOASTVALUE case below). + * + * Safety: RelationIdGetRelation() will build the parent's relcache + * entry if it doesn't exist yet (calling RelationBuildDesc() which + * includes RelationInitReduceFPI()). Otherwise it returns the + * already-built entry. Either way, by the time we read + * parent->rd_reduce_fpi, it's guaranteed to be initialized. + * Worst case: we read false (the safe default). + */ + if (relation->rd_index && OidIsValid(relation->rd_index->indrelid)) + { + Relation parent = RelationIdGetRelation(relation->rd_index->indrelid); + + if (RelationIsValid(parent)) + { + relation->rd_reduce_fpi = parent->rd_reduce_fpi; + RelationClose(parent); + } + } + break; + } + + case RELKIND_TOASTVALUE: + { + /* + * Toast table: find parent heap via pg_class.reltoastrelid. + * We search for the heap relation that has this toast table as its + * reltoastrelid. + */ + Relation pg_class; + SysScanDesc scan; + HeapTuple tuple; + ScanKeyData key[1]; + + pg_class = table_open(RelationRelationId, AccessShareLock); + + /* Scan for heap relation with this toast OID */ + ScanKeyInit(&key[0], + Anum_pg_class_reltoastrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(relation))); + + scan = systable_beginscan(pg_class, InvalidOid, false, + NULL, 1, key); + + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple); + Relation parent = RelationIdGetRelation(classtup->oid); + + if (RelationIsValid(parent)) + { + relation->rd_reduce_fpi = parent->rd_reduce_fpi; + RelationClose(parent); + } + } + + systable_endscan(scan); + table_close(pg_class, AccessShareLock); + break; + } + + default: + /* Other relkinds don't use reduce_fpi */ + break; + } +} + /* * RelationBuildTupleDesc * @@ -1222,6 +1328,9 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); + /* initialize reduce_fpi flag (must be after RelationParseRelOptions) */ + RelationInitReduceFPI(relation); + /* * Fetch rules and triggers that affect this relation. * diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index 0c593c4ee67..4691a7d986b 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -38,6 +38,8 @@ #define REGBUF_KEEP_DATA 0x10 /* include data even if a full-page image * is taken */ #define REGBUF_NO_CHANGE 0x20 /* intentionally register clean buffer */ +#define REGBUF_REDUCE_FPI 0x40 /* relation has reduce_fpi enabled, suppress + * full page images when possible */ extern int max_replication_apply_lag; extern int max_replication_flush_lag; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 50d95bb8cb9..70ad05bcb7f 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -174,6 +174,14 @@ typedef struct RelationData */ bytea *rd_options; /* parsed pg_class.reloptions */ + /* + * rd_reduce_fpi: derived flag for reduced full-page-image WAL logging. + * For regular tables (RELKIND_RELATION): comes from StdRdOptions.reduce_fpi reloption. + * For index: derived from parent table's rd_reduce_fpi. + * For toast: derived from parent table's rd_reduce_fpi. + */ + bool rd_reduce_fpi; /* enable reduced FPI for this relation */ + /* * Oid of the handler for this relation. For an index this is a function * returning IndexAmRoutine, for table like relations a function returning @@ -343,6 +351,7 @@ typedef struct StdRdOptions int parallel_workers; /* max number of parallel workers */ StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ bool vacuum_truncate; /* enables vacuum to truncate a relation */ + bool reduce_fpi; /* reduce full page images in WAL */ } StdRdOptions; #define HEAP_MIN_FILLFACTOR 10 @@ -398,6 +407,14 @@ typedef struct StdRdOptions ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw)) +/* + * RelationGetReduceFPI + * Returns whether the relation has reduce_fpi enabled. + * For heap: comes from reloption. + * For index/toast: derived from parent heap. + */ +#define RelationGetReduceFPI(relation) ((relation)->rd_reduce_fpi) + /* ViewOptions->check_option values */ typedef enum ViewOptCheckOption { From c39d303d57514c98d4674c23bb9fece86d54bf36 Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Wed, 26 Nov 2025 23:30:49 +0000 Subject: [PATCH 4/9] refactor --- src/backend/commands/tablecmds.c | 87 +++++++++++++++++------------- src/backend/utils/cache/relcache.c | 2 +- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 730afc482d9..52f16288059 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -612,6 +612,7 @@ static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode); static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace); +static void InvalidateReduceFPIChildren(Relation rel); static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode); @@ -15042,6 +15043,51 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacen tab->newTableSpace = tablespaceId; } +/* + * InvalidateReduceFPIChildren + * + * When reduce_fpi changes on a heap table, invalidate relcache entries for + * all child relations (indexes and toast tables) so they re-derive the new + * value from the parent. + */ +static void +InvalidateReduceFPIChildren(Relation rel) +{ + List *indexoidlist; + ListCell *indexoidscan; + + /* Invalidate all indexes on this relation */ + indexoidlist = RelationGetIndexList(rel); + foreach(indexoidscan, indexoidlist) + { + Oid indexoid = lfirst_oid(indexoidscan); + + CacheInvalidateRelcacheByRelid(indexoid); + } + list_free(indexoidlist); + + /* Invalidate toast table and its indexes */ + if (OidIsValid(rel->rd_rel->reltoastrelid)) + { + Oid toastrelid = rel->rd_rel->reltoastrelid; + Relation toastrel; + + CacheInvalidateRelcacheByRelid(toastrelid); + + /* Also invalidate toast table's indexes */ + toastrel = table_open(toastrelid, AccessShareLock); + indexoidlist = RelationGetIndexList(toastrel); + foreach(indexoidscan, indexoidlist) + { + Oid indexoid = lfirst_oid(indexoidscan); + + CacheInvalidateRelcacheByRelid(indexoid); + } + list_free(indexoidlist); + table_close(toastrel, AccessShareLock); + } +} + /* * Set, reset, or replace reloptions. */ @@ -15185,9 +15231,12 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, * relcache for all indexes and toast relations so they pick up the new * value in their rd_reduce_fpi field. */ + /* + * For regular tables, if reduce_fpi changed, we need to invalidate + * child relations (indexes and toast) so they re-derive the new value. + */ if (rel->rd_rel->relkind == RELKIND_RELATION) { - List *changed_options = untransformRelOptions(newOptions); ListCell *cell; bool reduce_fpi_changed = false; @@ -15204,41 +15253,7 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, } if (reduce_fpi_changed) - { - List *indexoidlist; - ListCell *indexoidscan; - - /* Invalidate all indexes on this relation */ - indexoidlist = RelationGetIndexList(rel); - foreach(indexoidscan, indexoidlist) - { - Oid indexoid = lfirst_oid(indexoidscan); - - CacheInvalidateRelcacheByRelid(indexoid); - } - list_free(indexoidlist); - - /* Invalidate toast table and its indexes */ - if (OidIsValid(rel->rd_rel->reltoastrelid)) - { - Oid toastrelid = rel->rd_rel->reltoastrelid; - Relation toastrel; - - CacheInvalidateRelcacheByRelid(toastrelid); - - /* Also invalidate toast table's indexes */ - toastrel = table_open(toastrelid, AccessShareLock); - indexoidlist = RelationGetIndexList(toastrel); - foreach(indexoidscan, indexoidlist) - { - Oid indexoid = lfirst_oid(indexoidscan); - - CacheInvalidateRelcacheByRelid(indexoid); - } - list_free(indexoidlist); - table_close(toastrel, AccessShareLock); - } - } + InvalidateReduceFPIChildren(rel); } /* repeat the whole exercise for the toast table, if there's one */ diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index b1064c2e8dc..bf458fc9138 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -1328,7 +1328,7 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); - /* initialize reduce_fpi flag (must be after RelationParseRelOptions) */ + /* initialize reduce_fpi flag */ RelationInitReduceFPI(relation); /* From 97b05d694018639faf1cc265ec6d7eb367758895 Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Wed, 3 Dec 2025 00:17:48 +0000 Subject: [PATCH 5/9] rename the methods and update all call sites --- src/backend/access/heap/heapam.c | 58 ++++++----------------- src/backend/access/nbtree/nbtdedup.c | 6 +-- src/backend/access/nbtree/nbtinsert.c | 42 +++++++---------- src/backend/access/nbtree/nbtpage.c | 62 ++++++++++++------------- src/backend/access/transam/xlog.c | 8 ++-- src/backend/access/transam/xloginsert.c | 46 +++++++++--------- src/include/access/xloginsert.h | 30 +++++++++--- 7 files changed, 115 insertions(+), 137 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index f92fdae42aa..896f8333235 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2200,9 +2200,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, * write the whole page to the xlog, we don't need to store * xl_heap_header in the xlog. */ - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD | bufflags, + relation); XLogRegisterBufData(0, (char *) &xlhdr, SizeOfNeonHeapHeader); /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */ XLogRegisterBufData(0, @@ -3117,10 +3116,7 @@ heap_delete(Relation relation, ItemPointer tid, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); /* * Log replica identity of the deleted tuple if there is one @@ -3892,10 +3888,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, XLogRecPtr recptr; XLogBeginInsert(); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self); xlrec.xmax = xmax_lock_old_tuple; @@ -5228,10 +5221,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, XLogRecPtr recptr; XLogBeginInsert(); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, *buffer, bufflags); + XLogRegisterBufferForRelation(0, *buffer, REGBUF_STANDARD, relation); xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self); xlrec.xmax = xid; @@ -5984,10 +5974,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, Page page = BufferGetPage(buf); XLogBeginInsert(); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(rel)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buf, bufflags); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self); xlrec.xmax = new_xmax; @@ -6149,10 +6136,7 @@ heap_finish_speculative(Relation relation, ItemPointer tid) XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM); @@ -6309,10 +6293,7 @@ heap_abort_speculative(Relation relation, ItemPointer tid) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); /* No replica identity & replication origin logged */ @@ -6556,10 +6537,7 @@ heap_inplace_update_and_unlock(Relation relation, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -6662,10 +6640,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - int bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(relation)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buffer, bufflags); + XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -8887,9 +8862,7 @@ log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer, flags = REGBUF_STANDARD; if (!XLogHintBitIsNeeded()) flags |= REGBUF_NO_IMAGE; - if (RelationGetReduceFPI(rel)) - flags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(1, heap_buffer, flags); + XLogRegisterBufferForRelation(1, heap_buffer, flags, rel); recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE); @@ -9029,16 +9002,11 @@ log_heap_update(Relation reln, Buffer oldbuf, bufflags |= REGBUF_WILL_INIT; if (need_tuple_data) bufflags |= REGBUF_KEEP_DATA; - if (RelationGetReduceFPI(reln)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, newbuf, bufflags); + XLogRegisterBufferForRelation(0, newbuf, bufflags, reln); if (oldbuf != newbuf) { - int oldbufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(reln)) - oldbufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(1, oldbuf, oldbufflags); + XLogRegisterBufferForRelation(1, oldbuf, REGBUF_STANDARD, reln); } XLogRegisterData((char *) &xlrec, SizeOfNeonHeapUpdate); diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 456d86b51c9..c710ac14bd9 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -246,13 +246,13 @@ _bt_dedup_pass(Relation rel, Buffer buf, IndexTuple newitem, Size newitemsz, if (RelationNeedsWAL(rel)) { XLogRecPtr recptr; - xl_btree_dedup xlrec_dedup; + xl_btree_dedup xlrec_dedup; xlrec_dedup.nintervals = state->nintervals; XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); - XLogRegisterData((char *) &xlrec_dedup, SizeOfBtreeDedup); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_dedup, SizeOfBtreeDedup); /* * The intervals array is not in the buffer, but pretend that it is. diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 53476ebb10f..94acff3753f 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -1317,7 +1317,6 @@ _bt_insertonpg(Relation rel, uint8 xlinfo; XLogRecPtr recptr; uint16 upostingoff; - uint8 bufflags; xlrec.offnum = newitemoff; @@ -1340,12 +1339,9 @@ _bt_insertonpg(Relation rel, } else { - /* Internal page insert, which finishes a split on cbuf */ - xlinfo = XLOG_BTREE_INSERT_UPPER; - bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(rel)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(1, cbuf, bufflags); + /* Internal page insert, which finishes a split on cbuf */ + xlinfo = XLOG_BTREE_INSERT_UPPER; + XLogRegisterBufferForRelation(1, cbuf, REGBUF_STANDARD, rel); if (BufferIsValid(metabuf)) { @@ -1359,22 +1355,18 @@ _bt_insertonpg(Relation rel, xlmeta.fastroot = metad->btm_fastroot; xlmeta.fastlevel = metad->btm_fastlevel; xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages; - xlmeta.allequalimage = metad->btm_allequalimage; + xlmeta.allequalimage = metad->btm_allequalimage; - bufflags = REGBUF_WILL_INIT | REGBUF_STANDARD; - if (RelationGetReduceFPI(rel)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(2, metabuf, bufflags); + XLogRegisterBufferForRelation(2, metabuf, + REGBUF_WILL_INIT | REGBUF_STANDARD, + rel); XLogRegisterBufData(2, (char *) &xlmeta, sizeof(xl_btree_metadata)); } - } + } - bufflags = REGBUF_STANDARD; - if (RelationGetReduceFPI(rel)) - bufflags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(0, buf, bufflags); - if (postingoff == 0) + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + if (postingoff == 0) { /* Just log itup from caller */ XLogRegisterBufData(0, (char *) itup, IndexTupleSize(itup)); @@ -2025,13 +2017,13 @@ _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf, bufflags |= REGBUF_FORCE_IMAGE; } - XLogRegisterBuffer(0, buf, bufflags); - XLogRegisterBuffer(1, rbuf, REGBUF_WILL_INIT); + XLogRegisterBufferForRelation(0, buf, bufflags, rel); + XLogRegisterBufferForRelation(1, rbuf, REGBUF_WILL_INIT, rel); /* Log original right sibling, since we've changed its prev-pointer */ if (!isrightmost) - XLogRegisterBuffer(2, sbuf, REGBUF_STANDARD); + XLogRegisterBufferForRelation(2, sbuf, REGBUF_STANDARD, rel); if (!isleaf) - XLogRegisterBuffer(3, cbuf, REGBUF_STANDARD); + XLogRegisterBufferForRelation(3, cbuf, REGBUF_STANDARD, rel); /* * Log the new item, if it was inserted on the left page. (If it was @@ -2610,9 +2602,9 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfBtreeNewroot); - XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT); - XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD); - XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); + XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); + XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 01bbece6bfd..7325ba41d0d 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -288,7 +288,7 @@ _bt_set_cleanup_info(Relation rel, BlockNumber num_delpages) XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBuffer(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); + XLogRegisterBufferForRelation(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; @@ -475,11 +475,11 @@ _bt_getroot(Relation rel, Relation heaprel, int access) XLogRecPtr recptr; xl_btree_metadata md; - XLogBeginInsert(); - XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT); - XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); - Assert(metad->btm_version >= BTREE_NOVAC_VERSION); + Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; md.root = rootblkno; md.level = 0; @@ -1230,11 +1230,11 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, xl_btree_vacuum xlrec_vacuum; xlrec_vacuum.ndeleted = ndeletable; - xlrec_vacuum.nupdated = nupdatable; + xlrec_vacuum.nupdated = nupdatable; - XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); - XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum); if (ndeletable > 0) XLogRegisterBufData(0, (char *) deletable, @@ -1349,11 +1349,11 @@ _bt_delitems_delete(Relation rel, Buffer buf, xlrec_delete.snapshotConflictHorizon = snapshotConflictHorizon; xlrec_delete.ndeleted = ndeletable; xlrec_delete.nupdated = nupdatable; - xlrec_delete.isCatalogRel = isCatalogRel; + xlrec_delete.isCatalogRel = isCatalogRel; - XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_STANDARD); - XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); if (ndeletable > 0) XLogRegisterBufData(0, (char *) deletable, @@ -2258,13 +2258,13 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf, if (topparent != leafblkno) xlrec.topparent = topparent; else - xlrec.topparent = InvalidBlockNumber; + xlrec.topparent = InvalidBlockNumber; - XLogBeginInsert(); - XLogRegisterBuffer(0, leafbuf, REGBUF_WILL_INIT); - XLogRegisterBuffer(1, subtreeparent, REGBUF_STANDARD); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, leafbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(1, subtreeparent, REGBUF_STANDARD, rel); - page = BufferGetPage(leafbuf); + page = BufferGetPage(leafbuf); opaque = BTPageGetOpaque(page); xlrec.leftblk = opaque->btpo_prev; xlrec.rightblk = opaque->btpo_next; @@ -2674,17 +2674,17 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, uint8 xlinfo; XLogRecPtr recptr; - XLogBeginInsert(); + XLogBeginInsert(); - XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT); - if (BufferIsValid(lbuf)) - XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD); - XLogRegisterBuffer(2, rbuf, REGBUF_STANDARD); - if (target != leafblkno) - XLogRegisterBuffer(3, leafbuf, REGBUF_WILL_INIT); + XLogRegisterBufferForRelation(0, buf, REGBUF_WILL_INIT, rel); + if (BufferIsValid(lbuf)) + XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); + XLogRegisterBufferForRelation(2, rbuf, REGBUF_STANDARD, rel); + if (target != leafblkno) + XLogRegisterBufferForRelation(3, leafbuf, REGBUF_WILL_INIT, rel); - /* information stored on the target/to-be-unlinked block */ - xlrec.leftsib = leftsib; + /* information stored on the target/to-be-unlinked block */ + xlrec.leftsib = leftsib; xlrec.rightsib = rightsib; xlrec.level = targetlevel; xlrec.safexid = safexid; @@ -2696,11 +2696,11 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, XLogRegisterData((char *) &xlrec, SizeOfBtreeUnlinkPage); - if (BufferIsValid(metabuf)) - { - XLogRegisterBuffer(4, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); + if (BufferIsValid(metabuf)) + { + XLogRegisterBufferForRelation(4, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); - Assert(metad->btm_version >= BTREE_NOVAC_VERSION); + Assert(metad->btm_version >= BTREE_NOVAC_VERSION); xlmeta.version = metad->btm_version; xlmeta.root = metad->btm_root; xlmeta.level = metad->btm_level; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index cc37652a831..b260671da6e 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -868,9 +868,9 @@ XLogInsertRecord(XLogRecData *rdata, * just turned off, we could recompute the record without full pages, * but we choose not to bother.) * - * However, if force_disable_full_page_write is true, we skip the - * recomputation check since we're deliberately disabling full page - * writes for this record via the FPI control hook. + * However, if suppress_fpi is true, we skip the recomputation check + * since we're deliberately suppressing full page images for this + * record via the FPI control hook. */ if (RedoRecPtr != Insert->RedoRecPtr) { @@ -881,7 +881,7 @@ XLogInsertRecord(XLogRecData *rdata, if (doPageWrites && (!prevDoPageWrites || - (!force_disable_full_page_write && + (!suppress_fpi && fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr))) { /* diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 54b46c138c1..e6d914265fc 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -93,11 +93,11 @@ int max_replication_apply_lag; int max_replication_flush_lag; int max_replication_write_lag; -/* NEON: Hook to control Full Page Image (FPI) writes */ -xlog_fpi_control_hook_type xlog_fpi_control_hook = NULL; +/* NEON: Hook to determine if FPI should be suppressed for a WAL record */ +xlog_should_suppress_fpi_hook_type xlog_should_suppress_fpi_hook = NULL; -/* NEON: Global flag to force disable FPI for current WAL record */ -bool force_disable_full_page_write = false; +/* NEON: Global flag to suppress FPI for current WAL record */ +bool suppress_fpi = false; static registered_buffer *registered_buffers; static int max_registered_buffers; /* allocated size */ @@ -535,15 +535,15 @@ XLogInsert(RmgrId rmid, uint8 info) */ GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites); - /* - * NEON: Check if we should force disable FPI for this WAL record. - */ - force_disable_full_page_write = false; - if (xlog_fpi_control_hook != NULL) { - force_disable_full_page_write = xlog_fpi_control_hook(rmid); - elog(DEBUG1, "FPI control hook called: rmid=%u, force_disable=%d, doPageWrites=%d", - rmid, force_disable_full_page_write, doPageWrites); - } + /* + * NEON: Check if we should suppress FPI for this WAL record. + */ + suppress_fpi = false; + if (xlog_should_suppress_fpi_hook != NULL) { + suppress_fpi = xlog_should_suppress_fpi_hook(rmid); + elog(DEBUG1, "FPI suppress hook called: rmid=%u, suppress_fpi=%d, doPageWrites=%d", + rmid, suppress_fpi, doPageWrites); + } rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn, &num_fpi, &topxid_included); @@ -638,17 +638,17 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, needs_backup = false; else { - /* - * We assume page LSN is first data on *every* page that can be - * passed to XLogInsert, whether it has the standard page layout - * or not. - */ - XLogRecPtr page_lsn = PageGetLSN(regbuf->page); + /* + * We assume page LSN is first data on *every* page that can be + * passed to XLogInsert, whether it has the standard page layout + * or not. + */ + XLogRecPtr page_lsn = PageGetLSN(regbuf->page); - if (force_disable_full_page_write && (regbuf->flags & REGBUF_REDUCE_FPI)) - needs_backup = false; - else - needs_backup = (page_lsn <= RedoRecPtr); + if (suppress_fpi && (regbuf->flags & REGBUF_REDUCE_FPI)) + needs_backup = false; + else + needs_backup = (page_lsn <= RedoRecPtr); if (!needs_backup) { diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index 4691a7d986b..a56656e06c5 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -16,6 +16,7 @@ #include "storage/block.h" #include "storage/buf.h" #include "storage/relfilelocator.h" +#include "utils/rel.h" #include "utils/relcache.h" /* @@ -45,16 +46,16 @@ extern int max_replication_apply_lag; extern int max_replication_flush_lag; extern int max_replication_write_lag; -/* NEON: Hook to control Full Page Image (FPI) writes - * Returns true to DISABLE FPI, false to keep FPI enabled +/* NEON: Hook to determine if FPI should be suppressed for a WAL record + * Returns true to suppress FPI, false to allow FPI * Parameters: * rmid - Resource manager ID (e.g., RM_HEAP_ID, RM_BTREE_ID) */ -typedef bool (*xlog_fpi_control_hook_type)(RmgrId rmid); -extern PGDLLIMPORT xlog_fpi_control_hook_type xlog_fpi_control_hook; +typedef bool (*xlog_should_suppress_fpi_hook_type)(RmgrId rmid); +extern PGDLLIMPORT xlog_should_suppress_fpi_hook_type xlog_should_suppress_fpi_hook; -/* NEON: Flag set per-record to force disable FPI (set by neon_should_disable_fpi hook) */ -extern bool force_disable_full_page_write; +/* NEON: Flag set per-record to suppress FPI (set by xlog_should_suppress_fpi_hook) */ +extern bool suppress_fpi; /* prototypes for public functions in xloginsert.c: */ extern void XLogBeginInsert(void); @@ -81,4 +82,21 @@ extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std); extern void InitXLogInsert(void); +/* + * XLogRegisterBufferForRelation + * Convenience wrapper for XLogRegisterBuffer that automatically sets + * REGBUF_REDUCE_FPI based on the relation's reduce_fpi setting. + * + * This helper simplifies the code by eliminating the need to manually + * check RelationGetReduceFPI() at every call site. + */ +static inline void +XLogRegisterBufferForRelation(uint8 block_id, Buffer buffer, uint8 flags, + Relation rel) +{ + if (RelationGetReduceFPI(rel)) + flags |= REGBUF_REDUCE_FPI; + XLogRegisterBuffer(block_id, buffer, flags); +} + #endif /* XLOGINSERT_H */ From 6a375558ea7e9a8f9b76e55bbb67484f9079ba2c Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Wed, 3 Dec 2025 00:36:42 +0000 Subject: [PATCH 6/9] fix indent --- src/backend/access/nbtree/nbtdedup.c | 6 +-- src/backend/access/nbtree/nbtinsert.c | 16 +++---- src/backend/access/nbtree/nbtpage.c | 60 ++++++++++++------------- src/backend/access/transam/xloginsert.c | 18 ++++---- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index c710ac14bd9..a3dfd926566 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -246,13 +246,13 @@ _bt_dedup_pass(Relation rel, Buffer buf, IndexTuple newitem, Size newitemsz, if (RelationNeedsWAL(rel)) { XLogRecPtr recptr; - xl_btree_dedup xlrec_dedup; + xl_btree_dedup xlrec_dedup; xlrec_dedup.nintervals = state->nintervals; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); - XLogRegisterData((char *) &xlrec_dedup, SizeOfBtreeDedup); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_dedup, SizeOfBtreeDedup); /* * The intervals array is not in the buffer, but pretend that it is. diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 94acff3753f..fbd07cddc49 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -1337,13 +1337,13 @@ _bt_insertonpg(Relation rel, Assert(isleaf); xlinfo = XLOG_BTREE_INSERT_POST; } - else - { - /* Internal page insert, which finishes a split on cbuf */ - xlinfo = XLOG_BTREE_INSERT_UPPER; - XLogRegisterBufferForRelation(1, cbuf, REGBUF_STANDARD, rel); + else + { + /* Internal page insert, which finishes a split on cbuf */ + xlinfo = XLOG_BTREE_INSERT_UPPER; + XLogRegisterBufferForRelation(1, cbuf, REGBUF_STANDARD, rel); - if (BufferIsValid(metabuf)) + if (BufferIsValid(metabuf)) { /* Actually, it's an internal page insert + meta update */ xlinfo = XLOG_BTREE_INSERT_META; @@ -1355,9 +1355,9 @@ _bt_insertonpg(Relation rel, xlmeta.fastroot = metad->btm_fastroot; xlmeta.fastlevel = metad->btm_fastlevel; xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages; - xlmeta.allequalimage = metad->btm_allequalimage; + xlmeta.allequalimage = metad->btm_allequalimage; - XLogRegisterBufferForRelation(2, metabuf, + XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); XLogRegisterBufData(2, (char *) &xlmeta, diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 7325ba41d0d..a8c33f2c24f 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -475,11 +475,11 @@ _bt_getroot(Relation rel, Relation heaprel, int access) XLogRecPtr recptr; xl_btree_metadata md; - XLogBeginInsert(); - XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); - XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); - Assert(metad->btm_version >= BTREE_NOVAC_VERSION); + Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; md.root = rootblkno; md.level = 0; @@ -1230,11 +1230,11 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, xl_btree_vacuum xlrec_vacuum; xlrec_vacuum.ndeleted = ndeletable; - xlrec_vacuum.nupdated = nupdatable; + xlrec_vacuum.nupdated = nupdatable; - XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); - XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum); if (ndeletable > 0) XLogRegisterBufData(0, (char *) deletable, @@ -1349,11 +1349,11 @@ _bt_delitems_delete(Relation rel, Buffer buf, xlrec_delete.snapshotConflictHorizon = snapshotConflictHorizon; xlrec_delete.ndeleted = ndeletable; xlrec_delete.nupdated = nupdatable; - xlrec_delete.isCatalogRel = isCatalogRel; + xlrec_delete.isCatalogRel = isCatalogRel; - XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); - XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); if (ndeletable > 0) XLogRegisterBufData(0, (char *) deletable, @@ -2258,13 +2258,13 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf, if (topparent != leafblkno) xlrec.topparent = topparent; else - xlrec.topparent = InvalidBlockNumber; + xlrec.topparent = InvalidBlockNumber; - XLogBeginInsert(); - XLogRegisterBufferForRelation(0, leafbuf, REGBUF_WILL_INIT, rel); - XLogRegisterBufferForRelation(1, subtreeparent, REGBUF_STANDARD, rel); + XLogBeginInsert(); + XLogRegisterBufferForRelation(0, leafbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(1, subtreeparent, REGBUF_STANDARD, rel); - page = BufferGetPage(leafbuf); + page = BufferGetPage(leafbuf); opaque = BTPageGetOpaque(page); xlrec.leftblk = opaque->btpo_prev; xlrec.rightblk = opaque->btpo_next; @@ -2674,17 +2674,17 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, uint8 xlinfo; XLogRecPtr recptr; - XLogBeginInsert(); + XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_WILL_INIT, rel); - if (BufferIsValid(lbuf)) - XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); - XLogRegisterBufferForRelation(2, rbuf, REGBUF_STANDARD, rel); - if (target != leafblkno) - XLogRegisterBufferForRelation(3, leafbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBufferForRelation(0, buf, REGBUF_WILL_INIT, rel); + if (BufferIsValid(lbuf)) + XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); + XLogRegisterBufferForRelation(2, rbuf, REGBUF_STANDARD, rel); + if (target != leafblkno) + XLogRegisterBufferForRelation(3, leafbuf, REGBUF_WILL_INIT, rel); - /* information stored on the target/to-be-unlinked block */ - xlrec.leftsib = leftsib; + /* information stored on the target/to-be-unlinked block */ + xlrec.leftsib = leftsib; xlrec.rightsib = rightsib; xlrec.level = targetlevel; xlrec.safexid = safexid; @@ -2696,11 +2696,11 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, XLogRegisterData((char *) &xlrec, SizeOfBtreeUnlinkPage); - if (BufferIsValid(metabuf)) - { - XLogRegisterBufferForRelation(4, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); + if (BufferIsValid(metabuf)) + { + XLogRegisterBuffer(4, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); - Assert(metad->btm_version >= BTREE_NOVAC_VERSION); + Assert(metad->btm_version >= BTREE_NOVAC_VERSION); xlmeta.version = metad->btm_version; xlmeta.root = metad->btm_root; xlmeta.level = metad->btm_level; diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index e6d914265fc..4974218391e 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -535,15 +535,15 @@ XLogInsert(RmgrId rmid, uint8 info) */ GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites); - /* - * NEON: Check if we should suppress FPI for this WAL record. - */ - suppress_fpi = false; - if (xlog_should_suppress_fpi_hook != NULL) { - suppress_fpi = xlog_should_suppress_fpi_hook(rmid); - elog(DEBUG1, "FPI suppress hook called: rmid=%u, suppress_fpi=%d, doPageWrites=%d", - rmid, suppress_fpi, doPageWrites); - } + /* + * NEON: Check if we should suppress FPI for this WAL record. + */ + suppress_fpi = false; + if (xlog_should_suppress_fpi_hook != NULL) { + suppress_fpi = xlog_should_suppress_fpi_hook(rmid); + elog(DEBUG1, "FPI suppress hook called: rmid=%u, suppress_fpi=%d, doPageWrites=%d", + rmid, suppress_fpi, doPageWrites); + } rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, &fpw_lsn, &num_fpi, &topxid_included); From a8c6ae6dca4cf2bf47526b2757a533e7fae73dfd Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Thu, 4 Dec 2025 19:22:35 +0000 Subject: [PATCH 7/9] undo reloption changes --- src/backend/access/common/reloptions.c | 13 +-- src/backend/access/heap/heapam.c | 27 +++--- src/backend/access/nbtree/nbtdedup.c | 2 +- src/backend/access/nbtree/nbtinsert.c | 37 ++++---- src/backend/access/nbtree/nbtpage.c | 22 ++--- src/backend/access/transam/xloginsert.c | 2 +- src/backend/commands/tablecmds.c | 76 ----------------- src/backend/utils/cache/relcache.c | 109 ------------------------ src/include/access/xloginsert.h | 20 ----- src/include/utils/rel.h | 17 ---- 10 files changed, 44 insertions(+), 281 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 434ff8dc213..c6a2d13be8d 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -166,15 +166,6 @@ static relopt_bool boolRelOpts[] = }, true }, - { - { - "reduce_fpi", - "Reduces full page images in WAL for this table", - RELOPT_KIND_HEAP, /* regular tables only - indexes/toast derive from parent */ - ShareUpdateExclusiveLock /* applies only to subsequent WAL writes, like fillfactor */ - }, - false - }, /* list terminator */ {{NULL}} }; @@ -1898,9 +1889,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind) {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, offsetof(StdRdOptions, vacuum_index_cleanup)}, {"vacuum_truncate", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, vacuum_truncate)}, - {"reduce_fpi", RELOPT_TYPE_BOOL, - offsetof(StdRdOptions, reduce_fpi)} + offsetof(StdRdOptions, vacuum_truncate)} }; return (bytea *) build_reloptions(reloptions, validate, kind, diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 896f8333235..41200e9db11 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2200,8 +2200,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid, * write the whole page to the xlog, we don't need to store * xl_heap_header in the xlog. */ - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD | bufflags, - relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags); XLogRegisterBufData(0, (char *) &xlhdr, SizeOfNeonHeapHeader); /* PG73FORMAT: write bitmap [+ padding] [+ oid] + data */ XLogRegisterBufData(0, @@ -3116,7 +3115,7 @@ heap_delete(Relation relation, ItemPointer tid, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); /* * Log replica identity of the deleted tuple if there is one @@ -3888,7 +3887,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); xlrec.offnum = ItemPointerGetOffsetNumber(&oldtup.t_self); xlrec.xmax = xmax_lock_old_tuple; @@ -5221,7 +5220,7 @@ heap_lock_tuple(Relation relation, HeapTuple tuple, XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, *buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, *buffer, REGBUF_STANDARD); xlrec.offnum = ItemPointerGetOffsetNumber(&tuple->t_self); xlrec.xmax = xid; @@ -5974,7 +5973,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, Page page = BufferGetPage(buf); XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, buf, REGBUF_STANDARD); xlrec.offnum = ItemPointerGetOffsetNumber(&mytup.t_self); xlrec.xmax = new_xmax; @@ -6136,7 +6135,7 @@ heap_finish_speculative(Relation relation, ItemPointer tid) XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN); XLogRegisterData((char *) &xlrec, SizeOfHeapConfirm); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); recptr = XLogInsert(RM_HEAP_ID, XLOG_HEAP_CONFIRM); @@ -6293,7 +6292,7 @@ heap_abort_speculative(Relation relation, ItemPointer tid) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapDelete); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); /* No replica identity & replication origin logged */ @@ -6537,7 +6536,7 @@ heap_inplace_update_and_unlock(Relation relation, XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -6640,7 +6639,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfHeapInplace); - XLogRegisterBufferForRelation(0, buffer, REGBUF_STANDARD, relation); + XLogRegisterBuffer(0, buffer, REGBUF_STANDARD); XLogRegisterBufData(0, (char *) htup + htup->t_hoff, newlen); /* inplace updates aren't decoded atm, don't log the origin */ @@ -8862,7 +8861,7 @@ log_heap_visible(Relation rel, Buffer heap_buffer, Buffer vm_buffer, flags = REGBUF_STANDARD; if (!XLogHintBitIsNeeded()) flags |= REGBUF_NO_IMAGE; - XLogRegisterBufferForRelation(1, heap_buffer, flags, rel); + XLogRegisterBuffer(1, heap_buffer, flags); recptr = XLogInsert(RM_HEAP2_ID, XLOG_HEAP2_VISIBLE); @@ -9003,11 +9002,9 @@ log_heap_update(Relation reln, Buffer oldbuf, if (need_tuple_data) bufflags |= REGBUF_KEEP_DATA; - XLogRegisterBufferForRelation(0, newbuf, bufflags, reln); + XLogRegisterBuffer(0, newbuf, bufflags); if (oldbuf != newbuf) - { - XLogRegisterBufferForRelation(1, oldbuf, REGBUF_STANDARD, reln); - } + XLogRegisterBuffer(1, oldbuf, REGBUF_STANDARD); XLogRegisterData((char *) &xlrec, SizeOfNeonHeapUpdate); diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index a3dfd926566..456d86b51c9 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -251,7 +251,7 @@ _bt_dedup_pass(Relation rel, Buffer buf, IndexTuple newitem, Size newitemsz, xlrec_dedup.nintervals = state->nintervals; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, buf, REGBUF_STANDARD); XLogRegisterData((char *) &xlrec_dedup, SizeOfBtreeDedup); /* diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index fbd07cddc49..146b19991be 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -1337,13 +1337,13 @@ _bt_insertonpg(Relation rel, Assert(isleaf); xlinfo = XLOG_BTREE_INSERT_POST; } - else - { - /* Internal page insert, which finishes a split on cbuf */ - xlinfo = XLOG_BTREE_INSERT_UPPER; - XLogRegisterBufferForRelation(1, cbuf, REGBUF_STANDARD, rel); + else + { + /* Internal page insert, which finishes a split on cbuf */ + xlinfo = XLOG_BTREE_INSERT_UPPER; + XLogRegisterBuffer(1, cbuf, REGBUF_STANDARD); - if (BufferIsValid(metabuf)) + if (BufferIsValid(metabuf)) { /* Actually, it's an internal page insert + meta update */ xlinfo = XLOG_BTREE_INSERT_META; @@ -1357,16 +1357,15 @@ _bt_insertonpg(Relation rel, xlmeta.last_cleanup_num_delpages = metad->btm_last_cleanup_num_delpages; xlmeta.allequalimage = metad->btm_allequalimage; - XLogRegisterBufferForRelation(2, metabuf, - REGBUF_WILL_INIT | REGBUF_STANDARD, - rel); + XLogRegisterBuffer(2, metabuf, + REGBUF_WILL_INIT | REGBUF_STANDARD); XLogRegisterBufData(2, (char *) &xlmeta, sizeof(xl_btree_metadata)); } - } + } - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); - if (postingoff == 0) + XLogRegisterBuffer(0, buf, REGBUF_STANDARD); + if (postingoff == 0) { /* Just log itup from caller */ XLogRegisterBufData(0, (char *) itup, IndexTupleSize(itup)); @@ -2017,13 +2016,13 @@ _bt_split(Relation rel, Relation heaprel, BTScanInsert itup_key, Buffer buf, bufflags |= REGBUF_FORCE_IMAGE; } - XLogRegisterBufferForRelation(0, buf, bufflags, rel); - XLogRegisterBufferForRelation(1, rbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBuffer(0, buf, bufflags); + XLogRegisterBuffer(1, rbuf, REGBUF_WILL_INIT); /* Log original right sibling, since we've changed its prev-pointer */ if (!isrightmost) - XLogRegisterBufferForRelation(2, sbuf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(2, sbuf, REGBUF_STANDARD); if (!isleaf) - XLogRegisterBufferForRelation(3, cbuf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(3, cbuf, REGBUF_STANDARD); /* * Log the new item, if it was inserted on the left page. (If it was @@ -2602,9 +2601,9 @@ _bt_newlevel(Relation rel, Relation heaprel, Buffer lbuf, Buffer rbuf) XLogBeginInsert(); XLogRegisterData((char *) &xlrec, SizeOfBtreeNewroot); - XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); - XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); - XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT); + XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD); + XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index a8c33f2c24f..01bbece6bfd 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -288,7 +288,7 @@ _bt_set_cleanup_info(Relation rel, BlockNumber num_delpages) XLogRecPtr recptr; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; @@ -476,8 +476,8 @@ _bt_getroot(Relation rel, Relation heaprel, int access) xl_btree_metadata md; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, rootbuf, REGBUF_WILL_INIT, rel); - XLogRegisterBufferForRelation(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, rootbuf, REGBUF_WILL_INIT); + XLogRegisterBuffer(2, metabuf, REGBUF_WILL_INIT | REGBUF_STANDARD); Assert(metad->btm_version >= BTREE_NOVAC_VERSION); md.version = metad->btm_version; @@ -1233,7 +1233,7 @@ _bt_delitems_vacuum(Relation rel, Buffer buf, xlrec_vacuum.nupdated = nupdatable; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, buf, REGBUF_STANDARD); XLogRegisterData((char *) &xlrec_vacuum, SizeOfBtreeVacuum); if (ndeletable > 0) @@ -1352,7 +1352,7 @@ _bt_delitems_delete(Relation rel, Buffer buf, xlrec_delete.isCatalogRel = isCatalogRel; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, buf, REGBUF_STANDARD); XLogRegisterData((char *) &xlrec_delete, SizeOfBtreeDelete); if (ndeletable > 0) @@ -2261,8 +2261,8 @@ _bt_mark_page_halfdead(Relation rel, Relation heaprel, Buffer leafbuf, xlrec.topparent = InvalidBlockNumber; XLogBeginInsert(); - XLogRegisterBufferForRelation(0, leafbuf, REGBUF_WILL_INIT, rel); - XLogRegisterBufferForRelation(1, subtreeparent, REGBUF_STANDARD, rel); + XLogRegisterBuffer(0, leafbuf, REGBUF_WILL_INIT); + XLogRegisterBuffer(1, subtreeparent, REGBUF_STANDARD); page = BufferGetPage(leafbuf); opaque = BTPageGetOpaque(page); @@ -2676,12 +2676,12 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, XLogBeginInsert(); - XLogRegisterBufferForRelation(0, buf, REGBUF_WILL_INIT, rel); + XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT); if (BufferIsValid(lbuf)) - XLogRegisterBufferForRelation(1, lbuf, REGBUF_STANDARD, rel); - XLogRegisterBufferForRelation(2, rbuf, REGBUF_STANDARD, rel); + XLogRegisterBuffer(1, lbuf, REGBUF_STANDARD); + XLogRegisterBuffer(2, rbuf, REGBUF_STANDARD); if (target != leafblkno) - XLogRegisterBufferForRelation(3, leafbuf, REGBUF_WILL_INIT, rel); + XLogRegisterBuffer(3, leafbuf, REGBUF_WILL_INIT); /* information stored on the target/to-be-unlinked block */ xlrec.leftsib = leftsib; diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 4974218391e..ae345591bc5 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -645,7 +645,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, */ XLogRecPtr page_lsn = PageGetLSN(regbuf->page); - if (suppress_fpi && (regbuf->flags & REGBUF_REDUCE_FPI)) + if (suppress_fpi) needs_backup = false; else needs_backup = (page_lsn <= RedoRecPtr); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 52f16288059..3ba65a33a12 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -612,7 +612,6 @@ static void ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacename, LOCKMODE lockmode); static void ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode); static void ATExecSetTableSpaceNoStorage(Relation rel, Oid newTableSpace); -static void InvalidateReduceFPIChildren(Relation rel); static void ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, LOCKMODE lockmode); @@ -15043,51 +15042,6 @@ ATPrepSetTableSpace(AlteredTableInfo *tab, Relation rel, const char *tablespacen tab->newTableSpace = tablespaceId; } -/* - * InvalidateReduceFPIChildren - * - * When reduce_fpi changes on a heap table, invalidate relcache entries for - * all child relations (indexes and toast tables) so they re-derive the new - * value from the parent. - */ -static void -InvalidateReduceFPIChildren(Relation rel) -{ - List *indexoidlist; - ListCell *indexoidscan; - - /* Invalidate all indexes on this relation */ - indexoidlist = RelationGetIndexList(rel); - foreach(indexoidscan, indexoidlist) - { - Oid indexoid = lfirst_oid(indexoidscan); - - CacheInvalidateRelcacheByRelid(indexoid); - } - list_free(indexoidlist); - - /* Invalidate toast table and its indexes */ - if (OidIsValid(rel->rd_rel->reltoastrelid)) - { - Oid toastrelid = rel->rd_rel->reltoastrelid; - Relation toastrel; - - CacheInvalidateRelcacheByRelid(toastrelid); - - /* Also invalidate toast table's indexes */ - toastrel = table_open(toastrelid, AccessShareLock); - indexoidlist = RelationGetIndexList(toastrel); - foreach(indexoidscan, indexoidlist) - { - Oid indexoid = lfirst_oid(indexoidscan); - - CacheInvalidateRelcacheByRelid(indexoid); - } - list_free(indexoidlist); - table_close(toastrel, AccessShareLock); - } -} - /* * Set, reset, or replace reloptions. */ @@ -15226,36 +15180,6 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation, ReleaseSysCache(tuple); - /* - * If this is a heap relation and reduce_fpi was changed, invalidate - * relcache for all indexes and toast relations so they pick up the new - * value in their rd_reduce_fpi field. - */ - /* - * For regular tables, if reduce_fpi changed, we need to invalidate - * child relations (indexes and toast) so they re-derive the new value. - */ - if (rel->rd_rel->relkind == RELKIND_RELATION) - { - ListCell *cell; - bool reduce_fpi_changed = false; - - /* Check if reduce_fpi was in the ALTER statement */ - foreach(cell, defList) - { - DefElem *defel = (DefElem *) lfirst(cell); - - if (strcmp(defel->defname, "reduce_fpi") == 0) - { - reduce_fpi_changed = true; - break; - } - } - - if (reduce_fpi_changed) - InvalidateReduceFPIChildren(rel); - } - /* repeat the whole exercise for the toast table, if there's one */ if (OidIsValid(rel->rd_rel->reltoastrelid)) { diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index bf458fc9138..f5f0d60d33c 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -511,112 +511,6 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple) } } -/* - * RelationInitReduceFPI - * Initialize rd_reduce_fpi flag for a relation - * - * For heap: reads from StdRdOptions.reduce_fpi reloption. - * For index: derives from parent heap's rd_reduce_fpi. - * For toast: derives from parent heap's rd_reduce_fpi. - * - * Must be called after rd_rel, rd_index, and rd_options are set. - */ -static void -RelationInitReduceFPI(Relation relation) -{ - relation->rd_reduce_fpi = false; - - switch (relation->rd_rel->relkind) - { - case RELKIND_RELATION: - { - if (relation->rd_options) - { - StdRdOptions *opts = (StdRdOptions *) relation->rd_options; - relation->rd_reduce_fpi = opts->reduce_fpi; - } - break; - } - - case RELKIND_INDEX: - { - /* - * Index: derive from parent relation. - * - * This handles both: - * 1. Main table's indexes: index->indrelid points to table, - * which already has rd_reduce_fpi set from its reloption. - * 2. Toast table's indexes: index->indrelid points to toast table, - * which already has rd_reduce_fpi derived from its parent table - * (see RELKIND_TOASTVALUE case below). - * - * Safety: RelationIdGetRelation() will build the parent's relcache - * entry if it doesn't exist yet (calling RelationBuildDesc() which - * includes RelationInitReduceFPI()). Otherwise it returns the - * already-built entry. Either way, by the time we read - * parent->rd_reduce_fpi, it's guaranteed to be initialized. - * Worst case: we read false (the safe default). - */ - if (relation->rd_index && OidIsValid(relation->rd_index->indrelid)) - { - Relation parent = RelationIdGetRelation(relation->rd_index->indrelid); - - if (RelationIsValid(parent)) - { - relation->rd_reduce_fpi = parent->rd_reduce_fpi; - RelationClose(parent); - } - } - break; - } - - case RELKIND_TOASTVALUE: - { - /* - * Toast table: find parent heap via pg_class.reltoastrelid. - * We search for the heap relation that has this toast table as its - * reltoastrelid. - */ - Relation pg_class; - SysScanDesc scan; - HeapTuple tuple; - ScanKeyData key[1]; - - pg_class = table_open(RelationRelationId, AccessShareLock); - - /* Scan for heap relation with this toast OID */ - ScanKeyInit(&key[0], - Anum_pg_class_reltoastrelid, - BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(RelationGetRelid(relation))); - - scan = systable_beginscan(pg_class, InvalidOid, false, - NULL, 1, key); - - tuple = systable_getnext(scan); - if (HeapTupleIsValid(tuple)) - { - Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple); - Relation parent = RelationIdGetRelation(classtup->oid); - - if (RelationIsValid(parent)) - { - relation->rd_reduce_fpi = parent->rd_reduce_fpi; - RelationClose(parent); - } - } - - systable_endscan(scan); - table_close(pg_class, AccessShareLock); - break; - } - - default: - /* Other relkinds don't use reduce_fpi */ - break; - } -} - /* * RelationBuildTupleDesc * @@ -1328,9 +1222,6 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); - /* initialize reduce_fpi flag */ - RelationInitReduceFPI(relation); - /* * Fetch rules and triggers that affect this relation. * diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index a56656e06c5..8543766a5c5 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -16,7 +16,6 @@ #include "storage/block.h" #include "storage/buf.h" #include "storage/relfilelocator.h" -#include "utils/rel.h" #include "utils/relcache.h" /* @@ -39,8 +38,6 @@ #define REGBUF_KEEP_DATA 0x10 /* include data even if a full-page image * is taken */ #define REGBUF_NO_CHANGE 0x20 /* intentionally register clean buffer */ -#define REGBUF_REDUCE_FPI 0x40 /* relation has reduce_fpi enabled, suppress - * full page images when possible */ extern int max_replication_apply_lag; extern int max_replication_flush_lag; @@ -82,21 +79,4 @@ extern XLogRecPtr XLogSaveBufferForHint(Buffer buffer, bool buffer_std); extern void InitXLogInsert(void); -/* - * XLogRegisterBufferForRelation - * Convenience wrapper for XLogRegisterBuffer that automatically sets - * REGBUF_REDUCE_FPI based on the relation's reduce_fpi setting. - * - * This helper simplifies the code by eliminating the need to manually - * check RelationGetReduceFPI() at every call site. - */ -static inline void -XLogRegisterBufferForRelation(uint8 block_id, Buffer buffer, uint8 flags, - Relation rel) -{ - if (RelationGetReduceFPI(rel)) - flags |= REGBUF_REDUCE_FPI; - XLogRegisterBuffer(block_id, buffer, flags); -} - #endif /* XLOGINSERT_H */ diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 70ad05bcb7f..50d95bb8cb9 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -174,14 +174,6 @@ typedef struct RelationData */ bytea *rd_options; /* parsed pg_class.reloptions */ - /* - * rd_reduce_fpi: derived flag for reduced full-page-image WAL logging. - * For regular tables (RELKIND_RELATION): comes from StdRdOptions.reduce_fpi reloption. - * For index: derived from parent table's rd_reduce_fpi. - * For toast: derived from parent table's rd_reduce_fpi. - */ - bool rd_reduce_fpi; /* enable reduced FPI for this relation */ - /* * Oid of the handler for this relation. For an index this is a function * returning IndexAmRoutine, for table like relations a function returning @@ -351,7 +343,6 @@ typedef struct StdRdOptions int parallel_workers; /* max number of parallel workers */ StdRdOptIndexCleanup vacuum_index_cleanup; /* controls index vacuuming */ bool vacuum_truncate; /* enables vacuum to truncate a relation */ - bool reduce_fpi; /* reduce full page images in WAL */ } StdRdOptions; #define HEAP_MIN_FILLFACTOR 10 @@ -407,14 +398,6 @@ typedef struct StdRdOptions ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->parallel_workers : (defaultpw)) -/* - * RelationGetReduceFPI - * Returns whether the relation has reduce_fpi enabled. - * For heap: comes from reloption. - * For index/toast: derived from parent heap. - */ -#define RelationGetReduceFPI(relation) ((relation)->rd_reduce_fpi) - /* ViewOptions->check_option values */ typedef enum ViewOptCheckOption { From 3522ccd1b1ce1e7ef37ba79bd1bb151bda5e6a0a Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Fri, 5 Dec 2025 02:54:24 +0000 Subject: [PATCH 8/9] undo rmgr changes --- src/backend/access/transam/xloginsert.c | 6 +++--- src/include/access/xloginsert.h | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index ae345591bc5..0a85daafdc0 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -540,9 +540,9 @@ XLogInsert(RmgrId rmid, uint8 info) */ suppress_fpi = false; if (xlog_should_suppress_fpi_hook != NULL) { - suppress_fpi = xlog_should_suppress_fpi_hook(rmid); - elog(DEBUG1, "FPI suppress hook called: rmid=%u, suppress_fpi=%d, doPageWrites=%d", - rmid, suppress_fpi, doPageWrites); + suppress_fpi = xlog_should_suppress_fpi_hook(); + elog(DEBUG1, "FPI suppress hook called: suppress_fpi=%d, doPageWrites=%d", + suppress_fpi, doPageWrites); } rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, diff --git a/src/include/access/xloginsert.h b/src/include/access/xloginsert.h index 8543766a5c5..d66f2f055c1 100644 --- a/src/include/access/xloginsert.h +++ b/src/include/access/xloginsert.h @@ -45,10 +45,9 @@ extern int max_replication_write_lag; /* NEON: Hook to determine if FPI should be suppressed for a WAL record * Returns true to suppress FPI, false to allow FPI - * Parameters: - * rmid - Resource manager ID (e.g., RM_HEAP_ID, RM_BTREE_ID) + * Applies to all resource managers for checkpoint-based FPI triggers. */ -typedef bool (*xlog_should_suppress_fpi_hook_type)(RmgrId rmid); +typedef bool (*xlog_should_suppress_fpi_hook_type)(void); extern PGDLLIMPORT xlog_should_suppress_fpi_hook_type xlog_should_suppress_fpi_hook; /* NEON: Flag set per-record to suppress FPI (set by xlog_should_suppress_fpi_hook) */ From 446fdf46e614b1e7a1fca54b829dac95705f58e0 Mon Sep 17 00:00:00 2001 From: Yanan Xin Date: Mon, 8 Dec 2025 18:58:01 +0000 Subject: [PATCH 9/9] review comments, simplify code --- src/backend/access/transam/xloginsert.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 0a85daafdc0..aa2783a2064 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -634,7 +634,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, needs_backup = true; else if (regbuf->flags & REGBUF_NO_IMAGE) needs_backup = false; - else if (!doPageWrites) + else if (!doPageWrites || suppress_fpi) needs_backup = false; else { @@ -645,10 +645,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, */ XLogRecPtr page_lsn = PageGetLSN(regbuf->page); - if (suppress_fpi) - needs_backup = false; - else - needs_backup = (page_lsn <= RedoRecPtr); + needs_backup = (page_lsn <= RedoRecPtr); if (!needs_backup) {