PostgreSQL Source Code  git master
pgstat_xact.c
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------
2  *
3  * pgstat_xact.c
4  * Transactional integration for the cumulative statistics system.
5  *
6  * Copyright (c) 2001-2023, PostgreSQL Global Development Group
7  *
8  * IDENTIFICATION
9  * src/backend/utils/activity/pgstat_xact.c
10  * -------------------------------------------------------------------------
11  */
12 
13 #include "postgres.h"
14 
15 #include "access/transam.h"
16 #include "access/xact.h"
17 #include "pgstat.h"
18 #include "utils/memutils.h"
19 #include "utils/pgstat_internal.h"
20 
21 
23 {
25  bool is_create;
28 
29 
30 static void AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit);
32  bool isCommit, int nestDepth);
33 
35 
36 
37 /*
38  * Called from access/transam/xact.c at top-level transaction commit/abort.
39  */
40 void
41 AtEOXact_PgStat(bool isCommit, bool parallel)
42 {
43  PgStat_SubXactStatus *xact_state;
44 
45  AtEOXact_PgStat_Database(isCommit, parallel);
46 
47  /* handle transactional stats information */
48  xact_state = pgStatXactStack;
49  if (xact_state != NULL)
50  {
51  Assert(xact_state->nest_level == 1);
52  Assert(xact_state->prev == NULL);
53 
54  AtEOXact_PgStat_Relations(xact_state, isCommit);
55  AtEOXact_PgStat_DroppedStats(xact_state, isCommit);
56  }
57  pgStatXactStack = NULL;
58 
59  /* Make sure any stats snapshot is thrown away */
61 }
62 
63 /*
64  * When committing, drop stats for objects dropped in the transaction. When
65  * aborting, drop stats for objects created in the transaction.
66  */
67 static void
69 {
70  dlist_mutable_iter iter;
71  int not_freed_count = 0;
72 
73  if (dclist_count(&xact_state->pending_drops) == 0)
74  return;
75 
76  dclist_foreach_modify(iter, &xact_state->pending_drops)
77  {
80  xl_xact_stats_item *it = &pending->item;
81 
82  if (isCommit && !pending->is_create)
83  {
84  /*
85  * Transaction that dropped an object committed. Drop the stats
86  * too.
87  */
88  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
89  not_freed_count++;
90  }
91  else if (!isCommit && pending->is_create)
92  {
93  /*
94  * Transaction that created an object aborted. Drop the stats
95  * associated with the object.
96  */
97  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
98  not_freed_count++;
99  }
100 
101  dclist_delete_from(&xact_state->pending_drops, &pending->node);
102  pfree(pending);
103  }
104 
105  if (not_freed_count > 0)
107 }
108 
109 /*
110  * Called from access/transam/xact.c at subtransaction commit/abort.
111  */
112 void
113 AtEOSubXact_PgStat(bool isCommit, int nestDepth)
114 {
115  PgStat_SubXactStatus *xact_state;
116 
117  /* merge the sub-transaction's transactional stats into the parent */
118  xact_state = pgStatXactStack;
119  if (xact_state != NULL &&
120  xact_state->nest_level >= nestDepth)
121  {
122  /* delink xact_state from stack immediately to simplify reuse case */
123  pgStatXactStack = xact_state->prev;
124 
125  AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
126  AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
127 
128  pfree(xact_state);
129  }
130 }
131 
132 /*
133  * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
134  */
135 static void
137  bool isCommit, int nestDepth)
138 {
139  PgStat_SubXactStatus *parent_xact_state;
140  dlist_mutable_iter iter;
141  int not_freed_count = 0;
142 
143  if (dclist_count(&xact_state->pending_drops) == 0)
144  return;
145 
146  parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
147 
148  dclist_foreach_modify(iter, &xact_state->pending_drops)
149  {
152  xl_xact_stats_item *it = &pending->item;
153 
154  dclist_delete_from(&xact_state->pending_drops, &pending->node);
155 
156  if (!isCommit && pending->is_create)
157  {
158  /*
159  * Subtransaction creating a new stats object aborted. Drop the
160  * stats object.
161  */
162  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
163  not_freed_count++;
164  pfree(pending);
165  }
166  else if (isCommit)
167  {
168  /*
169  * Subtransaction dropping a stats object committed. Can't yet
170  * remove the stats object, the surrounding transaction might
171  * still abort. Pass it on to the parent.
172  */
173  dclist_push_tail(&parent_xact_state->pending_drops, &pending->node);
174  }
175  else
176  {
177  pfree(pending);
178  }
179  }
180 
181  Assert(dclist_count(&xact_state->pending_drops) == 0);
182  if (not_freed_count > 0)
184 }
185 
186 /*
187  * Save the transactional stats state at 2PC transaction prepare.
188  */
189 void
191 {
192  PgStat_SubXactStatus *xact_state;
193 
194  xact_state = pgStatXactStack;
195  if (xact_state != NULL)
196  {
197  Assert(xact_state->nest_level == 1);
198  Assert(xact_state->prev == NULL);
199 
200  AtPrepare_PgStat_Relations(xact_state);
201  }
202 }
203 
204 /*
205  * Clean up after successful PREPARE.
206  *
207  * Note: AtEOXact_PgStat is not called during PREPARE.
208  */
209 void
211 {
212  PgStat_SubXactStatus *xact_state;
213 
214  /*
215  * We don't bother to free any of the transactional state, since it's all
216  * in TopTransactionContext and will go away anyway.
217  */
218  xact_state = pgStatXactStack;
219  if (xact_state != NULL)
220  {
221  Assert(xact_state->nest_level == 1);
222  Assert(xact_state->prev == NULL);
223 
224  PostPrepare_PgStat_Relations(xact_state);
225  }
226  pgStatXactStack = NULL;
227 
228  /* Make sure any stats snapshot is thrown away */
230 }
231 
232 /*
233  * Ensure (sub)transaction stack entry for the given nest_level exists, adding
234  * it if needed.
235  */
238 {
239  PgStat_SubXactStatus *xact_state;
240 
241  xact_state = pgStatXactStack;
242  if (xact_state == NULL || xact_state->nest_level != nest_level)
243  {
244  xact_state = (PgStat_SubXactStatus *)
246  sizeof(PgStat_SubXactStatus));
247  dclist_init(&xact_state->pending_drops);
248  xact_state->nest_level = nest_level;
249  xact_state->prev = pgStatXactStack;
250  xact_state->first = NULL;
251  pgStatXactStack = xact_state;
252  }
253  return xact_state;
254 }
255 
256 /*
257  * Get stat items that need to be dropped at commit / abort.
258  *
259  * When committing, stats for objects that have been dropped in the
260  * transaction are returned. When aborting, stats for newly created objects are
261  * returned.
262  *
263  * Used by COMMIT / ABORT and 2PC PREPARE processing when building their
264  * respective WAL records, to ensure stats are dropped in case of a crash / on
265  * standbys.
266  *
267  * The list of items is allocated in CurrentMemoryContext and must be freed by
268  * the caller (directly or via memory context reset).
269  */
270 int
272 {
274  int nitems = 0;
275  dlist_iter iter;
276 
277  if (xact_state == NULL)
278  return 0;
279 
280  /*
281  * We expect to be called for subtransaction abort (which logs a WAL
282  * record), but not for subtransaction commit (which doesn't).
283  */
284  Assert(!isCommit || xact_state->nest_level == 1);
285  Assert(!isCommit || xact_state->prev == NULL);
286 
287  *items = palloc(dclist_count(&xact_state->pending_drops)
288  * sizeof(xl_xact_stats_item));
289 
290  dclist_foreach(iter, &xact_state->pending_drops)
291  {
294 
295  if (isCommit && pending->is_create)
296  continue;
297  if (!isCommit && !pending->is_create)
298  continue;
299 
300  Assert(nitems < dclist_count(&xact_state->pending_drops));
301  (*items)[nitems++] = pending->item;
302  }
303 
304  return nitems;
305 }
306 
307 /*
308  * Execute scheduled drops post-commit. Called from xact_redo_commit() /
309  * xact_redo_abort() during recovery, and from FinishPreparedTransaction()
310  * during normal 2PC COMMIT/ABORT PREPARED processing.
311  */
312 void
313 pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
314 {
315  int not_freed_count = 0;
316 
317  if (ndrops == 0)
318  return;
319 
320  for (int i = 0; i < ndrops; i++)
321  {
322  xl_xact_stats_item *it = &items[i];
323 
324  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
325  not_freed_count++;
326  }
327 
328  if (not_freed_count > 0)
330 }
331 
332 static void
333 create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
334 {
335  int nest_level = GetCurrentTransactionNestLevel();
336  PgStat_SubXactStatus *xact_state;
339 
340  xact_state = pgstat_get_xact_stack_level(nest_level);
341 
342  drop->is_create = is_create;
343  drop->item.kind = kind;
344  drop->item.dboid = dboid;
345  drop->item.objoid = objoid;
346 
347  dclist_push_tail(&xact_state->pending_drops, &drop->node);
348 }
349 
350 /*
351  * Create a stats entry for a newly created database object in a transactional
352  * manner.
353  *
354  * I.e. if the current (sub-)transaction aborts, the stats entry will also be
355  * dropped.
356  */
357 void
359 {
360  if (pgstat_get_entry_ref(kind, dboid, objoid, false, NULL))
361  {
363  errmsg("resetting existing statistics for kind %s, db=%u, oid=%u",
364  (pgstat_get_kind_info(kind))->name, dboid, objoid));
365 
366  pgstat_reset(kind, dboid, objoid);
367  }
368 
369  create_drop_transactional_internal(kind, dboid, objoid, /* create */ true);
370 }
371 
372 /*
373  * Drop a stats entry for a just dropped database object in a transactional
374  * manner.
375  *
376  * I.e. if the current (sub-)transaction aborts, the stats entry will stay
377  * alive.
378  */
379 void
381 {
382  create_drop_transactional_internal(kind, dboid, objoid, /* create */ false);
383 }
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
#define dclist_container(type, membername, ptr)
Definition: ilist.h:947
static void dclist_push_tail(dclist_head *head, dlist_node *node)
Definition: ilist.h:709
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
static void dclist_delete_from(dclist_head *head, dlist_node *node)
Definition: ilist.h:763
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
#define dclist_foreach_modify(iter, lhead)
Definition: ilist.h:973
#define dclist_foreach(iter, lhead)
Definition: ilist.h:970
#define nitems(x)
Definition: indent.h:31
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext TopTransactionContext
Definition: mcxt.c:146
void pfree(void *pointer)
Definition: mcxt.c:1456
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
void * palloc(Size size)
Definition: mcxt.c:1226
void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:737
const PgStat_KindInfo * pgstat_get_kind_info(PgStat_Kind kind)
Definition: pgstat.c:1263
void pgstat_clear_snapshot(void)
Definition: pgstat.c:785
PgStat_Kind
Definition: pgstat.h:36
void AtEOXact_PgStat_Database(bool isCommit, bool parallel)
void AtPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state)
void AtEOXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit)
void PostPrepare_PgStat_Relations(PgStat_SubXactStatus *xact_state)
void AtEOSubXact_PgStat_Relations(PgStat_SubXactStatus *xact_state, bool isCommit, int nestDepth)
void pgstat_request_entry_refs_gc(void)
Definition: pgstat_shmem.c:628
PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, Oid objoid, bool create, bool *created_entry)
Definition: pgstat_shmem.c:397
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:858
static PgStat_SubXactStatus * pgStatXactStack
Definition: pgstat_xact.c:34
void AtPrepare_PgStat(void)
Definition: pgstat_xact.c:190
void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
Definition: pgstat_xact.c:313
void AtEOXact_PgStat(bool isCommit, bool parallel)
Definition: pgstat_xact.c:41
static void AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit, int nestDepth)
Definition: pgstat_xact.c:136
void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:358
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:380
struct PgStat_PendingDroppedStatsItem PgStat_PendingDroppedStatsItem
void PostPrepare_PgStat(void)
Definition: pgstat_xact.c:210
int pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
Definition: pgstat_xact.c:271
void AtEOSubXact_PgStat(bool isCommit, int nestDepth)
Definition: pgstat_xact.c:113
PgStat_SubXactStatus * pgstat_get_xact_stack_level(int nest_level)
Definition: pgstat_xact.c:237
static void create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
Definition: pgstat_xact.c:333
static void AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
Definition: pgstat_xact.c:68
unsigned int Oid
Definition: postgres_ext.h:31
xl_xact_stats_item item
Definition: pgstat_xact.c:24
PgStat_TableXactStatus * first
struct PgStat_SubXactStatus * prev
dlist_node * cur
Definition: ilist.h:179
dlist_node * cur
Definition: ilist.h:200
const char * name
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:914