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-2022, 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 (xact_state->pending_drops_count == 0)
74  {
75  Assert(dlist_is_empty(&xact_state->pending_drops));
76  return;
77  }
78 
79  dlist_foreach_modify(iter, &xact_state->pending_drops)
80  {
83  xl_xact_stats_item *it = &pending->item;
84 
85  if (isCommit && !pending->is_create)
86  {
87  /*
88  * Transaction that dropped an object committed. Drop the stats
89  * too.
90  */
91  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
92  not_freed_count++;
93  }
94  else if (!isCommit && pending->is_create)
95  {
96  /*
97  * Transaction that created an object aborted. Drop the stats
98  * associated with the object.
99  */
100  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
101  not_freed_count++;
102  }
103 
104  dlist_delete(&pending->node);
105  xact_state->pending_drops_count--;
106  pfree(pending);
107  }
108 
109  if (not_freed_count > 0)
111 }
112 
113 /*
114  * Called from access/transam/xact.c at subtransaction commit/abort.
115  */
116 void
117 AtEOSubXact_PgStat(bool isCommit, int nestDepth)
118 {
119  PgStat_SubXactStatus *xact_state;
120 
121  /* merge the sub-transaction's transactional stats into the parent */
122  xact_state = pgStatXactStack;
123  if (xact_state != NULL &&
124  xact_state->nest_level >= nestDepth)
125  {
126  /* delink xact_state from stack immediately to simplify reuse case */
127  pgStatXactStack = xact_state->prev;
128 
129  AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
130  AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
131 
132  pfree(xact_state);
133  }
134 }
135 
136 /*
137  * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
138  */
139 static void
141  bool isCommit, int nestDepth)
142 {
143  PgStat_SubXactStatus *parent_xact_state;
144  dlist_mutable_iter iter;
145  int not_freed_count = 0;
146 
147  if (xact_state->pending_drops_count == 0)
148  return;
149 
150  parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
151 
152  dlist_foreach_modify(iter, &xact_state->pending_drops)
153  {
156  xl_xact_stats_item *it = &pending->item;
157 
158  dlist_delete(&pending->node);
159  xact_state->pending_drops_count--;
160 
161  if (!isCommit && pending->is_create)
162  {
163  /*
164  * Subtransaction creating a new stats object aborted. Drop the
165  * stats object.
166  */
167  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
168  not_freed_count++;
169  pfree(pending);
170  }
171  else if (isCommit)
172  {
173  /*
174  * Subtransaction dropping a stats object committed. Can't yet
175  * remove the stats object, the surrounding transaction might
176  * still abort. Pass it on to the parent.
177  */
178  dlist_push_tail(&parent_xact_state->pending_drops, &pending->node);
179  parent_xact_state->pending_drops_count++;
180  }
181  else
182  {
183  pfree(pending);
184  }
185  }
186 
187  Assert(xact_state->pending_drops_count == 0);
188  if (not_freed_count > 0)
190 }
191 
192 /*
193  * Save the transactional stats state at 2PC transaction prepare.
194  */
195 void
197 {
198  PgStat_SubXactStatus *xact_state;
199 
200  xact_state = pgStatXactStack;
201  if (xact_state != NULL)
202  {
203  Assert(xact_state->nest_level == 1);
204  Assert(xact_state->prev == NULL);
205 
206  AtPrepare_PgStat_Relations(xact_state);
207  }
208 }
209 
210 /*
211  * Clean up after successful PREPARE.
212  *
213  * Note: AtEOXact_PgStat is not called during PREPARE.
214  */
215 void
217 {
218  PgStat_SubXactStatus *xact_state;
219 
220  /*
221  * We don't bother to free any of the transactional state, since it's all
222  * in TopTransactionContext and will go away anyway.
223  */
224  xact_state = pgStatXactStack;
225  if (xact_state != NULL)
226  {
227  Assert(xact_state->nest_level == 1);
228  Assert(xact_state->prev == NULL);
229 
230  PostPrepare_PgStat_Relations(xact_state);
231  }
232  pgStatXactStack = NULL;
233 
234  /* Make sure any stats snapshot is thrown away */
236 }
237 
238 /*
239  * Ensure (sub)transaction stack entry for the given nest_level exists, adding
240  * it if needed.
241  */
244 {
245  PgStat_SubXactStatus *xact_state;
246 
247  xact_state = pgStatXactStack;
248  if (xact_state == NULL || xact_state->nest_level != nest_level)
249  {
250  xact_state = (PgStat_SubXactStatus *)
252  sizeof(PgStat_SubXactStatus));
253  dlist_init(&xact_state->pending_drops);
254  xact_state->pending_drops_count = 0;
255  xact_state->nest_level = nest_level;
256  xact_state->prev = pgStatXactStack;
257  xact_state->first = NULL;
258  pgStatXactStack = xact_state;
259  }
260  return xact_state;
261 }
262 
263 /*
264  * Get stat items that need to be dropped at commit / abort.
265  *
266  * When committing, stats for objects that have been dropped in the
267  * transaction are returned. When aborting, stats for newly created objects are
268  * returned.
269  *
270  * Used by COMMIT / ABORT and 2PC PREPARE processing when building their
271  * respective WAL records, to ensure stats are dropped in case of a crash / on
272  * standbys.
273  *
274  * The list of items is allocated in CurrentMemoryContext and must be freed by
275  * the caller (directly or via memory context reset).
276  */
277 int
279 {
281  int nitems = 0;
282  dlist_iter iter;
283 
284  if (xact_state == NULL)
285  return 0;
286 
287  /*
288  * We expect to be called for subtransaction abort (which logs a WAL
289  * record), but not for subtransaction commit (which doesn't).
290  */
291  Assert(!isCommit || xact_state->nest_level == 1);
292  Assert(!isCommit || xact_state->prev == NULL);
293 
294  *items = palloc(xact_state->pending_drops_count
295  * sizeof(xl_xact_stats_item));
296 
297  dlist_foreach(iter, &xact_state->pending_drops)
298  {
301 
302  if (isCommit && pending->is_create)
303  continue;
304  if (!isCommit && !pending->is_create)
305  continue;
306 
307  Assert(nitems < xact_state->pending_drops_count);
308  (*items)[nitems++] = pending->item;
309  }
310 
311  return nitems;
312 }
313 
314 /*
315  * Execute scheduled drops post-commit. Called from xact_redo_commit() /
316  * xact_redo_abort() during recovery, and from FinishPreparedTransaction()
317  * during normal 2PC COMMIT/ABORT PREPARED processing.
318  */
319 void
320 pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
321 {
322  int not_freed_count = 0;
323 
324  if (ndrops == 0)
325  return;
326 
327  for (int i = 0; i < ndrops; i++)
328  {
329  xl_xact_stats_item *it = &items[i];
330 
331  if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
332  not_freed_count++;
333  }
334 
335  if (not_freed_count > 0)
337 }
338 
339 static void
340 create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
341 {
342  int nest_level = GetCurrentTransactionNestLevel();
343  PgStat_SubXactStatus *xact_state;
346 
347  xact_state = pgstat_get_xact_stack_level(nest_level);
348 
349  drop->is_create = is_create;
350  drop->item.kind = kind;
351  drop->item.dboid = dboid;
352  drop->item.objoid = objoid;
353 
354  dlist_push_tail(&xact_state->pending_drops, &drop->node);
355  xact_state->pending_drops_count++;
356 }
357 
358 /*
359  * Create a stats entry for a newly created database object in a transactional
360  * manner.
361  *
362  * I.e. if the current (sub-)transaction aborts, the stats entry will also be
363  * dropped.
364  */
365 void
367 {
368  if (pgstat_get_entry_ref(kind, dboid, objoid, false, NULL))
369  {
371  errmsg("resetting existing stats for type %s, db=%u, oid=%u",
372  (pgstat_get_kind_info(kind))->name, dboid, objoid));
373 
374  pgstat_reset(kind, dboid, objoid);
375  }
376 
377  create_drop_transactional_internal(kind, dboid, objoid, /* create */ true);
378 }
379 
380 /*
381  * Drop a stats entry for a just dropped database object in a transactional
382  * manner.
383  *
384  * I.e. if the current (sub-)transaction aborts, the stats entry will stay
385  * alive.
386  */
387 void
389 {
390  create_drop_transactional_internal(kind, dboid, objoid, /* create */ false);
391 }
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define WARNING
Definition: elog.h:30
#define ereport(elevel,...)
Definition: elog.h:143
const char * name
Definition: encode.c:561
#define dlist_foreach(iter, lhead)
Definition: ilist.h:526
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
static bool dlist_is_empty(dlist_head *head)
Definition: ilist.h:289
static void dlist_delete(dlist_node *node)
Definition: ilist.h:358
#define dlist_foreach_modify(iter, lhead)
Definition: ilist.h:543
static void dlist_push_tail(dlist_head *head, dlist_node *node)
Definition: ilist.h:317
#define dlist_container(type, membername, ptr)
Definition: ilist.h:496
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext TopTransactionContext
Definition: mcxt.c:53
void pfree(void *pointer)
Definition: mcxt.c:1175
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
void * palloc(Size size)
Definition: mcxt.c:1068
void pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat.c:705
const PgStat_KindInfo * pgstat_get_kind_info(PgStat_Kind kind)
Definition: pgstat.c:1211
void pgstat_clear_snapshot(void)
Definition: pgstat.c:752
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:608
PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, Oid objoid, bool create, bool *created_entry)
Definition: pgstat_shmem.c:393
bool pgstat_drop_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_shmem.c:838
static PgStat_SubXactStatus * pgStatXactStack
Definition: pgstat_xact.c:34
void AtPrepare_PgStat(void)
Definition: pgstat_xact.c:196
void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
Definition: pgstat_xact.c:320
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:140
void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:366
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
Definition: pgstat_xact.c:388
struct PgStat_PendingDroppedStatsItem PgStat_PendingDroppedStatsItem
void PostPrepare_PgStat(void)
Definition: pgstat_xact.c:216
int pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
Definition: pgstat_xact.c:278
void AtEOSubXact_PgStat(bool isCommit, int nestDepth)
Definition: pgstat_xact.c:117
PgStat_SubXactStatus * pgstat_get_xact_stack_level(int nest_level)
Definition: pgstat_xact.c:243
static void create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
Definition: pgstat_xact.c:340
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:161
dlist_node * cur
Definition: ilist.h:180
int GetCurrentTransactionNestLevel(void)
Definition: xact.c:910