Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
slot.h File Reference
Include dependency graph for slot.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ReplicationSlotPersistentData
 
struct  ReplicationSlot
 
struct  ReplicationSlotCtlData
 

Macros

#define PG_REPLSLOT_DIR   "pg_replslot"
 
#define CONFLICT_DETECTION_SLOT   "pg_conflict_detection"
 
#define RS_INVAL_MAX_CAUSES   4
 
#define SlotIsPhysical(slot)   ((slot)->data.database == InvalidOid)
 
#define SlotIsLogical(slot)   ((slot)->data.database != InvalidOid)
 

Typedefs

typedef enum ReplicationSlotPersistency ReplicationSlotPersistency
 
typedef enum ReplicationSlotInvalidationCause ReplicationSlotInvalidationCause
 
typedef struct ReplicationSlotPersistentData ReplicationSlotPersistentData
 
typedef struct ReplicationSlot ReplicationSlot
 
typedef struct ReplicationSlotCtlData ReplicationSlotCtlData
 

Enumerations

enum  ReplicationSlotPersistency { RS_PERSISTENT , RS_EPHEMERAL , RS_TEMPORARY }
 
enum  ReplicationSlotInvalidationCause {
  RS_INVAL_NONE = 0 , RS_INVAL_WAL_REMOVED = (1 << 0) , RS_INVAL_HORIZON = (1 << 1) , RS_INVAL_WAL_LEVEL = (1 << 2) ,
  RS_INVAL_IDLE_TIMEOUT = (1 << 3)
}
 

Functions

static void ReplicationSlotSetInactiveSince (ReplicationSlot *s, TimestampTz ts, bool acquire_lock)
 
Size ReplicationSlotsShmemSize (void)
 
void ReplicationSlotsShmemInit (void)
 
void ReplicationSlotCreate (const char *name, bool db_specific, ReplicationSlotPersistency persistency, bool two_phase, bool failover, bool synced)
 
void ReplicationSlotPersist (void)
 
void ReplicationSlotDrop (const char *name, bool nowait)
 
void ReplicationSlotDropAcquired (void)
 
void ReplicationSlotAlter (const char *name, const bool *failover, const bool *two_phase)
 
void ReplicationSlotAcquire (const char *name, bool nowait, bool error_if_invalid)
 
void ReplicationSlotRelease (void)
 
void ReplicationSlotCleanup (bool synced_only)
 
void ReplicationSlotSave (void)
 
void ReplicationSlotMarkDirty (void)
 
void ReplicationSlotInitialize (void)
 
bool ReplicationSlotValidateName (const char *name, bool allow_reserved_name, int elevel)
 
void ReplicationSlotReserveWal (void)
 
void ReplicationSlotsComputeRequiredXmin (bool already_locked)
 
void ReplicationSlotsComputeRequiredLSN (void)
 
XLogRecPtr ReplicationSlotsComputeLogicalRestartLSN (void)
 
bool ReplicationSlotsCountDBSlots (Oid dboid, int *nslots, int *nactive)
 
void ReplicationSlotsDropDBSlots (Oid dboid)
 
bool InvalidateObsoleteReplicationSlots (uint32 possible_causes, XLogSegNo oldestSegno, Oid dboid, TransactionId snapshotConflictHorizon)
 
ReplicationSlotSearchNamedReplicationSlot (const char *name, bool need_lock)
 
int ReplicationSlotIndex (ReplicationSlot *slot)
 
bool ReplicationSlotName (int index, Name name)
 
void ReplicationSlotNameForTablesync (Oid suboid, Oid relid, char *syncslotname, Size szslot)
 
void ReplicationSlotDropAtPubNode (WalReceiverConn *wrconn, char *slotname, bool missing_ok)
 
void StartupReplicationSlots (void)
 
void CheckPointReplicationSlots (bool is_shutdown)
 
void CheckSlotRequirements (void)
 
void CheckSlotPermissions (void)
 
ReplicationSlotInvalidationCause GetSlotInvalidationCause (const char *cause_name)
 
const char * GetSlotInvalidationCauseName (ReplicationSlotInvalidationCause cause)
 
bool SlotExistsInSyncStandbySlots (const char *slot_name)
 
bool StandbySlotsHaveCaughtup (XLogRecPtr wait_for_lsn, int elevel)
 
void WaitForStandbyConfirmation (XLogRecPtr wait_for_lsn)
 

Variables

PGDLLIMPORT ReplicationSlotCtlDataReplicationSlotCtl
 
PGDLLIMPORT ReplicationSlotMyReplicationSlot
 
PGDLLIMPORT int max_replication_slots
 
PGDLLIMPORT char * synchronized_standby_slots
 
PGDLLIMPORT int idle_replication_slot_timeout_secs
 

Macro Definition Documentation

◆ CONFLICT_DETECTION_SLOT

#define CONFLICT_DETECTION_SLOT   "pg_conflict_detection"

Definition at line 28 of file slot.h.

◆ PG_REPLSLOT_DIR

#define PG_REPLSLOT_DIR   "pg_replslot"

Definition at line 21 of file slot.h.

◆ RS_INVAL_MAX_CAUSES

#define RS_INVAL_MAX_CAUSES   4

Definition at line 72 of file slot.h.

◆ SlotIsLogical

#define SlotIsLogical (   slot)    ((slot)->data.database != InvalidOid)

Definition at line 255 of file slot.h.

◆ SlotIsPhysical

#define SlotIsPhysical (   slot)    ((slot)->data.database == InvalidOid)

Definition at line 254 of file slot.h.

Typedef Documentation

◆ ReplicationSlot

◆ ReplicationSlotCtlData

◆ ReplicationSlotInvalidationCause

◆ ReplicationSlotPersistency

◆ ReplicationSlotPersistentData

Enumeration Type Documentation

◆ ReplicationSlotInvalidationCause

Enumerator
RS_INVAL_NONE 
RS_INVAL_WAL_REMOVED 
RS_INVAL_HORIZON 
RS_INVAL_WAL_LEVEL 
RS_INVAL_IDLE_TIMEOUT 

Definition at line 58 of file slot.h.

59{
60 RS_INVAL_NONE = 0,
61 /* required WAL has been removed */
62 RS_INVAL_WAL_REMOVED = (1 << 0),
63 /* required rows have been removed */
64 RS_INVAL_HORIZON = (1 << 1),
65 /* wal_level insufficient for slot */
66 RS_INVAL_WAL_LEVEL = (1 << 2),
67 /* idle slot timeout has occurred */
68 RS_INVAL_IDLE_TIMEOUT = (1 << 3),
ReplicationSlotInvalidationCause
Definition: slot.h:59
@ RS_INVAL_WAL_REMOVED
Definition: slot.h:62
@ RS_INVAL_IDLE_TIMEOUT
Definition: slot.h:68
@ RS_INVAL_HORIZON
Definition: slot.h:64
@ RS_INVAL_WAL_LEVEL
Definition: slot.h:66
@ RS_INVAL_NONE
Definition: slot.h:60

◆ ReplicationSlotPersistency

Enumerator
RS_PERSISTENT 
RS_EPHEMERAL 
RS_TEMPORARY 

Definition at line 43 of file slot.h.

44{
ReplicationSlotPersistency
Definition: slot.h:44
@ RS_PERSISTENT
Definition: slot.h:45
@ RS_EPHEMERAL
Definition: slot.h:46
@ RS_TEMPORARY
Definition: slot.h:47

Function Documentation

◆ CheckPointReplicationSlots()

void CheckPointReplicationSlots ( bool  is_shutdown)

Definition at line 2115 of file slot.c.

2116{
2117 int i;
2118 bool last_saved_restart_lsn_updated = false;
2119
2120 elog(DEBUG1, "performing replication slot checkpoint");
2121
2122 /*
2123 * Prevent any slot from being created/dropped while we're active. As we
2124 * explicitly do *not* want to block iterating over replication_slots or
2125 * acquiring a slot we cannot take the control lock - but that's OK,
2126 * because holding ReplicationSlotAllocationLock is strictly stronger, and
2127 * enough to guarantee that nobody can change the in_use bits on us.
2128 */
2129 LWLockAcquire(ReplicationSlotAllocationLock, LW_SHARED);
2130
2131 for (i = 0; i < max_replication_slots; i++)
2132 {
2134 char path[MAXPGPATH];
2135
2136 if (!s->in_use)
2137 continue;
2138
2139 /* save the slot to disk, locking is handled in SaveSlotToPath() */
2140 sprintf(path, "%s/%s", PG_REPLSLOT_DIR, NameStr(s->data.name));
2141
2142 /*
2143 * Slot's data is not flushed each time the confirmed_flush LSN is
2144 * updated as that could lead to frequent writes. However, we decide
2145 * to force a flush of all logical slot's data at the time of shutdown
2146 * if the confirmed_flush LSN is changed since we last flushed it to
2147 * disk. This helps in avoiding an unnecessary retreat of the
2148 * confirmed_flush LSN after restart.
2149 */
2150 if (is_shutdown && SlotIsLogical(s))
2151 {
2153
2154 if (s->data.invalidated == RS_INVAL_NONE &&
2156 {
2157 s->just_dirtied = true;
2158 s->dirty = true;
2159 }
2161 }
2162
2163 /*
2164 * Track if we're going to update slot's last_saved_restart_lsn. We
2165 * need this to know if we need to recompute the required LSN.
2166 */
2168 last_saved_restart_lsn_updated = true;
2169
2170 SaveSlotToPath(s, path, LOG);
2171 }
2172 LWLockRelease(ReplicationSlotAllocationLock);
2173
2174 /*
2175 * Recompute the required LSN if SaveSlotToPath() updated
2176 * last_saved_restart_lsn for any slot.
2177 */
2178 if (last_saved_restart_lsn_updated)
2180}
#define NameStr(name)
Definition: c.h:751
#define LOG
Definition: elog.h:31
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:226
int i
Definition: isn.c:77
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
#define MAXPGPATH
#define sprintf
Definition: port.h:241
static void SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
Definition: slot.c:2309
int max_replication_slots
Definition: slot.c:151
ReplicationSlotCtlData * ReplicationSlotCtl
Definition: slot.c:145
void ReplicationSlotsComputeRequiredLSN(void)
Definition: slot.c:1201
#define PG_REPLSLOT_DIR
Definition: slot.h:21
#define SlotIsLogical(slot)
Definition: slot.h:255
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
ReplicationSlot replication_slots[1]
Definition: slot.h:266
XLogRecPtr confirmed_flush
Definition: slot.h:118
ReplicationSlotInvalidationCause invalidated
Definition: slot.h:110
slock_t mutex
Definition: slot.h:165
XLogRecPtr last_saved_confirmed_flush
Definition: slot.h:217
bool in_use
Definition: slot.h:168
bool just_dirtied
Definition: slot.h:174
XLogRecPtr last_saved_restart_lsn
Definition: slot.h:250
bool dirty
Definition: slot.h:175
ReplicationSlotPersistentData data
Definition: slot.h:192

References ReplicationSlotPersistentData::confirmed_flush, ReplicationSlot::data, DEBUG1, ReplicationSlot::dirty, elog, i, ReplicationSlot::in_use, ReplicationSlotPersistentData::invalidated, ReplicationSlot::just_dirtied, ReplicationSlot::last_saved_confirmed_flush, ReplicationSlot::last_saved_restart_lsn, LOG, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, MAXPGPATH, ReplicationSlot::mutex, ReplicationSlotPersistentData::name, NameStr, PG_REPLSLOT_DIR, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotsComputeRequiredLSN(), ReplicationSlotPersistentData::restart_lsn, RS_INVAL_NONE, SaveSlotToPath(), SlotIsLogical, SpinLockAcquire, SpinLockRelease, and sprintf.

Referenced by CheckPointGuts().

◆ CheckSlotPermissions()

void CheckSlotPermissions ( void  )

Definition at line 1522 of file slot.c.

1523{
1525 ereport(ERROR,
1526 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1527 errmsg("permission denied to use replication slots"),
1528 errdetail("Only roles with the %s attribute may use replication slots.",
1529 "REPLICATION")));
1530}
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
Oid GetUserId(void)
Definition: miscinit.c:469
bool has_rolreplication(Oid roleid)
Definition: miscinit.c:688

References ereport, errcode(), errdetail(), errmsg(), ERROR, GetUserId(), and has_rolreplication().

Referenced by copy_replication_slot(), pg_create_logical_replication_slot(), pg_create_physical_replication_slot(), pg_drop_replication_slot(), pg_logical_slot_get_changes_guts(), pg_replication_slot_advance(), and pg_sync_replication_slots().

◆ CheckSlotRequirements()

void CheckSlotRequirements ( void  )

Definition at line 1500 of file slot.c.

1501{
1502 /*
1503 * NB: Adding a new requirement likely means that RestoreSlotFromDisk()
1504 * needs the same check.
1505 */
1506
1507 if (max_replication_slots == 0)
1508 ereport(ERROR,
1509 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1510 errmsg("replication slots can only be used if \"max_replication_slots\" > 0")));
1511
1513 ereport(ERROR,
1514 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1515 errmsg("replication slots can only be used if \"wal_level\" >= \"replica\"")));
1516}
int wal_level
Definition: xlog.c:132
@ WAL_LEVEL_REPLICA
Definition: xlog.h:75

