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-2023, 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/builtins.h" /* for namestrcpy() */
30 #include "utils/pgstat_internal.h"
31 
32 
33 static int get_replslot_index(const char *name);
34 
35 
36 /*
37  * Reset counters for a single replication slot.
38  *
39  * Permission checking for this function is managed through the normal
40  * GRANT system.
41  */
42 void
44 {
45  ReplicationSlot *slot;
46 
47  Assert(name != NULL);
48 
49  /* Check if the slot exits with the given name. */
50  slot = SearchNamedReplicationSlot(name, true);
51 
52  if (!slot)
53  ereport(ERROR,
54  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
55  errmsg("replication slot \"%s\" does not exist",
56  name)));
57 
58  /*
59  * Nothing to do for physical slots as we collect stats only for logical
60  * slots.
61  */
62  if (SlotIsPhysical(slot))
63  return;
64 
65  /* reset this one entry */
67  ReplicationSlotIndex(slot));
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 
117  ReplicationSlotIndex(slot), false);
118  shstatent = (PgStatShared_ReplSlot *) entry_ref->shared_stats;
119 
120  /*
121  * NB: need to accept that there might be stats from an older slot, e.g.
122  * if we previously crashed after dropping a slot.
123  */
124  memset(&shstatent->stats, 0, sizeof(shstatent->stats));
125 
126  pgstat_unlock_entry(entry_ref);
127 }
128 
129 /*
130  * Report replication slot has been acquired.
131  *
132  * This guarantees that a stats entry exists during later
133  * pgstat_report_replslot() calls.
134  *
135  * If we previously crashed, no stats data exists. But if we did not crash,
136  * the stats do belong to this slot:
137  * - the stats cannot belong to a dropped slot, pgstat_drop_replslot() would
138  * have been called
139  * - if the slot was removed while shut down,
140  * pgstat_replslot_from_serialized_name_cb() returning false would have
141  * caused the stats to be dropped
142  */
143 void
145 {
147  ReplicationSlotIndex(slot), true, NULL);
148 }
149 
150 /*
151  * Report replication slot drop.
152  */
153 void
155 {
157  ReplicationSlotIndex(slot));
158 }
159 
160 /*
161  * Support function for the SQL-callable pgstat* functions. Returns
162  * a pointer to the replication slot statistics struct.
163  */
166 {
167  int idx = get_replslot_index(NameStr(slotname));
168 
169  if (idx == -1)
170  return NULL;
171 
172  return (PgStat_StatReplSlotEntry *)
174 }
175 
176 void
178 {
179  /*
180  * This is only called late during shutdown. The set of existing slots
181  * isn't allowed to change at this point, we can assume that a slot exists
182  * at the offset.
183  */
184  if (!ReplicationSlotName(key->objoid, name))
185  elog(ERROR, "could not find name for replication slot index %u",
186  key->objoid);
187 }
188 
189 bool
191 {
193 
194  /* slot might have been deleted */
195  if (idx == -1)
196  return false;
197 
198  key->kind = PGSTAT_KIND_REPLSLOT;
199  key->dboid = InvalidOid;
200  key->objoid = idx;
201 
202  return true;
203 }
204 
205 void
207 {
208  ((PgStatShared_ReplSlot *) header)->stats.stat_reset_timestamp = ts;
209 }
210 
211 static int
213 {
214  ReplicationSlot *slot;
215 
216  Assert(name != NULL);
217 
218  slot = SearchNamedReplicationSlot(name, true);
219 
220  if (!slot)
221  return -1;
222 
223  return ReplicationSlotIndex(slot);
224 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define NameStr(name)
Definition: c.h:735
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')
void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:737
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:815
@ 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)
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:397
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:603
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:858
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, Oid objoid, bool nowait)
Definition: pgstat_shmem.c:612
#define InvalidOid
Definition: postgres_ext.h:36
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
Definition: slot.c:376
int ReplicationSlotIndex(ReplicationSlot *slot)
Definition: slot.c:409
bool ReplicationSlotName(int index, Name name)
Definition: slot.c:425
#define SlotIsPhysical(slot)
Definition: slot.h:190
PgStat_StatReplSlotEntry stats
PgStatShared_Common * shared_stats
Definition: c.h:730
const char * name