PostgreSQL Source Code  git master
pgstat_replslot.c
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  *
3  * pgstat_replslot.c
4  * Implementation of replication slot statistics.
5  *
6  * This file contains the implementation of replication slot statistics. It is kept
7  * separate from pgstat.c to enforce the line between the statistics access /
8  * storage implementation and the details about individual types of
9  * statistics.
10  *
11  * Replication slot stats work a bit different than other variable-numbered
12  * stats. Slots do not have oids (so they can be created on physical
13  * replicas). Use the slot index as object id while running. However, the slot
14  * index can change when restarting. That is addressed by using the name when
15  * (de-)serializing. After a restart it is possible for slots to have been
16  * dropped while shut down, which is addressed by not restoring stats for
17  * slots that cannot be found by name when starting up.
18  *
19  * Copyright (c) 2001-2024, PostgreSQL Global Development Group
20  *
21  * IDENTIFICATION
22  * src/backend/utils/activity/pgstat_replslot.c
23  * -------------------------------------------------------------------------
24  */
25 
26 #include "postgres.h"
27 
28 #include "replication/slot.h"
29 #include "utils/pgstat_internal.h"
30 
31 
32 static int get_replslot_index(const char *name, bool need_lock);
33 
34 
35 /*
36  * Reset counters for a single replication slot.
37  *
38  * Permission checking for this function is managed through the normal
39  * GRANT system.
40  */
41 void
43 {
44  ReplicationSlot *slot;
45 
46  Assert(name != NULL);
47 
48  LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
49 
50  /* Check if the slot exits with the given name. */
51  slot = SearchNamedReplicationSlot(name, false);
52 
53  if (!slot)
54  ereport(ERROR,
55  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
56  errmsg("replication slot \"%s\" does not exist",
57  name)));
58 
59  /*
60  * Reset stats if it is a logical slot. Nothing to do for physical slots
61  * as we collect stats only for logical slots.
62  */
63  if (SlotIsLogical(slot))
65  ReplicationSlotIndex(slot));
66 
67  LWLockRelease(ReplicationSlotControlLock);
68 }
69 
70 /*
71  * Report replication slot statistics.
72  *
73  * We can rely on the stats for the slot to exist and to belong to this
74  * slot. We can only get here if pgstat_create_replslot() or
75  * pgstat_acquire_replslot() have already been called.
76  */
77 void
79 {
80  PgStat_EntryRef *entry_ref;
81  PgStatShared_ReplSlot *shstatent;
82  PgStat_StatReplSlotEntry *statent;
83 
85  ReplicationSlotIndex(slot), false);
86  shstatent = (PgStatShared_ReplSlot *) entry_ref->shared_stats;
87  statent = &shstatent->stats;
88 
89  /* Update the replication slot statistics */
90 #define REPLSLOT_ACC(fld) statent->fld += repSlotStat->fld
91  REPLSLOT_ACC(spill_txns);
92  REPLSLOT_ACC(spill_count);
93  REPLSLOT_ACC(spill_bytes);
94  REPLSLOT_ACC(stream_txns);
95  REPLSLOT_ACC(stream_count);
96  REPLSLOT_ACC(stream_bytes);
97  REPLSLOT_ACC(total_txns);
98  REPLSLOT_ACC(total_bytes);
99 #undef REPLSLOT_ACC
100 
101  pgstat_unlock_entry(entry_ref);
102 }
103 
104 /*
105  * Report replication slot creation.
106  *
107  * NB: This gets called with ReplicationSlotAllocationLock already held, be
108  * careful about calling back into slot.c.
109  */
110 void
112 {
113  PgStat_EntryRef *entry_ref;
114  PgStatShared_ReplSlot *shstatent;
115 
116  Assert(LWLockHeldByMeInMode(ReplicationSlotAllocationLock, LW_EXCLUSIVE));
117 
119  ReplicationSlotIndex(slot), false);
120  shstatent = (PgStatShared_ReplSlot *) entry_ref->shared_stats;
121 
122  /*
123  * NB: need to accept that there might be stats from an older slot, e.g.
124  * if we previously crashed after dropping a slot.
125  */
126  memset(&shstatent->stats, 0, sizeof(shstatent->stats));
127 
128  pgstat_unlock_entry(entry_ref);
129 }
130 
131 /*
132  * Report replication slot has been acquired.
133  *
134  * This guarantees that a stats entry exists during later
135  * pgstat_report_replslot() calls.
136  *
137  * If we previously crashed, no stats data exists. But if we did not crash,
138  * the stats do belong to this slot:
139  * - the stats cannot belong to a dropped slot, pgstat_drop_replslot() would
140  * have been called
141  * - if the slot was removed while shut down,
142  * pgstat_replslot_from_serialized_name_cb() returning false would have
143  * caused the stats to be dropped
144  */
145 void
147 {
149  ReplicationSlotIndex(slot), true, NULL);
150 }
151 
152 /*
153  * Report replication slot drop.
154  */
155 void
157 {
158  Assert(LWLockHeldByMeInMode(ReplicationSlotAllocationLock, LW_EXCLUSIVE));
159 
161  ReplicationSlotIndex(slot));
162 }
163 
164 /*
165  * Support function for the SQL-callable pgstat* functions. Returns
166  * a pointer to the replication slot statistics struct.
167  */
170 {
171  int idx;
172  PgStat_StatReplSlotEntry *slotentry = NULL;
173 
174  LWLockAcquire(ReplicationSlotControlLock, LW_SHARED);
175 
176  idx = get_replslot_index(NameStr(slotname), false);
177 
178  if (idx != -1)
180  InvalidOid, idx);
181 
182  LWLockRelease(ReplicationSlotControlLock);
183 
184  return slotentry;
185 }
186 
187 void
189 {
190  /*
191  * This is only called late during shutdown. The set of existing slots
192  * isn't allowed to change at this point, we can assume that a slot exists
193  * at the offset.
194  */
195  if (!ReplicationSlotName(key->objoid, name))
196  elog(ERROR, "could not find name for replication slot index %u",
197  key->objoid);
198 }
199 
200 bool
202 {
203  int idx = get_replslot_index(NameStr(*name), true);
204 
205  /* slot might have been deleted */
206  if (idx == -1)
207  return false;
208 
209  key->kind = PGSTAT_KIND_REPLSLOT;
210  key->dboid = InvalidOid;
211  key->objoid = idx;
212 
213  return true;
214 }
215 
216 void
218 {
219  ((PgStatShared_ReplSlot *) header)->stats.stat_reset_timestamp = ts;
220 }
221 
222 static int
223 get_replslot_index(const char *name, bool need_lock)
224 {
225  ReplicationSlot *slot;
226 
227  Assert(name != NULL);
228 
229  slot = SearchNamedReplicationSlot(name, need_lock);
230 
231  if (!slot)
232  return -1;
233 
234  return ReplicationSlotIndex(slot);
235 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define NameStr(name)
Definition: c.h:746
#define Assert(condition)
Definition: c.h:858
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define ereport(elevel,...)
Definition: elog.h:149
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1939
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_SHARED
Definition: lwlock.h:115
@ LW_EXCLUSIVE
Definition: lwlock.h:114
void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:734
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:812
@ PGSTAT_KIND_REPLSLOT
Definition: pgstat.h:44
bool pgstat_replslot_from_serialized_name_cb(const NameData *name, PgStat_HashKey *key)
void pgstat_reset_replslot(const char *name)
void pgstat_create_replslot(ReplicationSlot *slot)
void pgstat_acquire_replslot(ReplicationSlot *slot)
static int get_replslot_index(const char *name, bool need_lock)
void pgstat_report_replslot(ReplicationSlot *slot, const PgStat_StatReplSlotEntry *repSlotStat)
void pgstat_replslot_to_serialized_name_cb(const PgStat_HashKey *key, const PgStatShared_Common *header, NameData *name)
void pgstat_replslot_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
void pgstat_drop_replslot(ReplicationSlot *slot)
PgStat_StatReplSlotEntry * pgstat_fetch_replslot(NameData slotname)
#define REPLSLOT_ACC(fld)
PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, Oid objoid, bool create, bool *created_entry)
Definition: pgstat_shmem.c:398
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:604
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:859
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, Oid objoid, bool nowait)
Definition: pgstat_shmem.c:613
#define InvalidOid
Definition: postgres_ext.h:36
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
Definition: slot.c:464
int ReplicationSlotIndex(ReplicationSlot *slot)
Definition: slot.c:497
bool ReplicationSlotName(int index, Name name)
Definition: slot.c:513
#define SlotIsLogical(slot)
Definition: slot.h:210
PgStat_StatReplSlotEntry stats
PgStatShared_Common * shared_stats
Definition: c.h:741
const char * name