References ereport, errcode(), errmsg(), ERROR, max_replication_slots, wal_level, and WAL_LEVEL_REPLICA.

Referenced by CheckLogicalDecodingRequirements(), copy_replication_slot(), pg_create_physical_replication_slot(), and pg_drop_replication_slot().

◆ GetSlotInvalidationCause()

ReplicationSlotInvalidationCause GetSlotInvalidationCause ( const char *  cause_name)

Definition at line 2707 of file slot.c.

2708{
2709 Assert(cause_name);
2710
2711 /* Search lookup table for the cause having this name */
2712 for (int i = 0; i <= RS_INVAL_MAX_CAUSES; i++)
2713 {
2714 if (strcmp(SlotInvalidationCauses[i].cause_name, cause_name) == 0)
2716 }
2717
2718 Assert(false);
2719 return RS_INVAL_NONE; /* to keep compiler quiet */
2720}
Assert(PointerIsAligned(start, uint64))
static const SlotInvalidationCauseMap SlotInvalidationCauses[]
Definition: slot.c:113
#define RS_INVAL_MAX_CAUSES
Definition: slot.h:72
ReplicationSlotInvalidationCause cause
Definition: slot.c:109

References Assert(), SlotInvalidationCauseMap::cause, i, RS_INVAL_MAX_CAUSES, RS_INVAL_NONE, and SlotInvalidationCauses.

Referenced by synchronize_slots().

◆ GetSlotInvalidationCauseName()

const char * GetSlotInvalidationCauseName ( ReplicationSlotInvalidationCause  cause)

Definition at line 2727 of file slot.c.

2728{
2729 /* Search lookup table for the name of this cause */
2730 for (int i = 0; i <= RS_INVAL_MAX_CAUSES; i++)
2731 {
2732 if (SlotInvalidationCauses[i].cause == cause)
2734 }
2735
2736 Assert(false);
2737 return "none"; /* to keep compiler quiet */
2738}
const char * cause_name
Definition: slot.c:110

References Assert(), SlotInvalidationCauseMap::cause_name, i, RS_INVAL_MAX_CAUSES, and SlotInvalidationCauses.

Referenced by pg_get_replication_slots(), and ReplicationSlotAcquire().

◆ InvalidateObsoleteReplicationSlots()

bool InvalidateObsoleteReplicationSlots ( uint32  possible_causes,
XLogSegNo  oldestSegno,
Oid  dboid,
TransactionId  snapshotConflictHorizon 
)

Definition at line 2055 of file slot.c.

2058{
2059 XLogRecPtr oldestLSN;
2060 bool invalidated = false;
2061
2062 Assert(!(possible_causes & RS_INVAL_HORIZON) || TransactionIdIsValid(snapshotConflictHorizon));
2063 Assert(!(possible_causes & RS_INVAL_WAL_REMOVED) || oldestSegno > 0);
2064 Assert(possible_causes != RS_INVAL_NONE);
2065
2066 if (max_replication_slots == 0)
2067 return invalidated;
2068
2069 XLogSegNoOffsetToRecPtr(oldestSegno, 0, wal_segment_size, oldestLSN);
2070
2071restart:
2072 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
2073 for (int i = 0; i < max_replication_slots; i++)
2074 {
2076
2077 if (!s->in_use)
2078 continue;
2079
2080 /* Prevent invalidation of logical slots during binary upgrade */
2082 continue;
2083
2084 if (InvalidatePossiblyObsoleteSlot(possible_causes, s, oldestLSN, dboid,
2085 snapshotConflictHorizon,
2086 &invalidated))
2087 {
2088 /* if the lock was released, start from scratch */
2089 goto restart;
2090 }
2091 }
2092 LWLockRelease(ReplicationSlotControlLock);
2093
2094 /*
2095 * If any slots have been invalidated, recalculate the resource limits.
2096 */
2097 if (invalidated)
2098 {
2101 }
2102
2103 return invalidated;
2104}
bool IsBinaryUpgrade
Definition: globals.c:121
void ReplicationSlotsComputeRequiredXmin(bool already_locked)
Definition: slot.c:1145
static bool InvalidatePossiblyObsoleteSlot(uint32 possible_causes, ReplicationSlot *s, XLogRecPtr oldestLSN, Oid dboid, TransactionId snapshotConflictHorizon, bool *invalidated)
Definition: slot.c:1803
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int wal_segment_size
Definition: xlog.c:144
#define XLogSegNoOffsetToRecPtr(segno, offset, wal_segsz_bytes, dest)
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References Assert(), i, ReplicationSlot::in_use, InvalidatePossiblyObsoleteSlot(), IsBinaryUpgrade, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotsComputeRequiredLSN(), ReplicationSlotsComputeRequiredXmin(), RS_INVAL_HORIZON, RS_INVAL_NONE, RS_INVAL_WAL_REMOVED, SlotIsLogical, TransactionIdIsValid, wal_segment_size, and XLogSegNoOffsetToRecPtr.

Referenced by CreateCheckPoint(), CreateRestartPoint(), ResolveRecoveryConflictWithSnapshot(), and xlog_redo().

◆ ReplicationSlotAcquire()

void ReplicationSlotAcquire ( const char *  name,
bool  nowait,
bool  error_if_invalid 
)

Definition at line 593 of file slot.c.

594{
596 int active_pid;
597
598 Assert(name != NULL);
599
600retry:
601 Assert(MyReplicationSlot == NULL);
602
603 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
604
605 /* Check if the slot exits with the given name. */
607 if (s == NULL || !s->in_use)
608 {
609 LWLockRelease(ReplicationSlotControlLock);
610
612 (errcode(ERRCODE_UNDEFINED_OBJECT),
613 errmsg("replication slot \"%s\" does not exist",
614 name)));
615 }
616
617 /*
618 * Do not allow users to acquire the reserved slot. This scenario may
619 * occur if the launcher that owns the slot has terminated unexpectedly
620 * due to an error, and a backend process attempts to reuse the slot.
621 */
624 errcode(ERRCODE_UNDEFINED_OBJECT),
625 errmsg("cannot acquire replication slot \"%s\"", name),
626 errdetail("The slot is reserved for conflict detection and can only be acquired by logical replication launcher."));
627
628 /*
629 * This is the slot we want; check if it's active under some other
630 * process. In single user mode, we don't need this check.
631 */
633 {
634 /*
635 * Get ready to sleep on the slot in case it is active. (We may end
636 * up not sleeping, but we don't want to do this while holding the
637 * spinlock.)
638 */
639 if (!nowait)
641
642 /*
643 * It is important to reset the inactive_since under spinlock here to
644 * avoid race conditions with slot invalidation. See comments related
645 * to inactive_since in InvalidatePossiblyObsoleteSlot.
646 */
648 if (s->active_pid == 0)
650 active_pid = s->active_pid;
653 }
654 else
655 {
656 s->active_pid = active_pid = MyProcPid;
658 }
659 LWLockRelease(ReplicationSlotControlLock);
660
661 /*
662 * If we found the slot but it's already active in another process, we
663 * wait until the owning process signals us that it's been released, or
664 * error out.
665 */
666 if (active_pid != MyProcPid)
667 {
668 if (!nowait)
669 {
670 /* Wait here until we get signaled, and then restart */
672 WAIT_EVENT_REPLICATION_SLOT_DROP);
674 goto retry;
675 }
676
678 (errcode(ERRCODE_OBJECT_IN_USE),
679 errmsg("replication slot \"%s\" is active for PID %d",
680 NameStr(s->data.name), active_pid)));
681 }
682 else if (!nowait)
683 ConditionVariableCancelSleep(); /* no sleep needed after all */
684
685 /* We made this slot active, so it's ours now. */
687
688 /*
689 * We need to check for invalidation after making the slot ours to avoid
690 * the possible race condition with the checkpointer that can otherwise
691 * invalidate the slot immediately after the check.
692 */
693 if (error_if_invalid && s->data.invalidated != RS_INVAL_NONE)
695 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
696 errmsg("can no longer access replication slot \"%s\"",
697 NameStr(s->data.name)),
698 errdetail("This replication slot has been invalidated due to \"%s\".",
700
701 /* Let everybody know we've modified this slot */
703
704 /*
705 * The call to pgstat_acquire_replslot() protects against stats for a
706 * different slot, from before a restart or such, being present during
707 * pgstat_report_replslot().
708 */
709 if (SlotIsLogical(s))
711
712
713 if (am_walsender)
714 {
717 ? errmsg("acquired logical replication slot \"%s\"",
718 NameStr(s->data.name))
719 : errmsg("acquired physical replication slot \"%s\"",
720 NameStr(s->data.name)));
721 }
722}
bool ConditionVariableCancelSleep(void)
void ConditionVariableBroadcast(ConditionVariable *cv)
void ConditionVariablePrepareToSleep(ConditionVariable *cv)
void ConditionVariableSleep(ConditionVariable *cv, uint32 wait_event_info)
int MyProcPid
Definition: globals.c:47
bool IsUnderPostmaster
Definition: globals.c:120
bool IsLogicalLauncher(void)
Definition: launcher.c:1531
void pgstat_acquire_replslot(ReplicationSlot *slot)
ReplicationSlot * MyReplicationSlot
Definition: slot.c:148
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
Definition: slot.c:513
const char * GetSlotInvalidationCauseName(ReplicationSlotInvalidationCause cause)
Definition: slot.c:2727
static bool IsSlotForConflictCheck(const char *name)
Definition: slot.c:329
static void ReplicationSlotSetInactiveSince(ReplicationSlot *s, TimestampTz ts, bool acquire_lock)
Definition: slot.h:273
pid_t active_pid
Definition: slot.h:171
ConditionVariable active_cv
Definition: slot.h:198
const char * name
bool am_walsender
Definition: walsender.c:123
bool log_replication_commands
Definition: walsender.c:133

