LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat_xact.c (source / functions) Coverage Total Hit LBC UIC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 96.2 % 131 126 2 3 2 65 16 43 3 72 9
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 12 12 10 1 1 10
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       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                 : 
      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 CBC      486200 : AtEOXact_PgStat(bool isCommit, bool parallel)
      42                 : {
      43                 :     PgStat_SubXactStatus *xact_state;
      44                 : 
      45          486200 :     AtEOXact_PgStat_Database(isCommit, parallel);
      46                 : 
      47                 :     /* handle transactional stats information */
      48          486200 :     xact_state = pgStatXactStack;
      49          486200 :     if (xact_state != NULL)
      50                 :     {
      51          293944 :         Assert(xact_state->nest_level == 1);
      52          293944 :         Assert(xact_state->prev == NULL);
      53                 : 
      54          293944 :         AtEOXact_PgStat_Relations(xact_state, isCommit);
      55          293944 :         AtEOXact_PgStat_DroppedStats(xact_state, isCommit);
      56                 :     }
      57          486200 :     pgStatXactStack = NULL;
      58                 : 
      59                 :     /* Make sure any stats snapshot is thrown away */
      60          486200 :     pgstat_clear_snapshot();
      61          486200 : }
      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          293944 : AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
      69                 : {
      70                 :     dlist_mutable_iter iter;
      71          293944 :     int         not_freed_count = 0;
      72                 : 
      73 GNC      293944 :     if (dclist_count(&xact_state->pending_drops) == 0)
      74 CBC      214415 :         return;
      75 ECB             : 
      76 GNC      287733 :     dclist_foreach_modify(iter, &xact_state->pending_drops)
      77 ECB             :     {
      78 GIC      208204 :         PgStat_PendingDroppedStatsItem *pending =
      79 GNC      208204 :         dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
      80 GIC      208204 :         xl_xact_stats_item *it = &pending->item;
      81                 : 
      82          208204 :         if (isCommit && !pending->is_create)
      83                 :         {
      84                 :             /*
      85 ECB             :              * Transaction that dropped an object committed. Drop the stats
      86                 :              * too.
      87                 :              */
      88 CBC       32137 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
      89 GIC        4575 :                 not_freed_count++;
      90                 :         }
      91          176067 :         else if (!isCommit && pending->is_create)
      92                 :         {
      93                 :             /*
      94 ECB             :              * Transaction that created an object aborted. Drop the stats
      95 EUB             :              * associated with the object.
      96                 :              */
      97 GIC        1683 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
      98 LBC           0 :                 not_freed_count++;
      99 ECB             :         }
     100                 : 
     101 GNC      208204 :         dclist_delete_from(&xact_state->pending_drops, &pending->node);
     102 CBC      208204 :         pfree(pending);
     103                 :     }
     104                 : 
     105 GIC       79529 :     if (not_freed_count > 0)
     106            1766 :         pgstat_request_entry_refs_gc();
     107                 : }
     108                 : 
     109 ECB             : /*
     110                 :  * Called from access/transam/xact.c at subtransaction commit/abort.
     111                 :  */
     112                 : void
     113 GIC        8797 : AtEOSubXact_PgStat(bool isCommit, int nestDepth)
     114 ECB             : {
     115                 :     PgStat_SubXactStatus *xact_state;
     116                 : 
     117                 :     /* merge the sub-transaction's transactional stats into the parent */
     118 GIC        8797 :     xact_state = pgStatXactStack;
     119 CBC        8797 :     if (xact_state != NULL &&
     120 GIC        3746 :         xact_state->nest_level >= nestDepth)
     121 ECB             :     {
     122                 :         /* delink xact_state from stack immediately to simplify reuse case */
     123 GIC        3336 :         pgStatXactStack = xact_state->prev;
     124 ECB             : 
     125 GIC        3336 :         AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
     126 CBC        3336 :         AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
     127                 : 
     128 GIC        3336 :         pfree(xact_state);
     129                 :     }
     130            8797 : }
     131                 : 
     132 ECB             : /*
     133                 :  * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
     134                 :  */
     135                 : static void
     136 GIC        3336 : AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
     137 ECB             :                                 bool isCommit, int nestDepth)
     138                 : {
     139                 :     PgStat_SubXactStatus *parent_xact_state;
     140                 :     dlist_mutable_iter iter;
     141 GIC        3336 :     int         not_freed_count = 0;
     142 ECB             : 
     143 GNC        3336 :     if (dclist_count(&xact_state->pending_drops) == 0)
     144 CBC        3267 :         return;
     145                 : 
     146              69 :     parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
     147 ECB             : 
     148 GNC         202 :     dclist_foreach_modify(iter, &xact_state->pending_drops)
     149                 :     {
     150 CBC         133 :         PgStat_PendingDroppedStatsItem *pending =
     151 GNC         133 :         dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
     152 CBC         133 :         xl_xact_stats_item *it = &pending->item;
     153                 : 
     154 GNC         133 :         dclist_delete_from(&xact_state->pending_drops, &pending->node);
     155                 : 
     156 GIC         133 :         if (!isCommit && pending->is_create)
     157 ECB             :         {
     158 EUB             :             /*
     159 ECB             :              * Subtransaction creating a new stats object aborted. Drop the
     160                 :              * stats object.
     161                 :              */
     162 GIC          63 :             if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
     163 UIC           0 :                 not_freed_count++;
     164 GIC          63 :             pfree(pending);
     165                 :         }
     166              70 :         else if (isCommit)
     167                 :         {
     168 ECB             :             /*
     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 GNC          49 :             dclist_push_tail(&parent_xact_state->pending_drops, &pending->node);
     174                 :         }
     175 ECB             :         else
     176                 :         {
     177 GBC          21 :             pfree(pending);
     178                 :         }
     179                 :     }
     180                 : 
     181 GNC          69 :     Assert(dclist_count(&xact_state->pending_drops) == 0);
     182 GIC          69 :     if (not_freed_count > 0)
     183 UIC           0 :         pgstat_request_entry_refs_gc();
     184 ECB             : }
     185                 : 
     186                 : /*
     187                 :  * Save the transactional stats state at 2PC transaction prepare.
     188                 :  */
     189                 : void
     190 GIC         363 : AtPrepare_PgStat(void)
     191 ECB             : {
     192                 :     PgStat_SubXactStatus *xact_state;
     193                 : 
     194 CBC         363 :     xact_state = pgStatXactStack;
     195 GIC         363 :     if (xact_state != NULL)
     196 ECB             :     {
     197 GIC         358 :         Assert(xact_state->nest_level == 1);
     198             358 :         Assert(xact_state->prev == NULL);
     199                 : 
     200             358 :         AtPrepare_PgStat_Relations(xact_state);
     201                 :     }
     202             363 : }
     203                 : 
     204 ECB             : /*
     205                 :  * Clean up after successful PREPARE.
     206                 :  *
     207                 :  * Note: AtEOXact_PgStat is not called during PREPARE.
     208                 :  */
     209                 : void
     210 GIC         363 : PostPrepare_PgStat(void)
     211                 : {
     212 ECB             :     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 CBC         363 :     xact_state = pgStatXactStack;
     219 GIC         363 :     if (xact_state != NULL)
     220 ECB             :     {
     221 GIC         358 :         Assert(xact_state->nest_level == 1);
     222             358 :         Assert(xact_state->prev == NULL);
     223 ECB             : 
     224 CBC         358 :         PostPrepare_PgStat_Relations(xact_state);
     225                 :     }
     226 GIC         363 :     pgStatXactStack = NULL;
     227                 : 
     228                 :     /* Make sure any stats snapshot is thrown away */
     229             363 :     pgstat_clear_snapshot();
     230             363 : }
     231 ECB             : 
     232                 : /*
     233                 :  * Ensure (sub)transaction stack entry for the given nest_level exists, adding
     234                 :  * it if needed.
     235                 :  */
     236                 : PgStat_SubXactStatus *
     237 GIC      922450 : pgstat_get_xact_stack_level(int nest_level)
     238                 : {
     239 ECB             :     PgStat_SubXactStatus *xact_state;
     240                 : 
     241 CBC      922450 :     xact_state = pgStatXactStack;
     242          922450 :     if (xact_state == NULL || xact_state->nest_level != nest_level)
     243 ECB             :     {
     244                 :         xact_state = (PgStat_SubXactStatus *)
     245 CBC      297638 :             MemoryContextAlloc(TopTransactionContext,
     246                 :                                sizeof(PgStat_SubXactStatus));
     247 GNC      297638 :         dclist_init(&xact_state->pending_drops);
     248 GIC      297638 :         xact_state->nest_level = nest_level;
     249          297638 :         xact_state->prev = pgStatXactStack;
     250          297638 :         xact_state->first = NULL;
     251          297638 :         pgStatXactStack = xact_state;
     252                 :     }
     253          922450 :     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 ECB             :  * 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
     271 CBC      469921 : pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
     272                 : {
     273 GIC      469921 :     PgStat_SubXactStatus *xact_state = pgStatXactStack;
     274          469921 :     int         nitems = 0;
     275                 :     dlist_iter  iter;
     276                 : 
     277 CBC      469921 :     if (xact_state == NULL)
     278          174657 :         return 0;
     279                 : 
     280 ECB             :     /*
     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 GIC      295264 :     Assert(!isCommit || xact_state->nest_level == 1);
     285 CBC      295264 :     Assert(!isCommit || xact_state->prev == NULL);
     286 ECB             : 
     287 GNC      295264 :     *items = palloc(dclist_count(&xact_state->pending_drops)
     288 ECB             :                     * sizeof(xl_xact_stats_item));
     289                 : 
     290 GNC      504103 :     dclist_foreach(iter, &xact_state->pending_drops)
     291 ECB             :     {
     292 GIC      208839 :         PgStat_PendingDroppedStatsItem *pending =
     293 GNC      208839 :         dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
     294 ECB             : 
     295 GIC      208839 :         if (isCommit && pending->is_create)
     296          174015 :             continue;
     297 CBC       34824 :         if (!isCommit && !pending->is_create)
     298 GIC         436 :             continue;
     299                 : 
     300 GNC       34388 :         Assert(nitems < dclist_count(&xact_state->pending_drops));
     301 GIC       34388 :         (*items)[nitems++] = pending->item;
     302                 :     }
     303                 : 
     304          295264 :     return nitems;
     305                 : }
     306 ECB             : 
     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 CBC        2852 : pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
     314                 : {
     315            2852 :     int         not_freed_count = 0;
     316                 : 
     317            2852 :     if (ndrops == 0)
     318             358 :         return;
     319                 : 
     320 GIC       10148 :     for (int i = 0; i < ndrops; i++)
     321 ECB             :     {
     322 CBC        7654 :         xl_xact_stats_item *it = &items[i];
     323                 : 
     324 GIC        7654 :         if (!pgstat_drop_entry(it->kind, it->dboid, it->objoid))
     325               2 :             not_freed_count++;
     326 ECB             :     }
     327                 : 
     328 CBC        2494 :     if (not_freed_count > 0)
     329 GIC           2 :         pgstat_request_entry_refs_gc();
     330                 : }
     331 ECB             : 
     332                 : static void
     333 CBC      208331 : create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, Oid objoid, bool is_create)
     334                 : {
     335          208331 :     int         nest_level = GetCurrentTransactionNestLevel();
     336 ECB             :     PgStat_SubXactStatus *xact_state;
     337                 :     PgStat_PendingDroppedStatsItem *drop = (PgStat_PendingDroppedStatsItem *)
     338 CBC      208331 :     MemoryContextAlloc(TopTransactionContext, sizeof(PgStat_PendingDroppedStatsItem));
     339                 : 
     340          208331 :     xact_state = pgstat_get_xact_stack_level(nest_level);
     341 ECB             : 
     342 GIC      208331 :     drop->is_create = is_create;
     343          208331 :     drop->item.kind = kind;
     344          208331 :     drop->item.dboid = dboid;
     345          208331 :     drop->item.objoid = objoid;
     346                 : 
     347 GNC      208331 :     dclist_push_tail(&xact_state->pending_drops, &drop->node);
     348 GIC      208331 : }
     349                 : 
     350 ECB             : /*
     351                 :  * Create a stats entry for a newly created database object in a transactional
     352                 :  * manner.
     353                 :  *
     354 EUB             :  * I.e. if the current (sub-)transaction aborts, the stats entry will also be
     355                 :  * dropped.
     356                 :  */
     357                 : void
     358 GBC      175761 : pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
     359                 : {
     360 GIC      175761 :     if (pgstat_get_entry_ref(kind, dboid, objoid, false, NULL))
     361 ECB             :     {
     362 LBC           0 :         ereport(WARNING,
     363                 :                 errmsg("resetting existing statistics for kind %s, db=%u, oid=%u",
     364                 :                        (pgstat_get_kind_info(kind))->name, dboid, objoid));
     365                 : 
     366 UIC           0 :         pgstat_reset(kind, dboid, objoid);
     367                 :     }
     368                 : 
     369 GIC      175761 :     create_drop_transactional_internal(kind, dboid, objoid, /* create */ true);
     370          175761 : }
     371                 : 
     372 ECB             : /*
     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
     380 GIC       32570 : pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
     381                 : {
     382           32570 :     create_drop_transactional_internal(kind, dboid, objoid, /* create */ false);
     383           32570 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a