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 other
12  * variable-numbered stats. Slots do not have oids (so they can be created on
13  * physical replicas). Use the slot index as object id while running. However,
14  * the slot index can change when restarting. That is addressed by using the
15  * name when (de-)serializing. After a restart it is possible for slots to
16  * have been dropped while shut down, which is addressed by not restoring
17  * stats for slots that cannot be found by name when starting up.
18  *
19  * Copyright (c) 2001-2022, 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  AssertArg(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 void
75 {
76  PgStat_EntryRef *entry_ref;
77  PgStatShared_ReplSlot *shstatent;
78  PgStat_StatReplSlotEntry *statent;
79 
81  ReplicationSlotIndex(slot), false);
82  shstatent = (PgStatShared_ReplSlot *) entry_ref->shared_stats;
83  statent = &shstatent->stats;
84 
85  /*
86  * Any mismatch should have been fixed in pgstat_create_replslot() or
87  * pgstat_acquire_replslot().
88  */
89  Assert(namestrcmp(&statent->slotname, NameStr(slot->data.name)) == 0);
90 
91  /* Update the replication slot statistics */
92 #define REPLSLOT_ACC(fld) statent->fld += repSlotStat->fld
93  REPLSLOT_ACC(spill_txns);
94  REPLSLOT_ACC(spill_count);
95  REPLSLOT_ACC(spill_bytes);
96  REPLSLOT_ACC(stream_txns);
97  REPLSLOT_ACC(stream_count);
98  REPLSLOT_ACC(stream_bytes);
99  REPLSLOT_ACC(total_txns);
100  REPLSLOT_ACC(total_bytes);
101 #undef REPLSLOT_ACC
102 
103  pgstat_unlock_entry(entry_ref);
104 }
105 
106 /*
107  * Report replication slot creation.
108  *
109  * NB: This gets called with ReplicationSlotAllocationLock already held, be
110  * careful about calling back into slot.c.
111  */
112 void
114 {
115  PgStat_EntryRef *entry_ref;
116  PgStatShared_ReplSlot *shstatent;
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  namestrcpy(&shstatent->stats.slotname, NameStr(slot->data.name));
128 
129  pgstat_unlock_entry(entry_ref);
130 }
131 
132 /*
133  * Report replication slot has been acquired.
134  */
135 void
137 {
138  PgStat_EntryRef *entry_ref;
139  PgStatShared_ReplSlot *shstatent;
140  PgStat_StatReplSlotEntry *statent;
141 
143  ReplicationSlotIndex(slot), false);
144  shstatent = (PgStatShared_ReplSlot *) entry_ref->shared_stats;
145  statent = &shstatent->stats;
146 
147  /*
148  * NB: need to accept that there might be stats from an older slot, e.g.
149  * if we previously crashed after dropping a slot.
150  */
151  if (NameStr(statent->slotname)[0] == 0 ||
152  namestrcmp(&statent->slotname, NameStr(slot->data.name)) != 0)
153  {
154  memset(statent, 0, sizeof(*statent));
155  namestrcpy(&statent->slotname, NameStr(slot->data.name));
156  }
157 
158  pgstat_unlock_entry(entry_ref);
159 }
160 
161 /*
162  * Report replication slot drop.
163  */
164 void
166 {
168  ReplicationSlotIndex(slot));
169 }
170 
171 /*
172  * Support function for the SQL-callable pgstat* functions. Returns
173  * a pointer to the replication slot statistics struct.
174  */
177 {
178  int idx = get_replslot_index(NameStr(slotname));
179 
180  if (idx == -1)
181  return NULL;
182 
183  return (PgStat_StatReplSlotEntry *)
185 }
186 
187 void
189 {
190  namestrcpy(name, NameStr(((PgStatShared_ReplSlot *) header)->stats.slotname));
191 }
192 
193 bool
195 {
197 
198  /* slot might have been deleted */
199  if (idx == -1)
200  return false;
201 
202  key->kind = PGSTAT_KIND_REPLSLOT;
203  key->dboid = InvalidOid;
204  key->objoid = idx;
205 
206  return true;
207 }
208 
209 void
211 {
212  ((PgStatShared_ReplSlot *) header)->stats.stat_reset_timestamp = ts;
213 }
214 
215 static int
217 {
218  ReplicationSlot *slot;
219 
220  AssertArg(name != NULL);
221 
222  slot = SearchNamedReplicationSlot(name, true);
223 
224  if (!slot)
225  return -1;
226 
227  return ReplicationSlotIndex(slot);
228 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
#define NameStr(name)
Definition: c.h:681
#define AssertArg(condition)
Definition: c.h:806
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
const char * name
Definition: encode.c:561
Assert(fmt[strlen(fmt) - 1] !='\n')
int namestrcmp(Name name, const char *str)
Definition: name.c:247
void namestrcpy(Name name, const char *str)
Definition: name.c:233
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:212
void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:705
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:779
@ 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 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)
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:583
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:838
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, Oid objoid, bool nowait)
Definition: pgstat_shmem.c:592
#define InvalidOid
Definition: postgres_ext.h:36
ReplicationSlot * SearchNamedReplicationSlot(const char *name, bool need_lock)
Definition: slot.c:377
int ReplicationSlotIndex(ReplicationSlot *slot)
Definition: slot.c:410
#define SlotIsPhysical(slot)
Definition: slot.h:168
PgStat_StatReplSlotEntry stats
PgStatShared_Common * shared_stats
ReplicationSlotPersistentData data
Definition: slot.h:147
Definition: c.h:676