References ReplicationSlot::active_cv, ReplicationSlot::active_pid, am_walsender, Assert(), ConditionVariableBroadcast(), ConditionVariableCancelSleep(), ConditionVariablePrepareToSleep(), ConditionVariableSleep(), ReplicationSlot::data, DEBUG1, ereport, errcode(), errdetail(), errmsg(), ERROR, GetSlotInvalidationCauseName(), ReplicationSlot::in_use, ReplicationSlotPersistentData::invalidated, IsLogicalLauncher(), IsSlotForConflictCheck(), IsUnderPostmaster, LOG, log_replication_commands, LW_SHARED, LWLockAcquire(), LWLockRelease(), ReplicationSlot::mutex, MyProcPid, MyReplicationSlot, name, ReplicationSlotPersistentData::name, NameStr, pgstat_acquire_replslot(), ReplicationSlotSetInactiveSince(), RS_INVAL_NONE, SearchNamedReplicationSlot(), SlotIsLogical, SpinLockAcquire, and SpinLockRelease.

Referenced by acquire_conflict_slot_if_exists(), binary_upgrade_logical_slot_has_caught_up(), drop_local_obsolete_slots(), pg_logical_slot_get_changes_guts(), pg_replication_slot_advance(), ReplicationSlotAlter(), ReplicationSlotDrop(), StartLogicalReplication(), StartReplication(), and synchronize_one_slot().

◆ ReplicationSlotAlter()

void ReplicationSlotAlter ( const char *  name,
const bool *  failover,
const bool *  two_phase 
)

Definition at line 882 of file slot.c.

884{
885 bool update_slot = false;
886
887 Assert(MyReplicationSlot == NULL);
889
890 ReplicationSlotAcquire(name, false, true);
891
894 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
895 errmsg("cannot use %s with a physical replication slot",
896 "ALTER_REPLICATION_SLOT"));
897
898 if (RecoveryInProgress())
899 {
900 /*
901 * Do not allow users to alter the slots which are currently being
902 * synced from the primary to the standby.
903 */
906 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
907 errmsg("cannot alter replication slot \"%s\"", name),
908 errdetail("This replication slot is being synchronized from the primary server."));
909
910 /*
911 * Do not allow users to enable failover on the standby as we do not
912 * support sync to the cascading standby.
913 */
914 if (failover && *failover)
916 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
917 errmsg("cannot enable failover for a replication slot"
918 " on the standby"));
919 }
920
921 if (failover)
922 {
923 /*
924 * Do not allow users to enable failover for temporary slots as we do
925 * not support syncing temporary slots to the standby.
926 */
929 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
930 errmsg("cannot enable failover for a temporary replication slot"));
931
933 {
937
938 update_slot = true;
939 }
940 }
941
943 {
947
948 update_slot = true;
949 }
950
951 if (update_slot)
952 {
955 }
956
958}
static bool two_phase
static bool failover
void ReplicationSlotAcquire(const char *name, bool nowait, bool error_if_invalid)
Definition: slot.c:593
void ReplicationSlotMarkDirty(void)
Definition: slot.c:1106
void ReplicationSlotSave(void)
Definition: slot.c:1088
void ReplicationSlotRelease(void)
Definition: slot.c:731
#define SlotIsPhysical(slot)
Definition: slot.h:254
ReplicationSlotPersistency persistency
Definition: slot.h:88
bool RecoveryInProgress(void)
Definition: xlog.c:6386

References Assert(), ReplicationSlot::data, ereport, errcode(), errdetail(), errmsg(), ERROR, failover, ReplicationSlotPersistentData::failover, ReplicationSlot::mutex, MyReplicationSlot, name, ReplicationSlotPersistentData::persistency, RecoveryInProgress(), ReplicationSlotAcquire(), ReplicationSlotMarkDirty(), ReplicationSlotRelease(), ReplicationSlotSave(), RS_TEMPORARY, SlotIsPhysical, SpinLockAcquire, SpinLockRelease, ReplicationSlotPersistentData::synced, two_phase, and ReplicationSlotPersistentData::two_phase.

Referenced by AlterReplicationSlot().

◆ ReplicationSlotCleanup()

void ReplicationSlotCleanup ( bool  synced_only)

Definition at line 820 of file slot.c.

821{
822 int i;
823
824 Assert(MyReplicationSlot == NULL);
825
826restart:
827 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
828 for (i = 0; i < max_replication_slots; i++)
829 {
831
832 if (!s->in_use)
833 continue;
834
836 if ((s->active_pid == MyProcPid &&
837 (!synced_only || s->data.synced)))
838 {
841 LWLockRelease(ReplicationSlotControlLock); /* avoid deadlock */
842
844
846 goto restart;
847 }
848 else
850 }
851
852 LWLockRelease(ReplicationSlotControlLock);
853}
static void ReplicationSlotDropPtr(ReplicationSlot *slot)
Definition: slot.c:981

References ReplicationSlot::active_cv, ReplicationSlot::active_pid, Assert(), ConditionVariableBroadcast(), ReplicationSlot::data, i, ReplicationSlot::in_use, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, MyProcPid, MyReplicationSlot, ReplicationSlotPersistentData::persistency, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotDropPtr(), RS_TEMPORARY, SpinLockAcquire, SpinLockRelease, and ReplicationSlotPersistentData::synced.

Referenced by PostgresMain(), ReplicationSlotShmemExit(), slotsync_failure_callback(), slotsync_worker_onexit(), SyncReplicationSlots(), and WalSndErrorCleanup().

◆ ReplicationSlotCreate()

void ReplicationSlotCreate ( const char *  name,
bool  db_specific,
ReplicationSlotPersistency  persistency,
bool  two_phase,
bool  failover,
bool  synced 
)

Definition at line 352 of file slot.c.

