diff options
| author | Amit Kapila <akapila@postgresql.org> | 2025-11-28 05:21:35 +0000 |
|---|---|---|
| committer | Amit Kapila <akapila@postgresql.org> | 2025-11-28 05:21:35 +0000 |
| commit | e68b6adad96d414fdf24e072fdb1d41fb4b8f0b7 (patch) | |
| tree | 36cbdc3befc3b490893d4daa2184aa664ca46adb /src/backend | |
| parent | 9ccc049dfe655ca9927f7c62559ec32f4d1f94dd (diff) | |
Add slotsync_skip_reason column to pg_replication_slots view.
Introduce a new column, slotsync_skip_reason, in the pg_replication_slots
view. This column records the reason why the last slot synchronization was
skipped. It is primarily relevant for logical replication slots on standby
servers where the 'synced' field is true. The value is NULL when
synchronization succeeds.
Author: Shlok Kyal <shlok.kyal.oss@gmail.com>
Reviewed-by: shveta malik <shveta.malik@gmail.com>
Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Reviewed-by: Ashutosh Sharma <ashu.coek88@gmail.com>
Reviewed-by: Hou Zhijie <houzj.fnst@fujitsu.com>
Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
Discussion: https://postgr.es/m/CAE9k0PkhfKrTEAsGz4DjOhEj1nQ+hbQVfvWUxNacD38ibW3a1g@mail.gmail.com
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/catalog/system_views.sql | 3 | ||||
| -rw-r--r-- | src/backend/replication/logical/slotsync.c | 43 | ||||
| -rw-r--r-- | src/backend/replication/slot.c | 1 | ||||
| -rw-r--r-- | src/backend/replication/slotfuncs.c | 18 | ||||
| -rw-r--r-- | src/backend/utils/activity/pgstat_replslot.c | 4 |
5 files changed, 60 insertions, 9 deletions
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 6fffdb9398e..086c4c8fb6f 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1060,7 +1060,8 @@ CREATE VIEW pg_replication_slots AS L.conflicting, L.invalidation_reason, L.failover, - L.synced + L.synced, + L.slotsync_skip_reason FROM pg_get_replication_slots() AS L LEFT JOIN pg_database D ON (L.datoid = D.oid); diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c index 1f4f06d467b..53c7d629239 100644 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@ -149,6 +149,35 @@ static void slotsync_failure_callback(int code, Datum arg); static void update_synced_slots_inactive_since(void); /* + * Update slot sync skip stats. This function requires the caller to acquire + * the slot. + */ +static void +update_slotsync_skip_stats(SlotSyncSkipReason skip_reason) +{ + ReplicationSlot *slot; + + Assert(MyReplicationSlot); + + slot = MyReplicationSlot; + + /* + * Update the slot sync related stats in pg_stat_replication_slot when a + * slot sync is skipped + */ + if (skip_reason != SS_SKIP_NONE) + pgstat_report_replslotsync(slot); + + /* Update the slot sync skip reason */ + if (slot->slotsync_skip_reason != skip_reason) + { + SpinLockAcquire(&slot->mutex); + slot->slotsync_skip_reason = skip_reason; + SpinLockRelease(&slot->mutex); + } +} + +/* * If necessary, update the local synced slot's metadata based on the data * from the remote slot. * @@ -170,6 +199,7 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid, ReplicationSlot *slot = MyReplicationSlot; bool updated_xmin_or_lsn = false; bool updated_config = false; + SlotSyncSkipReason skip_reason = SS_SKIP_NONE; Assert(slot->data.invalidated == RS_INVAL_NONE); @@ -188,7 +218,7 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid, slot->data.catalog_xmin)) { /* Update slot sync skip stats */ - pgstat_report_replslotsync(slot); + update_slotsync_skip_stats(SS_SKIP_WAL_OR_ROWS_REMOVED); /* * This can happen in following situations: @@ -286,12 +316,15 @@ update_local_synced_slot(RemoteSlot *remote_slot, Oid remote_dbid, * persisted. See update_and_persist_local_synced_slot(). */ if (found_consistent_snapshot && !(*found_consistent_snapshot)) - pgstat_report_replslotsync(slot); + skip_reason = SS_SKIP_NO_CONSISTENT_SNAPSHOT; } updated_xmin_or_lsn = true; } + /* Update slot sync skip stats */ + update_slotsync_skip_stats(skip_reason); + if (remote_dbid != slot->data.database || remote_slot->two_phase != slot->data.two_phase || remote_slot->failover != slot->data.failover || @@ -696,7 +729,7 @@ synchronize_one_slot(RemoteSlot *remote_slot, Oid remote_dbid) /* Skip the sync of an invalidated slot */ if (slot->data.invalidated != RS_INVAL_NONE) { - pgstat_report_replslotsync(slot); + update_slotsync_skip_stats(SS_SKIP_INVALID); ReplicationSlotRelease(); return slot_updated; @@ -711,7 +744,7 @@ synchronize_one_slot(RemoteSlot *remote_slot, Oid remote_dbid) */ if (remote_slot->confirmed_lsn > latestFlushPtr) { - pgstat_report_replslotsync(slot); + update_slotsync_skip_stats(SS_SKIP_WAL_NOT_FLUSHED); /* * Can get here only if GUC 'synchronized_standby_slots' on the @@ -812,7 +845,7 @@ synchronize_one_slot(RemoteSlot *remote_slot, Oid remote_dbid) */ if (remote_slot->confirmed_lsn > latestFlushPtr) { - pgstat_report_replslotsync(slot); + update_slotsync_skip_stats(SS_SKIP_WAL_NOT_FLUSHED); /* * Can get here only if GUC 'synchronized_standby_slots' on the diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 1ec1e997b27..86ae99a3ca9 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -491,6 +491,7 @@ ReplicationSlotCreate(const char *name, bool db_specific, slot->last_saved_confirmed_flush = InvalidXLogRecPtr; slot->last_saved_restart_lsn = InvalidXLogRecPtr; slot->inactive_since = 0; + slot->slotsync_skip_reason = SS_SKIP_NONE; /* * Create the slot on disk. We haven't actually marked the slot allocated diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 0478fc9c977..7647f051581 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -25,6 +25,17 @@ #include "utils/pg_lsn.h" /* + * Map SlotSyncSkipReason enum values to human-readable names. + */ +static const char *SlotSyncSkipReasonNames[] = { + [SS_SKIP_NONE] = "none", + [SS_SKIP_WAL_NOT_FLUSHED] = "wal_not_flushed", + [SS_SKIP_WAL_OR_ROWS_REMOVED] = "wal_or_rows_removed", + [SS_SKIP_NO_CONSISTENT_SNAPSHOT] = "no_consistent_snapshot", + [SS_SKIP_INVALID] = "slot_invalidated" +}; + +/* * Helper function for creating a new physical replication slot with * given arguments. Note that this function doesn't release the created * slot. @@ -235,7 +246,7 @@ pg_drop_replication_slot(PG_FUNCTION_ARGS) Datum pg_get_replication_slots(PG_FUNCTION_ARGS) { -#define PG_GET_REPLICATION_SLOTS_COLS 20 +#define PG_GET_REPLICATION_SLOTS_COLS 21 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; XLogRecPtr currlsn; int slotno; @@ -443,6 +454,11 @@ pg_get_replication_slots(PG_FUNCTION_ARGS) values[i++] = BoolGetDatum(slot_contents.data.synced); + if (slot_contents.slotsync_skip_reason == SS_SKIP_NONE) + nulls[i++] = true; + else + values[i++] = CStringGetTextDatum(SlotSyncSkipReasonNames[slot_contents.slotsync_skip_reason]); + Assert(i == PG_GET_REPLICATION_SLOTS_COLS); tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, diff --git a/src/backend/utils/activity/pgstat_replslot.c b/src/backend/utils/activity/pgstat_replslot.c index f93179146c2..e08d33e8b4c 100644 --- a/src/backend/utils/activity/pgstat_replslot.c +++ b/src/backend/utils/activity/pgstat_replslot.c @@ -115,8 +115,8 @@ pgstat_report_replslotsync(ReplicationSlot *slot) PgStatShared_ReplSlot *shstatent; PgStat_StatReplSlotEntry *statent; - /* Slot sync stats are valid only for logical slots on standby. */ - Assert(SlotIsLogical(slot)); + /* Slot sync stats are valid only for synced logical slots on standby. */ + Assert(slot->data.synced); Assert(RecoveryInProgress()); entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_REPLSLOT, InvalidOid, |
