LCOV - code coverage report
Current view: top level - src/backend/utils/activity - pgstat_xact.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16devel Lines: 121 126 96.0 %
Date: 2022-08-17 03:10:30 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      22             : typedef struct PgStat_PendingDroppedStatsItem
      23             : {
      24             :     xl_xact_stats_item item;
      25             :     bool        is_create;
      26             :     dlist_node  node;
      27             : } PgStat_PendingDroppedStatsItem;
      28             : 
      29             : 
      30             : static void AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit);
      31             : static void AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
      32             :                                             bool isCommit, int nestDepth);
      33             : 
      34             : static PgStat_SubXactStatus *pgStatXactStack = NULL;
      35             : 
      36             : 
      37             : /*
      38             :  * Called from access/transam/xact.c at top-level transaction commit/abort.
      39             :  */
      40             : void
      41      905828 : AtEOXact_PgStat(bool isCommit, bool parallel)
      42             : {
      43             :     PgStat_SubXactStatus *xact_state;
      44             : 
      45      905828 :     AtEOXact_PgStat_Database(isCommit, parallel);
      46             : 
      47             :     /* handle transactional stats information */
      48      905828 :     xact_state = pgStatXactStack;
      49      905828 :     if (xact_state != NULL)
      50             :     {
      51             :         Assert(xact_state->nest_level == 1);
      52             :         Assert(xact_state->prev == NULL);
      53             : 
      54      540814 :         AtEOXact_PgStat_Relations(xact_state, isCommit);
      55      540814 :         AtEOXact_PgStat_DroppedStats(xact_state, isCommit);
      56             :     }
      57      905828 :     pgStatXactStack = NULL;
      58             : 
      59             :     /* Make sure any stats snapshot is thrown away */
      60      905828 :     pgstat_clear_snapshot();
      61      905828 : }
      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
      68      540814 : AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
      69             : {
      70             :     dlist_mutable_iter iter;
      71      540814 :     int         not_freed_count = 0;
      72             : 
      73      540814 :     if (xact_state->pending_drops_count == 0)
      74             :     {
      75             :         Assert(dlist_is_empty(&xact_state->pending_drops));
      76      400068 :         return;
      77             :     }
      78             : 
      79      387186 :     dlist_foreach_modify(iter, &xact_state->pending_drops)
      80             :     {
      81      246440 :         PgStat_PendingDroppedStatsItem *pending =
      82      246440 :         dlist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
      83      246440 :         xl_xact_stats_item *it = &pending->item;
      84             : 
      85      246440 :         if (isCommit && !pending->is_create)
      86             :         {
      87             :             /*
      88             :              * Transaction that dropped an object committed. Drop the stats
      89             :              * too.
      90             :              */
      91       41316 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
      92        5406 :                 not_freed_count++;
      93             :         }
      94      205124 :         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        2562 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
     101           0 :                 not_freed_count++;
     102             :         }
     103             : 
     104      246440 :         dlist_delete(&pending->node);
     105      246440 :         xact_state->pending_drops_count--;
     106      246440 :         pfree(pending);
     107             :     }
     108             : 
     109      140746 :     if (not_freed_count > 0)
     110        3220 :         pgstat_request_entry_refs_gc();
     111             : }
     112             : 
     113             : /*
     114             :  * Called from access/transam/xact.c at subtransaction commit/abort.
     115             :  */
     116             : void
     117       21878 : 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       21878 :     xact_state = pgStatXactStack;
     123       21878 :     if (xact_state != NULL &&
     124        6534 :         xact_state->nest_level >= nestDepth)
     125             :     {
     126             :         /* delink xact_state from stack immediately to simplify reuse case */
     127        5752 :         pgStatXactStack = xact_state->prev;
     128             : 
     129        5752 :         AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
     130        5752 :         AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
     131             : 
     132        5752 :         pfree(xact_state);
     133             :     }
     134       21878 : }
     135             : 
     136             : /*
     137             :  * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
     138             :  */
     139             : static void
     140        5752 : AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
     141             :                                 bool isCommit, int nestDepth)
     142             : {
     143             :     PgStat_SubXactStatus *parent_xact_state;
     144             :     dlist_mutable_iter iter;
     145        5752 :     int         not_freed_count = 0;
     146             : 
     147        5752 :     if (xact_state->pending_drops_count == 0)
     148        5614 :         return;
     149             : 
     150         138 :     parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
     151             : 
     152         348 :     dlist_foreach_modify(iter, &xact_state->pending_drops)
     153             :     {
     154         210 :         PgStat_PendingDroppedStatsItem *pending =
     155         210 :         dlist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
     156         210 :         xl_xact_stats_item *it = &pending->item;
     157             : 
     158         210 :         dlist_delete(&pending->node);
     159         210 :         xact_state->pending_drops_count--;
     160             : 
     161         210 :         if (!isCommit && pending->is_create)
     162             :         {
     163             :             /*
     164             :              * Subtransaction creating a new stats object aborted. Drop the
     165             :              * stats object.
     166             :              */
     167          92 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
     168           0 :                 not_freed_count++;
     169          92 :             pfree(pending);
     170             :         }
     171         118 :         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          78 :             dlist_push_tail(&parent_xact_state->pending_drops, &pending->node);
     179          78 :             parent_xact_state->pending_drops_count++;
     180             :         }
     181             :         else
     182             :         {
     183          40 :             pfree(pending);
     184             :         }
     185             :     }
     186             : 
     187             :     Assert(xact_state->pending_drops_count == 0);
     188         138 :     if (not_freed_count > 0)
     189           0 :         pgstat_request_entry_refs_gc();
     190             : }
     191             : 
     192             : /*
     193             :  * Save the transactional stats state at 2PC transaction prepare.
     194             :  */
     195             : void
     196         716 : AtPrepare_PgStat(void)
     197             : {
     198             :     PgStat_SubXactStatus *xact_state;
     199             : 
     200         716 :     xact_state = pgStatXactStack;
     201         716 :     if (xact_state != NULL)
     202             :     {
     203             :         Assert(xact_state->nest_level == 1);
     204             :         Assert(xact_state->prev == NULL);
     205             : 
     206         708 :         AtPrepare_PgStat_Relations(xact_state);
     207             :     }
     208         716 : }
     209             : 
     210             : /*
     211             :  * Clean up after successful PREPARE.
     212             :  *
     213             :  * Note: AtEOXact_PgStat is not called during PREPARE.
     214             :  */
     215             : void
     216         716 : PostPrepare_PgStat(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         716 :     xact_state = pgStatXactStack;
     225         716 :     if (xact_state != NULL)
     226             :     {
     227             :         Assert(xact_state->nest_level == 1);
     228             :         Assert(xact_state->prev == NULL);
     229             : 
     230         708 :         PostPrepare_PgStat_Relations(xact_state);
     231             :     }
     232         716 :     pgStatXactStack = NULL;
     233             : 
     234             :     /* Make sure any stats snapshot is thrown away */
     235         716 :     pgstat_clear_snapshot();
     236         716 : }
     237             : 
     238             : /*
     239             :  * Ensure (sub)transaction stack entry for the given nest_level exists, adding
     240             :  * it if needed.
     241             :  */
     242             : PgStat_SubXactStatus *
     243     1561676 : pgstat_get_xact_stack_level(int nest_level)
     244             : {
     245             :     PgStat_SubXactStatus *xact_state;
     246             : 
     247     1561676 :     xact_state = pgStatXactStack;
     248     1561676 :     if (xact_state == NULL || xact_state->nest_level != nest_level)
     249             :     {
     250             :         xact_state = (PgStat_SubXactStatus *)
     251      547274 :             MemoryContextAlloc(TopTransactionContext,
     252             :                                sizeof(PgStat_SubXactStatus));
     253      547274 :         dlist_init(&xact_state->pending_drops);
     254      547274 :         xact_state->pending_drops_count = 0;
     255      547274 :         xact_state->nest_level = nest_level;
     256      547274 :         xact_state->prev = pgStatXactStack;
     257      547274 :         xact_state->first = NULL;
     258      547274 :         pgStatXactStack = xact_state;
     259             :     }
     260     1561676 :     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
     278      875290 : pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
     279             : {
     280      875290 :     PgStat_SubXactStatus *xact_state = pgStatXactStack;
     281      875290 :     int         nitems = 0;
     282             :     dlist_iter  iter;
     283             : 
     284      875290 :     if (xact_state == NULL)
     285      331900 :         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      543390 :     *items = palloc(xact_state->pending_drops_count
     295             :                     * sizeof(xl_xact_stats_item));
     296             : 
     297      790756 :     dlist_foreach(iter, &xact_state->pending_drops)
     298             :     {
     299      247366 :         PgStat_PendingDroppedStatsItem *pending =
     300      247366 :         dlist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
     301             : 
     302      247366 :         if (isCommit && pending->is_create)
     303      202022 :             continue;
     304       45344 :         if (!isCommit && !pending->is_create)
     305         650 :             continue;
     306             : 
     307             :         Assert(nitems < xact_state->pending_drops_count);
     308       44694 :         (*items)[nitems++] = pending->item;
     309             :     }
     310             : 
     311      543390 :     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        5156 : pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
     321             : {
     322        5156 :     int         not_freed_count = 0;
     323             : 
     324        5156 :     if (ndrops == 0)
     325         704 :         return;
     326             : 
     327       14542 :     for (int i = 0; i < ndrops; i++)
     328             :     {
     329       10090 :         xl_xact_stats_item *it = &items[i];
     330             : 
     331       10090 :         if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
     332           4 :             not_freed_count++;
     333             :     }
     334             : 
     335        4452 :     if (not_freed_count > 0)
     336           4 :         pgstat_request_entry_refs_gc();
     337             : }
     338             : 
     339             : static void
     340      246636 : create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
     341             : {
     342      246636 :     int         nest_level = GetCurrentTransactionNestLevel();
     343             :     PgStat_SubXactStatus *xact_state;
     344             :     PgStat_PendingDroppedStatsItem *drop = (PgStat_PendingDroppedStatsItem *)
     345      246636 :     MemoryContextAlloc(TopTransactionContext, sizeof(PgStat_PendingDroppedStatsItem));
     346             : 
     347      246636 :     xact_state = pgstat_get_xact_stack_level(nest_level);
     348             : 
     349      246636 :     drop->is_create = is_create;
     350      246636 :     drop->item.kind = kind;
     351      246636 :     drop->item.dboid = dboid;
     352      246636 :     drop->item.objoid = objoid;
     353             : 
     354      246636 :     dlist_push_tail(&xact_state->pending_drops, &drop->node);
     355      246636 :     xact_state->pending_drops_count++;
     356      246636 : }
     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
     366      204676 : pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
     367             : {
     368      204676 :     if (pgstat_get_entry_ref(kind, dboid, objoid, false, NULL))
     369             :     {
     370           0 :         ereport(WARNING,
     371             :                 errmsg("resetting existing stats for type %s, db=%u, oid=%u",
     372             :                        (pgstat_get_kind_info(kind))->name, dboid, objoid));
     373             : 
     374           0 :         pgstat_reset(kind, dboid, objoid);
     375             :     }
     376             : 
     377      204676 :     create_drop_transactional_internal(kind, dboid, objoid, /* create */ true);
     378      204676 : }
     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
     388       41960 : pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
     389             : {
     390       41960 :     create_drop_transactional_internal(kind, dboid, objoid, /* create */ false);
     391       41960 : }

Generated by: LCOV version 1.14