355{
356 ReplicationSlot *slot = NULL;
357 int i;
358
359 Assert(MyReplicationSlot == NULL);
360
361 /*
362 * The logical launcher or pg_upgrade may create or migrate an internal
363 * slot, so using a reserved name is allowed in these cases.
364 */
366 ERROR);
367
368 if (failover)
369 {
370 /*
371 * Do not allow users to create the failover enabled slots on the
372 * standby as we do not support sync to the cascading standby.
373 *
374 * However, failover enabled slots can be created during slot
375 * synchronization because we need to retain the same values as the
376 * remote slot.
377 */
380 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
381 errmsg("cannot enable failover for a replication slot created on the standby"));
382
383 /*
384 * Do not allow users to create failover enabled temporary slots,
385 * because temporary slots will not be synced to the standby.
386 *
387 * However, failover enabled temporary slots can be created during
388 * slot synchronization. See the comments atop slotsync.c for details.
389 */
390 if (persistency == RS_TEMPORARY && !IsSyncingReplicationSlots())
392 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
393 errmsg("cannot enable failover for a temporary replication slot"));
394 }
395
396 /*
397 * If some other backend ran this code concurrently with us, we'd likely
398 * both allocate the same slot, and that would be bad. We'd also be at
399 * risk of missing a name collision. Also, we don't want to try to create
400 * a new slot while somebody's busy cleaning up an old one, because we
401 * might both be monkeying with the same directory.
402 */
403 LWLockAcquire(ReplicationSlotAllocationLock, LW_EXCLUSIVE);
404
405 /*
406 * Check for name collision, and identify an allocatable slot. We need to
407 * hold ReplicationSlotControlLock in shared mode for this, so that nobody
408 * else can change the in_use flags while we're looking at them.
409 */
410 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
411 for (i = 0; i < max_replication_slots; i++)
412 {
414
415 if (s->in_use && strcmp(name, NameStr(s->data.name)) == 0)
418 errmsg("replication slot \"%s\" already exists", name)));
419 if (!s->in_use && slot == NULL)
420 slot = s;
421 }
422 LWLockRelease(ReplicationSlotControlLock);
423
424 /* If all slots are in use, we're out of luck. */
425 if (slot == NULL)
427 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
428 errmsg("all replication slots are in use"),
429 errhint("Free one or increase \"max_replication_slots\".")));
430
431 /*
432 * Since this slot is not in use, nobody should be looking at any part of
433 * it other than the in_use field unless they're trying to allocate it.
434 * And since we hold ReplicationSlotAllocationLock, nobody except us can
435 * be doing that. So it's safe to initialize the slot.
436 */
437 Assert(!slot->in_use);
438 Assert(slot->active_pid == 0);
439
440 /* first initialize persistent data */
441 memset(&slot->data, 0, sizeof(ReplicationSlotPersistentData));
442 namestrcpy(&slot->data.name, name);
443 slot->data.database = db_specific ? MyDatabaseId : InvalidOid;
444 slot->data.persistency = persistency;
445 slot->data.two_phase = two_phase;
447 slot->data.failover = failover;
448 slot->data.synced = synced;
449
450 /* and then data only present in shared memory */
451 slot->just_dirtied = false;
452 slot->dirty = false;
461 slot->inactive_since = 0;
462
463 /*
464 * Create the slot on disk. We haven't actually marked the slot allocated
465 * yet, so no special cleanup is required if this errors out.
466 */
467 CreateSlotOnDisk(slot);
468
469 /*
470 * We need to briefly prevent any other backend from iterating over the
471 * slots while we flip the in_use flag. We also need to set the active
472 * flag while holding the ControlLock as otherwise a concurrent
473 * ReplicationSlotAcquire() could acquire the slot as well.
474 */
475 LWLockAcquire(ReplicationSlotControlLock, LW_EXCLUSIVE);
476
477 slot->in_use = true;
478
479 /* We can now mark the slot active, and that makes it our slot. */
480 SpinLockAcquire(&slot->mutex);
481 Assert(slot->active_pid == 0);
482 slot->active_pid = MyProcPid;
483 SpinLockRelease(&slot->mutex);
484 MyReplicationSlot = slot;
485
486 LWLockRelease(ReplicationSlotControlLock);
487
488 /*
489 * Create statistics entry for the new logical slot. We don't collect any
490 * stats for physical slots, so no need to create an entry for the same.
491 * See ReplicationSlotDropPtr for why we need to do this before releasing
492 * ReplicationSlotAllocationLock.
493 */
494 if (SlotIsLogical(slot))
496
497 /*
498 * Now that the slot has been marked as in_use and active, it's safe to
499 * let somebody else try to allocate a slot.
500 */
501 LWLockRelease(ReplicationSlotAllocationLock);
502
503 /* Let everybody know we've modified this slot */
505}
int errhint(const char *fmt,...)
Definition: elog.c:1321
Oid MyDatabaseId
Definition: globals.c:94
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void namestrcpy(Name name, const char *str)
Definition: name.c:233
void pgstat_create_replslot(ReplicationSlot *slot)
#define InvalidOid
Definition: postgres_ext.h:37
static void CreateSlotOnDisk(ReplicationSlot *slot)
Definition: slot.c:2248
bool ReplicationSlotValidateName(const char *name, bool allow_reserved_name, int elevel)
Definition: slot.c:272
bool IsSyncingReplicationSlots(void)
Definition: slotsync.c:1668
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
XLogRecPtr candidate_xmin_lsn
Definition: slot.h:208
TransactionId effective_catalog_xmin
Definition: slot.h:189
XLogRecPtr candidate_restart_valid
Definition: slot.h:209
TransactionId effective_xmin
Definition: slot.h:188
XLogRecPtr candidate_restart_lsn
Definition: slot.h:210
TransactionId candidate_catalog_xmin
Definition: slot.h:207
TimestampTz inactive_since
Definition: slot.h:224
#define InvalidTransactionId
Definition: transam.h:31
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References ReplicationSlot::active_cv, ReplicationSlot::active_pid, Assert(), ReplicationSlot::candidate_catalog_xmin, ReplicationSlot::candidate_restart_lsn, ReplicationSlot::candidate_restart_valid, ReplicationSlot::candidate_xmin_lsn, ConditionVariableBroadcast(), CreateSlotOnDisk(), ReplicationSlot::data, ReplicationSlotPersistentData::database, ReplicationSlot::dirty, ReplicationSlot::effective_catalog_xmin, ReplicationSlot::effective_xmin, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, failover, ReplicationSlotPersistentData::failover, i, ReplicationSlot::in_use, ReplicationSlot::inactive_since, InvalidOid, InvalidTransactionId, InvalidXLogRecPtr, IsBinaryUpgrade, IsLogicalLauncher(), IsSyncingReplicationSlots(), ReplicationSlot::just_dirtied, ReplicationSlot::last_saved_confirmed_flush, ReplicationSlot::last_saved_restart_lsn, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, MyDatabaseId, MyProcPid, MyReplicationSlot, name, ReplicationSlotPersistentData::name, NameStr, namestrcpy(), ReplicationSlotPersistentData::persistency, pgstat_create_replslot(), RecoveryInProgress(), ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotValidateName(), RS_TEMPORARY, SlotIsLogical, SpinLockAcquire, SpinLockRelease, ReplicationSlotPersistentData::synced, two_phase, ReplicationSlotPersistentData::two_phase, and ReplicationSlotPersistentData::two_phase_at.

Referenced by create_logical_replication_slot(), create_physical_replication_slot(), CreateConflictDetectionSlot(), CreateReplicationSlot(), and synchronize_one_slot().

◆ ReplicationSlotDrop()

void ReplicationSlotDrop ( const char *  name,
bool  nowait 
)

Definition at line 859 of file slot.c.

860{
861 Assert(MyReplicationSlot == NULL);
862
863 ReplicationSlotAcquire(name, nowait, false);
864
865 /*
866 * Do not allow users to drop the slots which are currently being synced
867 * from the primary to the standby.
868 */
871 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
872 errmsg("cannot drop replication slot \"%s\"", name),
873 errdetail("This replication slot is being synchronized from the primary server."));
874
876}
void ReplicationSlotDropAcquired(void)
Definition: slot.c:964

References Assert(), ReplicationSlot::data, ereport, errcode(), errdetail(), errmsg(), ERROR, MyReplicationSlot, name, RecoveryInProgress(), ReplicationSlotAcquire(), ReplicationSlotDropAcquired(), and ReplicationSlotPersistentData::synced.

Referenced by DropReplicationSlot(), and pg_drop_replication_slot().

◆ ReplicationSlotDropAcquired()

void ReplicationSlotDropAcquired ( void  )

Definition at line 964 of file slot.c.

965{
967
968 Assert(MyReplicationSlot != NULL);
969
970 /* slot isn't acquired anymore */
971 MyReplicationSlot = NULL;
972
974}

References Assert(), MyReplicationSlot, and ReplicationSlotDropPtr().

Referenced by ApplyLauncherMain(), drop_local_obsolete_slots(), ReplicationSlotDrop(), ReplicationSlotRelease(), and ReplicationSlotsDropDBSlots().

◆ ReplicationSlotDropAtPubNode()

void ReplicationSlotDropAtPubNode ( WalReceiverConn wrconn,
char *  slotname,
bool  missing_ok 
)

Definition at line 2147 of file subscriptioncmds.c.

2148{
2149 StringInfoData cmd;
2150
2151 Assert(wrconn);
2152
2153 load_file("libpqwalreceiver", false);
2154
2155 initStringInfo(&cmd);
2156 appendStringInfo(&cmd, "DROP_REPLICATION_SLOT %s WAIT", quote_identifier(slotname));
2157
2158 PG_TRY();
2159 {
2160 WalRcvExecResult *res;
2161
2162 res = walrcv_exec(wrconn, cmd.data, 0, NULL);
2163
2164 if (res->status == WALRCV_OK_COMMAND)
2165 {
2166 /* NOTICE. Success. */
2168 (errmsg("dropped replication slot \"%s\" on publisher",
2169 slotname)));
2170 }
2171 else if (res->status == WALRCV_ERROR &&
2172 missing_ok &&
2173 res->sqlstate == ERRCODE_UNDEFINED_OBJECT)
2174 {
2175 /* LOG. Error, but missing_ok = true. */
2176 ereport(LOG,
2177 (errmsg("could not drop replication slot \"%s\" on publisher: %s",
2178 slotname, res->err)));
2179 }
2180 else
2181 {
2182 /* ERROR. */
2183 ereport(ERROR,
2184 (errcode(ERRCODE_CONNECTION_FAILURE),
2185 errmsg("could not drop replication slot \"%s\" on publisher: %s",
2186 slotname, res->err)));
2187 }
2188
2190 }
2191 PG_FINALLY();
2192 {
2193 pfree(cmd.data);
2194 }
2195 PG_END_TRY();
2196}
void load_file(const char *filename, bool restricted)
Definition: dfmgr.c:149
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define NOTICE
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:389
void pfree(void *pointer)
Definition: mcxt.c:1594
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:13030
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
WalRcvExecStatus status
Definition: walreceiver.h:220
static WalReceiverConn * wrconn
Definition: walreceiver.c:93
@ WALRCV_OK_COMMAND
Definition: walreceiver.h:205
@ WALRCV_ERROR
Definition: walreceiver.h:204
static void walrcv_clear_result(WalRcvExecResult *walres)
Definition: walreceiver.h:471
#define walrcv_exec(conn, exec, nRetTypes, retTypes)
Definition: walreceiver.h:465

References appendStringInfo(), Assert(), StringInfoData::data, ereport, WalRcvExecResult::err, errcode(), errmsg(), ERROR, initStringInfo(), load_file(), LOG, NOTICE, pfree(), PG_END_TRY, PG_FINALLY, PG_TRY, quote_identifier(), WalRcvExecResult::sqlstate, WalRcvExecResult::status, walrcv_clear_result(), WALRCV_ERROR, walrcv_exec, WALRCV_OK_COMMAND, and wrconn.

Referenced by AlterSubscription_refresh(), DropSubscription(), LogicalRepSyncTableStart(), and process_syncing_tables_for_sync().

◆ ReplicationSlotIndex()

◆ ReplicationSlotInitialize()

void ReplicationSlotInitialize ( void  )

Definition at line 241 of file slot.c.

242{
244}
void before_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:337
static void ReplicationSlotShmemExit(int code, Datum arg)
Definition: slot.c:250

References before_shmem_exit(), and ReplicationSlotShmemExit().

Referenced by BaseInit().

◆ ReplicationSlotMarkDirty()

◆ ReplicationSlotName()

bool ReplicationSlotName ( int  index,
Name  name 
)

Definition at line 562 of file slot.c.

563{
564 ReplicationSlot *slot;
565 bool found;
566
568
569 /*
570 * Ensure that the slot cannot be dropped while we copy the name. Don't
571 * need the spinlock as the name of an existing slot cannot change.
572 */
573 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
574 found = slot->in_use;
575 if (slot->in_use)
577 LWLockRelease(ReplicationSlotControlLock);
578
579 return found;
580}
Definition: type.h:96

References ReplicationSlot::data, ReplicationSlot::in_use, LW_SHARED, LWLockAcquire(), LWLockRelease(), name, ReplicationSlotPersistentData::name, NameStr, namestrcpy(), ReplicationSlotCtlData::replication_slots, and ReplicationSlotCtl.

Referenced by pgstat_replslot_to_serialized_name_cb().

◆ ReplicationSlotNameForTablesync()

void ReplicationSlotNameForTablesync ( Oid  suboid,
Oid  relid,
char *  syncslotname,
Size  szslot 
)

Definition at line 1303 of file tablesync.c.

1305{
1306 snprintf(syncslotname, szslot, "pg_%u_sync_%u_" UINT64_FORMAT, suboid,
1307 relid, GetSystemIdentifier());
1308}
#define UINT64_FORMAT
Definition: c.h:557
#define snprintf
Definition: port.h:239
uint64 GetSystemIdentifier(void)
Definition: xlog.c:4595

References GetSystemIdentifier(), snprintf, and UINT64_FORMAT.

Referenced by AlterSubscription_refresh(), DropSubscription(), LogicalRepSyncTableStart(), process_syncing_tables_for_sync(), and ReportSlotConnectionError().

◆ ReplicationSlotPersist()

◆ ReplicationSlotRelease()

void ReplicationSlotRelease ( void  )

Definition at line 731 of file slot.c.

732{
734 char *slotname = NULL; /* keep compiler quiet */
735 bool is_logical = false; /* keep compiler quiet */
736 TimestampTz now = 0;
737
738 Assert(slot != NULL && slot->active_pid != 0);
739
740 if (am_walsender)
741 {
742 slotname = pstrdup(NameStr(slot->data.name));
743 is_logical = SlotIsLogical(slot);
744 }
745
746 if (slot->data.persistency == RS_EPHEMERAL)
747 {
748 /*
749 * Delete the slot. There is no !PANIC case where this is allowed to
750 * fail, all that may happen is an incomplete cleanup of the on-disk
751 * data.
752 */
754 }
755
756 /*
757 * If slot needed to temporarily restrain both data and catalog xmin to
758 * create the catalog snapshot, remove that temporary constraint.
759 * Snapshots can only be exported while the initial snapshot is still
760 * acquired.
761 */
762 if (!TransactionIdIsValid(slot->data.xmin) &&
764 {
765 SpinLockAcquire(&slot->mutex);
767 SpinLockRelease(&slot->mutex);
769 }
770
771 /*
772 * Set the time since the slot has become inactive. We get the current
773 * time beforehand to avoid system call while holding the spinlock.
774 */
776
777 if (slot->data.persistency == RS_PERSISTENT)
778 {
779 /*
780 * Mark persistent slot inactive. We're not freeing it, just
781 * disconnecting, but wake up others that may be waiting for it.
782 */
783 SpinLockAcquire(&slot->mutex);
784 slot->active_pid = 0;
786 SpinLockRelease(&slot->mutex);
788 }
789 else
791
792 MyReplicationSlot = NULL;
793
794 /* might not have been set when we've been a plain slot */
795 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
796 MyProc->statusFlags &= ~PROC_IN_LOGICAL_DECODING;
798 LWLockRelease(ProcArrayLock);
799
800 if (am_walsender)
801 {
803 is_logical
804 ? errmsg("released logical replication slot \"%s\"",
805 slotname)
806 : errmsg("released physical replication slot \"%s\"",
807 slotname));
808
809 pfree(slotname);
810 }
811}
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
int64 TimestampTz
Definition: timestamp.h:39
char * pstrdup(const char *in)
Definition: mcxt.c:1759
PGPROC * MyProc
Definition: proc.c:66
PROC_HDR * ProcGlobal
Definition: proc.c:78
uint8 statusFlags
Definition: proc.h:259
int pgxactoff
Definition: proc.h:201
uint8 * statusFlags
Definition: proc.h:403
TransactionId xmin
Definition: slot.h:96

References ReplicationSlot::active_cv, ReplicationSlot::active_pid, am_walsender, Assert(), ConditionVariableBroadcast(), ReplicationSlot::data, DEBUG1, ReplicationSlot::effective_xmin, ereport, errmsg(), GetCurrentTimestamp(), InvalidTransactionId, LOG, log_replication_commands, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ReplicationSlot::mutex, MyProc, MyReplicationSlot, ReplicationSlotPersistentData::name, NameStr, now(), ReplicationSlotPersistentData::persistency, pfree(), PGPROC::pgxactoff, ProcGlobal, pstrdup(), ReplicationSlotDropAcquired(), ReplicationSlotsComputeRequiredXmin(), ReplicationSlotSetInactiveSince(), RS_EPHEMERAL, RS_PERSISTENT, SlotIsLogical, SpinLockAcquire, SpinLockRelease, PGPROC::statusFlags, PROC_HDR::statusFlags, TransactionIdIsValid, and ReplicationSlotPersistentData::xmin.

Referenced by binary_upgrade_create_conflict_detection_slot(), binary_upgrade_logical_slot_has_caught_up(), copy_replication_slot(), CreateReplicationSlot(), InvalidatePossiblyObsoleteSlot(), pg_create_logical_replication_slot(), pg_create_physical_replication_slot(), pg_logical_slot_get_changes_guts(), pg_replication_slot_advance(), PostgresMain(), ReplicationSlotAlter(), ReplicationSlotShmemExit(), slotsync_failure_callback(), slotsync_worker_onexit(), StartLogicalReplication(), StartReplication(), synchronize_one_slot(), and WalSndErrorCleanup().

◆ ReplicationSlotReserveWal()

void ReplicationSlotReserveWal ( void  )

Definition at line 1539 of file slot.c.

1540{
1542
1543 Assert(slot != NULL);
1546
1547 /*
1548 * The replication slot mechanism is used to prevent removal of required
1549 * WAL. As there is no interlock between this routine and checkpoints, WAL
1550 * segments could concurrently be removed when a now stale return value of
1551 * ReplicationSlotsComputeRequiredLSN() is used. In the unlikely case that
1552 * this happens we'll just retry.
1553 */
1554 while (true)
1555 {
1556 XLogSegNo segno;
1557 XLogRecPtr restart_lsn;
1558
1559 /*
1560 * For logical slots log a standby snapshot and start logical decoding
1561 * at exactly that position. That allows the slot to start up more
1562 * quickly. But on a standby we cannot do WAL writes, so just use the
1563 * replay pointer; effectively, an attempt to create a logical slot on
1564 * standby will cause it to wait for an xl_running_xact record to be
1565 * logged independently on the primary, so that a snapshot can be
1566 * built using the record.
1567 *
1568 * None of this is needed (or indeed helpful) for physical slots as
1569 * they'll start replay at the last logged checkpoint anyway. Instead
1570 * return the location of the last redo LSN. While that slightly
1571 * increases the chance that we have to retry, it's where a base
1572 * backup has to start replay at.
1573 */
1574 if (SlotIsPhysical(slot))
1575 restart_lsn = GetRedoRecPtr();
1576 else if (RecoveryInProgress())
1577 restart_lsn = GetXLogReplayRecPtr(NULL);
1578 else
1579 restart_lsn = GetXLogInsertRecPtr();
1580
1581 SpinLockAcquire(&slot->mutex);
1582 slot->data.restart_lsn = restart_lsn;
1583 SpinLockRelease(&slot->mutex);
1584
1585 /* prevent WAL removal as fast as possible */
1587
1588 /*
1589 * If all required WAL is still there, great, otherwise retry. The
1590 * slot should prevent further removal of WAL, unless there's a
1591 * concurrent ReplicationSlotsComputeRequiredLSN() after we've written
1592 * the new restart_lsn above, so normally we should never need to loop
1593 * more than twice.
1594 */
1596 if (XLogGetLastRemovedSegno() < segno)
1597 break;
1598 }
1599
1600 if (!RecoveryInProgress() && SlotIsLogical(slot))
1601 {
1602 XLogRecPtr flushptr;
1603
1604 /* make sure we have enough information to start */
1605 flushptr = LogStandbySnapshot();
1606
1607 /* and make sure it's fsynced to disk */
1608 XLogFlush(flushptr);
1609 }
1610}
XLogRecPtr LogStandbySnapshot(void)
Definition: standby.c:1282
XLogSegNo XLogGetLastRemovedSegno(void)
Definition: xlog.c:3774
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:6489
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:9479
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2780
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
uint64 XLogSegNo
Definition: xlogdefs.h:51
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)

References Assert(), ReplicationSlot::data, GetRedoRecPtr(), GetXLogInsertRecPtr(), GetXLogReplayRecPtr(), InvalidXLogRecPtr, ReplicationSlot::last_saved_restart_lsn, LogStandbySnapshot(), ReplicationSlot::mutex, MyReplicationSlot, RecoveryInProgress(), ReplicationSlotsComputeRequiredLSN(), ReplicationSlotPersistentData::restart_lsn, SlotIsLogical, SlotIsPhysical, SpinLockAcquire, SpinLockRelease, wal_segment_size, XLByteToSeg, XLogFlush(), and XLogGetLastRemovedSegno().

Referenced by create_physical_replication_slot(), CreateInitDecodingContext(), and CreateReplicationSlot().

◆ ReplicationSlotSave()

◆ ReplicationSlotsComputeLogicalRestartLSN()

XLogRecPtr ReplicationSlotsComputeLogicalRestartLSN ( void  )

Definition at line 1271 of file slot.c.

1272{
1274 int i;
1275
1276 if (max_replication_slots <= 0)
1277 return InvalidXLogRecPtr;
1278
1279 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
1280
1281 for (i = 0; i < max_replication_slots; i++)
1282 {
1283 ReplicationSlot *s;
1284 XLogRecPtr restart_lsn;
1285 XLogRecPtr last_saved_restart_lsn;
1286 bool invalidated;
1287 ReplicationSlotPersistency persistency;
1288
1290
1291 /* cannot change while ReplicationSlotCtlLock is held */
1292 if (!s->in_use)
1293 continue;
1294
1295 /* we're only interested in logical slots */
1296 if (!SlotIsLogical(s))
1297 continue;
1298
1299 /* read once, it's ok if it increases while we're checking */
1301 persistency = s->data.persistency;
1302 restart_lsn = s->data.restart_lsn;
1303 invalidated = s->data.invalidated != RS_INVAL_NONE;
1304 last_saved_restart_lsn = s->last_saved_restart_lsn;
1306
1307 /* invalidated slots need not apply */
1308 if (invalidated)
1309 continue;
1310
1311 /*
1312 * For persistent slot use last_saved_restart_lsn to compute the
1313 * oldest LSN for removal of WAL segments. The segments between
1314 * last_saved_restart_lsn and restart_lsn might be needed by a
1315 * persistent slot in the case of database crash. Non-persistent
1316 * slots can't survive the database crash, so we don't care about
1317 * last_saved_restart_lsn for them.
1318 */
1319 if (persistency == RS_PERSISTENT)
1320 {
1321 if (last_saved_restart_lsn != InvalidXLogRecPtr &&
1322 restart_lsn > last_saved_restart_lsn)
1323 {
1324 restart_lsn = last_saved_restart_lsn;
1325 }
1326 }
1327
1328 if (restart_lsn == InvalidXLogRecPtr)
1329 continue;
1330
1331 if (result == InvalidXLogRecPtr ||
1332 restart_lsn < result)
1333 result = restart_lsn;
1334 }
1335
1336 LWLockRelease(ReplicationSlotControlLock);
1337
1338 return result;
1339}

References ReplicationSlot::data, i, ReplicationSlot::in_use, ReplicationSlotPersistentData::invalidated, InvalidXLogRecPtr, ReplicationSlot::last_saved_restart_lsn, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, ReplicationSlotPersistentData::persistency, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotPersistentData::restart_lsn, RS_INVAL_NONE, RS_PERSISTENT, SlotIsLogical, SpinLockAcquire, and SpinLockRelease.

Referenced by CheckPointLogicalRewriteHeap(), and CheckPointSnapBuild().

◆ ReplicationSlotsComputeRequiredLSN()

void ReplicationSlotsComputeRequiredLSN ( void  )

Definition at line 1201 of file slot.c.

1202{
1203 int i;
1204 XLogRecPtr min_required = InvalidXLogRecPtr;
1205
1206 Assert(ReplicationSlotCtl != NULL);
1207
1208 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
1209 for (i = 0; i < max_replication_slots; i++)
1210 {
1212 XLogRecPtr restart_lsn;
1213 XLogRecPtr last_saved_restart_lsn;
1214 bool invalidated;
1215 ReplicationSlotPersistency persistency;
1216
1217 if (!s->in_use)
1218 continue;
1219
1221 persistency = s->data.persistency;
1222 restart_lsn = s->data.restart_lsn;
1223 invalidated = s->data.invalidated != RS_INVAL_NONE;
1224 last_saved_restart_lsn = s->last_saved_restart_lsn;
1226
1227 /* invalidated slots need not apply */
1228 if (invalidated)
1229 continue;
1230
1231 /*
1232 * For persistent slot use last_saved_restart_lsn to compute the
1233 * oldest LSN for removal of WAL segments. The segments between
1234 * last_saved_restart_lsn and restart_lsn might be needed by a
1235 * persistent slot in the case of database crash. Non-persistent
1236 * slots can't survive the database crash, so we don't care about
1237 * last_saved_restart_lsn for them.
1238 */
1239 if (persistency == RS_PERSISTENT)
1240 {
1241 if (last_saved_restart_lsn != InvalidXLogRecPtr &&
1242 restart_lsn > last_saved_restart_lsn)
1243 {
1244 restart_lsn = last_saved_restart_lsn;
1245 }
1246 }
1247
1248 if (restart_lsn != InvalidXLogRecPtr &&
1249 (min_required == InvalidXLogRecPtr ||
1250 restart_lsn < min_required))
1251 min_required = restart_lsn;
1252 }
1253 LWLockRelease(ReplicationSlotControlLock);
1254
1256}
void XLogSetReplicationSlotMinimumLSN(XLogRecPtr lsn)
Definition: xlog.c:2666

References Assert(), ReplicationSlot::data, i, ReplicationSlot::in_use, ReplicationSlotPersistentData::invalidated, InvalidXLogRecPtr, ReplicationSlot::last_saved_restart_lsn, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, ReplicationSlotPersistentData::persistency, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotPersistentData::restart_lsn, RS_INVAL_NONE, RS_PERSISTENT, SpinLockAcquire, SpinLockRelease, and XLogSetReplicationSlotMinimumLSN().

Referenced by CheckPointReplicationSlots(), copy_replication_slot(), InvalidateObsoleteReplicationSlots(), LogicalConfirmReceivedLocation(), pg_replication_slot_advance(), PhysicalConfirmReceivedLocation(), ReplicationSlotDropPtr(), ReplicationSlotReserveWal(), reserve_wal_for_local_slot(), StartupReplicationSlots(), and update_local_synced_slot().

◆ ReplicationSlotsComputeRequiredXmin()

void ReplicationSlotsComputeRequiredXmin ( bool  already_locked)

Definition at line 1145 of file slot.c.

1146{
1147 int i;
1149 TransactionId agg_catalog_xmin = InvalidTransactionId;
1150
1151 Assert(ReplicationSlotCtl != NULL);
1152
1153 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
1154
1155 for (i = 0; i < max_replication_slots; i++)
1156 {
1158 TransactionId effective_xmin;
1159 TransactionId effective_catalog_xmin;
1160 bool invalidated;
1161
1162 if (!s->in_use)
1163 continue;
1164
1166 effective_xmin = s->effective_xmin;
1167 effective_catalog_xmin = s->effective_catalog_xmin;
1168 invalidated = s->data.invalidated != RS_INVAL_NONE;
1170
1171 /* invalidated slots need not apply */
1172 if (invalidated)
1173 continue;
1174
1175 /* check the data xmin */
1176 if (TransactionIdIsValid(effective_xmin) &&
1177 (!TransactionIdIsValid(agg_xmin) ||
1178 TransactionIdPrecedes(effective_xmin, agg_xmin)))
1179 agg_xmin = effective_xmin;
1180
1181 /* check the catalog xmin */
1182 if (TransactionIdIsValid(effective_catalog_xmin) &&
1183 (!TransactionIdIsValid(agg_catalog_xmin) ||
1184 TransactionIdPrecedes(effective_catalog_xmin, agg_catalog_xmin)))
1185 agg_catalog_xmin = effective_catalog_xmin;
1186 }
1187
1188 LWLockRelease(ReplicationSlotControlLock);
1189
1190 ProcArraySetReplicationSlotXmin(agg_xmin, agg_catalog_xmin, already_locked);
1191}
uint32 TransactionId
Definition: c.h:657
void ProcArraySetReplicationSlotXmin(TransactionId xmin, TransactionId catalog_xmin, bool already_locked)
Definition: procarray.c:3905
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280

References Assert(), ReplicationSlot::data, ReplicationSlot::effective_catalog_xmin, ReplicationSlot::effective_xmin, i, ReplicationSlot::in_use, ReplicationSlotPersistentData::invalidated, InvalidTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, ProcArraySetReplicationSlotXmin(), ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, RS_INVAL_NONE, SpinLockAcquire, SpinLockRelease, TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by copy_replication_slot(), CreateInitDecodingContext(), init_conflict_slot_xmin(), InvalidateObsoleteReplicationSlots(), LogicalConfirmReceivedLocation(), pg_replication_slot_advance(), PhysicalReplicationSlotNewXmin(), ReplicationSlotDropPtr(), ReplicationSlotRelease(), StartupReplicationSlots(), synchronize_one_slot(), update_conflict_slot_xmin(), and update_local_synced_slot().

◆ ReplicationSlotsCountDBSlots()

bool ReplicationSlotsCountDBSlots ( Oid  dboid,
int *  nslots,
int *  nactive 
)

Definition at line 1350 of file slot.c.

1351{
1352 int i;
1353
1354 *nslots = *nactive = 0;
1355
1356 if (max_replication_slots <= 0)
1357 return false;
1358
1359 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
1360 for (i = 0; i < max_replication_slots; i++)
1361 {
1362 ReplicationSlot *s;
1363
1365
1366 /* cannot change while ReplicationSlotCtlLock is held */
1367 if (!s->in_use)
1368 continue;
1369
1370 /* only logical slots are database specific, skip */
1371 if (!SlotIsLogical(s))
1372 continue;
1373
1374 /* not our database, skip */
1375 if (s->data.database != dboid)
1376 continue;
1377
1378 /* NB: intentionally counting invalidated slots */
1379
1380 /* count slots with spinlock held */
1382 (*nslots)++;
1383 if (s->active_pid != 0)
1384 (*nactive)++;
1386 }
1387 LWLockRelease(ReplicationSlotControlLock);
1388
1389 if (*nslots > 0)
1390 return true;
1391 return false;
1392}

References ReplicationSlot::active_pid, ReplicationSlot::data, ReplicationSlotPersistentData::database, i, ReplicationSlot::in_use, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, SlotIsLogical, SpinLockAcquire, and SpinLockRelease.

Referenced by dropdb().

◆ ReplicationSlotsDropDBSlots()

void ReplicationSlotsDropDBSlots ( Oid  dboid)

Definition at line 1408 of file slot.c.

1409{
1410 int i;
1411
1412 if (max_replication_slots <= 0)
1413 return;
1414
1415restart:
1416 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
1417 for (i = 0; i < max_replication_slots; i++)
1418 {
1419 ReplicationSlot *s;
1420 char *slotname;
1421 int active_pid;
1422
1424
1425 /* cannot change while ReplicationSlotCtlLock is held */
1426 if (!s->in_use)
1427 continue;
1428
1429 /* only logical slots are database specific, skip */
1430 if (!SlotIsLogical(s))
1431 continue;
1432
1433 /* not our database, skip */
1434 if (s->data.database != dboid)
1435 continue;
1436
1437 /* NB: intentionally including invalidated slots */
1438
1439 /* acquire slot, so ReplicationSlotDropAcquired can be reused */
1441 /* can't change while ReplicationSlotControlLock is held */
1442 slotname = NameStr(s->data.name);
1443 active_pid = s->active_pid;
1444 if (active_pid == 0)
1445 {
1447 s->active_pid = MyProcPid;
1448 }
1450
1451 /*
1452 * Even though we hold an exclusive lock on the database object a
1453 * logical slot for that DB can still be active, e.g. if it's
1454 * concurrently being dropped by a backend connected to another DB.
1455 *
1456 * That's fairly unlikely in practice, so we'll just bail out.
1457 *
1458 * The slot sync worker holds a shared lock on the database before
1459 * operating on synced logical slots to avoid conflict with the drop
1460 * happening here. The persistent synced slots are thus safe but there
1461 * is a possibility that the slot sync worker has created a temporary
1462 * slot (which stays active even on release) and we are trying to drop
1463 * that here. In practice, the chances of hitting this scenario are
1464 * less as during slot synchronization, the temporary slot is
1465 * immediately converted to persistent and thus is safe due to the
1466 * shared lock taken on the database. So, we'll just bail out in such
1467 * a case.
1468 *
1469 * XXX: We can consider shutting down the slot sync worker before
1470 * trying to drop synced temporary slots here.
1471 */
1472 if (active_pid)
1473 ereport(ERROR,
1474 (errcode(ERRCODE_OBJECT_IN_USE),
1475 errmsg("replication slot \"%s\" is active for PID %d",
1476 slotname, active_pid)));
1477
1478 /*
1479 * To avoid duplicating ReplicationSlotDropAcquired() and to avoid
1480 * holding ReplicationSlotControlLock over filesystem operations,
1481 * release ReplicationSlotControlLock and use
1482 * ReplicationSlotDropAcquired.
1483 *
1484 * As that means the set of slots could change, restart scan from the
1485 * beginning each time we release the lock.
1486 */
1487 LWLockRelease(ReplicationSlotControlLock);
1489 goto restart;
1490 }
1491 LWLockRelease(ReplicationSlotControlLock);
1492}

References ReplicationSlot::active_pid, ReplicationSlot::data, ReplicationSlotPersistentData::database, ereport, errcode(), errmsg(), ERROR, i, ReplicationSlot::in_use, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, ReplicationSlot::mutex, MyProcPid, MyReplicationSlot, ReplicationSlotPersistentData::name, NameStr, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotDropAcquired(), SlotIsLogical, SpinLockAcquire, and SpinLockRelease.

Referenced by dbase_redo(), and dropdb().

◆ ReplicationSlotSetInactiveSince()

static void ReplicationSlotSetInactiveSince ( ReplicationSlot s,
TimestampTz  ts,
bool  acquire_lock 
)
inlinestatic

◆ ReplicationSlotsShmemInit()

void ReplicationSlotsShmemInit ( void  )

Definition at line 206 of file slot.c.

207{
208 bool found;
209
210 if (max_replication_slots == 0)
211 return;
212
214 ShmemInitStruct("ReplicationSlot Ctl", ReplicationSlotsShmemSize(),
215 &found);
216
217 if (!found)
218 {
219 int i;
220
221 /* First time through, so initialize */
223
224 for (i = 0; i < max_replication_slots; i++)
225 {
227
228 /* everything else is zeroed by the memset above */
229 SpinLockInit(&slot->mutex);
231 LWTRANCHE_REPLICATION_SLOT_IO);
233 }
234 }
235}
#define MemSet(start, val, len)
Definition: c.h:1019
void ConditionVariableInit(ConditionVariable *cv)
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:698
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size ReplicationSlotsShmemSize(void)
Definition: slot.c:188
#define SpinLockInit(lock)
Definition: spin.h:57
LWLock io_in_progress_lock
Definition: slot.h:195

References ReplicationSlot::active_cv, ConditionVariableInit(), i, ReplicationSlot::io_in_progress_lock, LWLockInitialize(), max_replication_slots, MemSet, ReplicationSlot::mutex, ReplicationSlotCtlData::replication_slots, ReplicationSlotCtl, ReplicationSlotsShmemSize(), ShmemInitStruct(), and SpinLockInit.

Referenced by CreateOrAttachShmemStructs().

◆ ReplicationSlotsShmemSize()

Size ReplicationSlotsShmemSize ( void  )

Definition at line 188 of file slot.c.

189{
190 Size size = 0;
191
192 if (max_replication_slots == 0)
193 return size;
194
195 size = offsetof(ReplicationSlotCtlData, replication_slots);
196 size = add_size(size,
198
199 return size;
200}
size_t Size
Definition: c.h:610
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

References add_size(), max_replication_slots, and mul_size().

Referenced by CalculateShmemSize(), and ReplicationSlotsShmemInit().

◆ ReplicationSlotValidateName()

bool ReplicationSlotValidateName ( const char *  name,
bool  allow_reserved_name,
int  elevel 
)

Definition at line 272 of file slot.c.

274{
275 const char *cp;
276
277 if (strlen(name) == 0)
278 {
279 ereport(elevel,
280 (errcode(ERRCODE_INVALID_NAME),
281 errmsg("replication slot name \"%s\" is too short",
282 name)));
283 return false;
284 }
285
286 if (strlen(name) >= NAMEDATALEN)
287 {
288 ereport(elevel,
289 (errcode(ERRCODE_NAME_TOO_LONG),
290 errmsg("replication slot name \"%s\" is too long",
291 name)));
292 return false;
293 }
294
295 for (cp = name; *cp; cp++)
296 {
297 if (!((*cp >= 'a' && *cp <= 'z')
298 || (*cp >= '0' && *cp <= '9')
299 || (*cp == '_')))
300 {
301 ereport(elevel,
302 (errcode(ERRCODE_INVALID_NAME),
303 errmsg("replication slot name \"%s\" contains invalid character",
304 name),
305 errhint("Replication slot names may only contain lower case letters, numbers, and the underscore character.")));
306 return false;
307 }
308 }
309
310 if (!allow_reserved_name && IsSlotForConflictCheck(name))
311 {
312 ereport(elevel,
313 errcode(ERRCODE_RESERVED_NAME),
314 errmsg("replication slot name \"%s\" is reserved",
315 name),
316 errdetail("The name \"%s\" is reserved for the conflict detection slot.",
318
319 return false;
320 }
321
322 return true;
323}
#define NAMEDATALEN
#define CONFLICT_DETECTION_SLOT
Definition: slot.h:28

References CONFLICT_DETECTION_SLOT, ereport, errcode(), errdetail(), errhint(), errmsg(), IsSlotForConflictCheck(), name, and NAMEDATALEN.

Referenced by check_primary_slot_name(), parse_subscription_options(), ReplicationSlotCreate(), and StartupReorderBuffer().

◆ SearchNamedReplicationSlot()

ReplicationSlot * SearchNamedReplicationSlot ( const char *  name,
bool  need_lock 
)

Definition at line 513 of file slot.c.

514{
515 int i;
516 ReplicationSlot *slot = NULL;
517
518 if (need_lock)
519 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
520
521 for (i = 0; i < max_replication_slots; i++)
522 {
524
525 if (s->in_use && strcmp(name, NameStr(s->data.name)) == 0)
526 {
527 slot = s;
528 break;
529 }
530 }
531
532 if (need_lock)
533 LWLockRelease(ReplicationSlotControlLock);
534
535 return slot;
536}

References ReplicationSlot::data, i, ReplicationSlot::in_use, LW_SHARED, LWLockAcquire(), LWLockRelease(), max_replication_slots, name, ReplicationSlotPersistentData::name, NameStr, ReplicationSlotCtlData::replication_slots, and ReplicationSlotCtl.

Referenced by acquire_conflict_slot_if_exists(), get_replslot_index(), pg_ls_replslotdir(), pgstat_reset_replslot(), ReadReplicationSlot(), ReplicationSlotAcquire(), StandbySlotsHaveCaughtup(), synchronize_one_slot(), and validate_sync_standby_slots().

◆ SlotExistsInSyncStandbySlots()

bool SlotExistsInSyncStandbySlots ( const char *  slot_name)

Definition at line 2872 of file slot.c.

2873{
2874 const char *standby_slot_name;
2875
2876 /* Return false if there is no value in synchronized_standby_slots */
2878 return false;
2879
2880 /*
2881 * XXX: We are not expecting this list to be long so a linear search
2882 * shouldn't hurt but if that turns out not to be true then we can cache
2883 * this information for each WalSender as well.
2884 */
2885 standby_slot_name = synchronized_standby_slots_config->slot_names;
2886 for (int i = 0; i < synchronized_standby_slots_config->nslotnames; i++)
2887 {
2888 if (strcmp(standby_slot_name, slot_name) == 0)
2889 return true;
2890
2891 standby_slot_name += strlen(standby_slot_name) + 1;
2892 }
2893
2894 return false;
2895}
static SyncStandbySlotsConfigData * synchronized_standby_slots_config
Definition: slot.c:167
char slot_names[FLEXIBLE_ARRAY_MEMBER]
Definition: slot.c:101

References i, SyncStandbySlotsConfigData::nslotnames, SyncStandbySlotsConfigData::slot_names, and synchronized_standby_slots_config.

Referenced by PhysicalWakeupLogicalWalSnd().

◆ StandbySlotsHaveCaughtup()

bool StandbySlotsHaveCaughtup ( XLogRecPtr  wait_for_lsn,
int  elevel 
)

Definition at line 2905 of file slot.c.

2906{
2907 const char *name;
2908 int caught_up_slot_num = 0;
2909 XLogRecPtr min_restart_lsn = InvalidXLogRecPtr;
2910
2911 /*
2912 * Don't need to wait for the standbys to catch up if there is no value in
2913 * synchronized_standby_slots.
2914 */
2916 return true;
2917
2918 /*
2919 * Don't need to wait for the standbys to catch up if we are on a standby
2920 * server, since we do not support syncing slots to cascading standbys.
2921 */
2922 if (RecoveryInProgress())
2923 return true;
2924
2925 /*
2926 * Don't need to wait for the standbys to catch up if they are already
2927 * beyond the specified WAL location.
2928 */
2930 ss_oldest_flush_lsn >= wait_for_lsn)
2931 return true;
2932
2933 /*
2934 * To prevent concurrent slot dropping and creation while filtering the
2935 * slots, take the ReplicationSlotControlLock outside of the loop.
2936 */
2937 LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
2938
2940 for (int i = 0; i < synchronized_standby_slots_config->nslotnames; i++)
2941 {
2942 XLogRecPtr restart_lsn;
2943 bool invalidated;
2944 bool inactive;
2945 ReplicationSlot *slot;
2946
2947 slot = SearchNamedReplicationSlot(name, false);
2948
2949 /*
2950 * If a slot name provided in synchronized_standby_slots does not
2951 * exist, report a message and exit the loop.
2952 *
2953 * Though validate_sync_standby_slots (the GUC check_hook) tries to
2954 * avoid this, it can nonetheless happen because the user can specify
2955 * a nonexistent slot name before server startup. That function cannot
2956 * validate such a slot during startup, as ReplicationSlotCtl is not
2957 * initialized by then. Also, the user might have dropped one slot.
2958 */
2959 if (!slot)
2960 {
2961 ereport(elevel,
2962 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2963 errmsg("replication slot \"%s\" specified in parameter \"%s\" does not exist",
2964 name, "synchronized_standby_slots"),
2965 errdetail("Logical replication is waiting on the standby associated with replication slot \"%s\".",
2966 name),
2967 errhint("Create the replication slot \"%s\" or amend parameter \"%s\".",
2968 name, "synchronized_standby_slots"));
2969 break;
2970 }
2971
2972 /* Same as above: if a slot is not physical, exit the loop. */
2973 if (SlotIsLogical(slot))
2974 {
2975 ereport(elevel,
2976 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2977 errmsg("cannot specify logical replication slot \"%s\" in parameter \"%s\"",
2978 name, "synchronized_standby_slots"),
2979 errdetail("Logical replication is waiting for correction on replication slot \"%s\".",
2980 name),
2981 errhint("Remove the logical replication slot \"%s\" from parameter \"%s\".",
2982 name, "synchronized_standby_slots"));
2983 break;
2984 }
2985
2986 SpinLockAcquire(&slot->mutex);
2987 restart_lsn = slot->data.restart_lsn;
2988 invalidated = slot->data.invalidated != RS_INVAL_NONE;
2989 inactive = slot->active_pid == 0;
2990 SpinLockRelease(&slot->mutex);
2991
2992 if (invalidated)
2993 {
2994 /* Specified physical slot has been invalidated */
2995 ereport(elevel,
2996 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2997 errmsg("physical replication slot \"%s\" specified in parameter \"%s\" has been invalidated",
2998 name, "synchronized_standby_slots"),
2999 errdetail("Logical replication is waiting on the standby associated with replication slot \"%s\".",
3000 name),
3001 errhint("Drop and recreate the replication slot \"%s\", or amend parameter \"%s\".",
3002 name, "synchronized_standby_slots"));
3003 break;
3004 }
3005
3006 if (XLogRecPtrIsInvalid(restart_lsn) || restart_lsn < wait_for_lsn)
3007 {
3008 /* Log a message if no active_pid for this physical slot */
3009 if (inactive)
3010 ereport(elevel,
3011 errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3012 errmsg("replication slot \"%s\" specified in parameter \"%s\" does not have active_pid",
3013 name, "synchronized_standby_slots"),
3014 errdetail("Logical replication is waiting on the standby associated with replication slot \"%s\".",
3015 name),
3016 errhint("Start the standby associated with the replication slot \"%s\", or amend parameter \"%s\".",
3017 name, "synchronized_standby_slots"));
3018
3019 /* Continue if the current slot hasn't caught up. */
3020 break;
3021 }
3022
3023 Assert(restart_lsn >= wait_for_lsn);
3024
3025 if (XLogRecPtrIsInvalid(min_restart_lsn) ||
3026 min_restart_lsn > restart_lsn)
3027 min_restart_lsn = restart_lsn;
3028
3029 caught_up_slot_num++;
3030
3031 name += strlen(name) + 1;
3032 }
3033
3034 LWLockRelease(ReplicationSlotControlLock);
3035
3036 /*
3037 * Return false if not all the standbys have caught up to the specified
3038 * WAL location.
3039 */
3040 if (caught_up_slot_num != synchronized_standby_slots_config->nslotnames)
3041 return false;
3042
3043 /* The ss_oldest_flush_lsn must not retreat. */
3045 min_restart_lsn >= ss_oldest_flush_lsn);
3046
3047 ss_oldest_flush_lsn = min_restart_lsn;
3048
3049 return true;
3050}
static XLogRecPtr ss_oldest_flush_lsn
Definition: slot.c:173
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29

References ReplicationSlot::active_pid, Assert(), ReplicationSlot::data, ereport, errcode(), errdetail(), errhint(), errmsg(), i, ReplicationSlotPersistentData::invalidated, InvalidXLogRecPtr, LW_SHARED, LWLockAcquire(), LWLockRelease(), ReplicationSlot::mutex, name, SyncStandbySlotsConfigData::nslotnames, RecoveryInProgress(), ReplicationSlotPersistentData::restart_lsn, RS_INVAL_NONE, SearchNamedReplicationSlot(), SyncStandbySlotsConfigData::slot_names, SlotIsLogical, SpinLockAcquire, SpinLockRelease, ss_oldest_flush_lsn, synchronized_standby_slots_config, and XLogRecPtrIsInvalid.

Referenced by NeedToWaitForStandbys(), and WaitForStandbyConfirmation().

◆ StartupReplicationSlots()

void StartupReplicationSlots ( void  )

Definition at line 2187 of file slot.c.

2188{
2189 DIR *replication_dir;
2190 struct dirent *replication_de;
2191
2192 elog(DEBUG1, "starting up replication slots");
2193
2194 /* restore all slots by iterating over all on-disk entries */
2195 replication_dir = AllocateDir(PG_REPLSLOT_DIR);
2196 while ((replication_de = ReadDir(replication_dir, PG_REPLSLOT_DIR)) != NULL)
2197 {
2198 char path[MAXPGPATH + sizeof(PG_REPLSLOT_DIR)];
2199 PGFileType de_type;
2200
2201 if (strcmp(replication_de->d_name, ".") == 0 ||
2202 strcmp(replication_de->d_name, "..") == 0)
2203 continue;
2204
2205 snprintf(path, sizeof(path), "%s/%s", PG_REPLSLOT_DIR, replication_de->d_name);
2206 de_type = get_dirent_type(path, replication_de, false, DEBUG1);
2207
2208 /* we're only creating directories here, skip if it's not our's */
2209 if (de_type != PGFILETYPE_ERROR && de_type != PGFILETYPE_DIR)
2210 continue;
2211
2212 /* we crashed while a slot was being setup or deleted, clean up */
2213 if (pg_str_endswith(replication_de->d_name, ".tmp"))
2214 {
2215 if (!rmtree(path, true))
2216 {
2218 (errmsg("could not remove directory \"%s\"",
2219 path)));
2220 continue;
2221 }
2223 continue;
2224 }
2225
2226 /* looks like a slot in a normal state, restore */
2227 RestoreSlotFromDisk(replication_de->d_name);
2228 }
2229 FreeDir(replication_dir);
2230
2231 /* currently no slots exist, we're done. */
2232 if (max_replication_slots <= 0)
2233 return;
2234
2235 /* Now that we have recovered all the data, compute replication xmin */
2238}
#define WARNING
Definition: elog.h:36
int FreeDir(DIR *dir)
Definition: fd.c:3022
void fsync_fname(const char *fname, bool isdir)
Definition: fd.c:753
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2904
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2970
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:547
PGFileType
Definition: file_utils.h:19
@ PGFILETYPE_DIR
Definition: file_utils.h:23
@ PGFILETYPE_ERROR
Definition: file_utils.h:20
bool rmtree(const char *path, bool rmtopdir)
Definition: rmtree.c:50
static void RestoreSlotFromDisk(const char *name)
Definition: slot.c:2465
bool pg_str_endswith(const char *str, const char *end)
Definition: string.c:31
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), dirent::d_name, DEBUG1, elog, ereport, errmsg(), FreeDir(), fsync_fname(), get_dirent_type(), max_replication_slots, MAXPGPATH, PG_REPLSLOT_DIR, pg_str_endswith(), PGFILETYPE_DIR, PGFILETYPE_ERROR, ReadDir(), ReplicationSlotsComputeRequiredLSN(), ReplicationSlotsComputeRequiredXmin(), RestoreSlotFromDisk(), rmtree(), snprintf, and WARNING.

Referenced by StartupXLOG().

◆ WaitForStandbyConfirmation()

void WaitForStandbyConfirmation ( XLogRecPtr  wait_for_lsn)

Definition at line 3059 of file slot.c.

3060{
3061 /*
3062 * Don't need to wait for the standby to catch up if the current acquired
3063 * slot is not a logical failover slot, or there is no value in
3064 * synchronized_standby_slots.
3065 */
3067 return;
3068
3070
3071 for (;;)
3072 {
3074
3076 {
3077 ConfigReloadPending = false;
3079 }
3080
3081 /* Exit if done waiting for every slot. */
3082 if (StandbySlotsHaveCaughtup(wait_for_lsn, WARNING))
3083 break;
3084
3085 /*
3086 * Wait for the slots in the synchronized_standby_slots to catch up,
3087 * but use a timeout (1s) so we can also check if the
3088 * synchronized_standby_slots has been changed.
3089 */
3091 WAIT_EVENT_WAIT_FOR_STANDBY_CONFIRMATION);
3092 }
3093
3095}
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
void ProcessConfigFile(GucContext context)
Definition: guc-file.l:120
@ PGC_SIGHUP
Definition: guc.h:75
volatile sig_atomic_t ConfigReloadPending
Definition: interrupt.c:27
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
bool StandbySlotsHaveCaughtup(XLogRecPtr wait_for_lsn, int elevel)
Definition: slot.c:2905
ConditionVariable wal_confirm_rcv_cv
WalSndCtlData * WalSndCtl
Definition: walsender.c:117

References CHECK_FOR_INTERRUPTS, ConditionVariableCancelSleep(), ConditionVariablePrepareToSleep(), ConditionVariableTimedSleep(), ConfigReloadPending, ReplicationSlot::data, ReplicationSlotPersistentData::failover, MyReplicationSlot, PGC_SIGHUP, ProcessConfigFile(), StandbySlotsHaveCaughtup(), synchronized_standby_slots_config, WalSndCtlData::wal_confirm_rcv_cv, WalSndCtl, and WARNING.

Referenced by LogicalSlotAdvanceAndCheckSnapState(), and pg_logical_slot_get_changes_guts().

Variable Documentation

◆ idle_replication_slot_timeout_secs

PGDLLIMPORT int idle_replication_slot_timeout_secs
extern

◆ max_replication_slots

◆ MyReplicationSlot

PGDLLIMPORT ReplicationSlot* MyReplicationSlot
extern

Definition at line 148 of file slot.c.

Referenced by ApplyLauncherMain(), binary_upgrade_logical_slot_has_caught_up(), compute_min_nonremovable_xid(), copy_replication_slot(), create_logical_replication_slot(), create_physical_replication_slot(), CreateConflictDetectionSlot(), CreateDecodingContext(), CreateInitDecodingContext(), CreateReplicationSlot(), init_conflict_slot_xmin(), InvalidatePossiblyObsoleteSlot(), LogicalConfirmReceivedLocation(), LogicalIncreaseRestartDecodingForSlot(), LogicalIncreaseXminForSlot(), logicalrep_worker_launch(), LogicalReplicationSlotHasPendingWal(), LogicalSlotAdvanceAndCheckSnapState(), NeedToWaitForStandbys(), pg_create_logical_replication_slot(), pg_create_physical_replication_slot(), pg_logical_slot_get_changes_guts(), pg_physical_replication_slot_advance(), pg_replication_slot_advance(), PhysicalConfirmReceivedLocation(), PhysicalReplicationSlotNewXmin(), PhysicalWakeupLogicalWalSnd(), PostgresMain(), ProcessStandbyHSFeedbackMessage(), ProcessStandbyReplyMessage(), ReorderBufferAllocate(), ReorderBufferFree(), ReorderBufferRestoreChanges(), ReorderBufferRestoreCleanup(), ReorderBufferSerializedPath(), ReorderBufferSerializeTXN(), ReplicationSlotAcquire(), ReplicationSlotAlter(), ReplicationSlotCleanup(), ReplicationSlotCreate(), ReplicationSlotDrop(), ReplicationSlotDropAcquired(), ReplicationSlotMarkDirty(), ReplicationSlotPersist(), ReplicationSlotRelease(), ReplicationSlotReserveWal(), ReplicationSlotSave(), ReplicationSlotsDropDBSlots(), ReplicationSlotShmemExit(), reserve_wal_for_local_slot(), slotsync_failure_callback(), slotsync_worker_onexit(), StartLogicalReplication(), StartReplication(), StartupDecodingContext(), synchronize_one_slot(), update_and_persist_local_synced_slot(), update_conflict_slot_xmin(), update_local_synced_slot(), WaitForStandbyConfirmation(), and WalSndErrorCleanup().

◆ ReplicationSlotCtl

◆ synchronized_standby_slots

PGDLLIMPORT char* synchronized_standby_slots
extern

Definition at line 164 of file slot.c.