LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat_xact.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 96.3 % 135 130 5 130
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 12 12 12
Baseline: lcov-20250906-005545-baseline Branches: 81.0 % 100 81 19 81
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 93.8 % 16 15 1 15
(360..) days: 96.6 % 119 115 4 115
Function coverage date bins:
(30,360] days: 100.0 % 3 3 3
(360..) days: 100.0 % 9 9 9
Branch coverage date bins:
(30,360] days: 70.0 % 10 7 3 7
(360..) days: 82.2 % 90 74 16 74

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /* -------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * pgstat_xact.c
                                  4                 :                :  *    Transactional integration for the cumulative statistics system.
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2001-2025, 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/xact.h"
                                 16                 :                : #include "pgstat.h"
                                 17                 :                : #include "utils/memutils.h"
                                 18                 :                : #include "utils/pgstat_internal.h"
                                 19                 :                : 
                                 20                 :                : 
                                 21                 :                : typedef struct PgStat_PendingDroppedStatsItem
                                 22                 :                : {
                                 23                 :                :     xl_xact_stats_item item;
                                 24                 :                :     bool        is_create;
                                 25                 :                :     dlist_node  node;
                                 26                 :                : } PgStat_PendingDroppedStatsItem;
                                 27                 :                : 
                                 28                 :                : 
                                 29                 :                : static void AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit);
                                 30                 :                : static void AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
                                 31                 :                :                                             bool isCommit, int nestDepth);
                                 32                 :                : 
                                 33                 :                : static PgStat_SubXactStatus *pgStatXactStack = NULL;
                                 34                 :                : 
                                 35                 :                : 
                                 36                 :                : /*
                                 37                 :                :  * Called from access/transam/xact.c at top-level transaction commit/abort.
                                 38                 :                :  */
                                 39                 :                : void
 1249 andres@anarazel.de         40                 :CBC      318635 : AtEOXact_PgStat(bool isCommit, bool parallel)
                                 41                 :                : {
                                 42                 :                :     PgStat_SubXactStatus *xact_state;
                                 43                 :                : 
                                 44                 :         318635 :     AtEOXact_PgStat_Database(isCommit, parallel);
                                 45                 :                : 
                                 46                 :                :     /* handle transactional stats information */
                                 47                 :         318635 :     xact_state = pgStatXactStack;
                                 48         [ +  + ]:         318635 :     if (xact_state != NULL)
                                 49                 :                :     {
                                 50         [ -  + ]:         124608 :         Assert(xact_state->nest_level == 1);
                                 51         [ -  + ]:         124608 :         Assert(xact_state->prev == NULL);
                                 52                 :                : 
                                 53                 :         124608 :         AtEOXact_PgStat_Relations(xact_state, isCommit);
                                 54                 :         124608 :         AtEOXact_PgStat_DroppedStats(xact_state, isCommit);
                                 55                 :                :     }
                                 56                 :         318635 :     pgStatXactStack = NULL;
                                 57                 :                : 
                                 58                 :                :     /* Make sure any stats snapshot is thrown away */
                                 59                 :         318635 :     pgstat_clear_snapshot();
                                 60                 :         318635 : }
                                 61                 :                : 
                                 62                 :                : /*
                                 63                 :                :  * When committing, drop stats for objects dropped in the transaction. When
                                 64                 :                :  * aborting, drop stats for objects created in the transaction.
                                 65                 :                :  */
                                 66                 :                : static void
                                 67                 :         124608 : AtEOXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state, bool isCommit)
                                 68                 :                : {
                                 69                 :                :     dlist_mutable_iter iter;
                                 70                 :         124608 :     int         not_freed_count = 0;
                                 71                 :                : 
 1039 drowley@postgresql.o       72         [ +  + ]:         124608 :     if (dclist_count(&xact_state->pending_drops) == 0)
 1249 andres@anarazel.de         73                 :          81756 :         return;
                                 74                 :                : 
 1039 drowley@postgresql.o       75   [ +  -  +  + ]:         155125 :     dclist_foreach_modify(iter, &xact_state->pending_drops)
                                 76                 :                :     {
 1249 andres@anarazel.de         77                 :         112273 :         PgStat_PendingDroppedStatsItem *pending =
  841 tgl@sss.pgh.pa.us          78                 :         112273 :             dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
 1249 andres@anarazel.de         79                 :         112273 :         xl_xact_stats_item *it = &pending->item;
  353 michael@paquier.xyz        80                 :         112273 :         uint64      objid = ((uint64) it->objid_hi) << 32 | it->objid_lo;
                                 81                 :                : 
 1249 andres@anarazel.de         82   [ +  +  +  + ]:         112273 :         if (isCommit && !pending->is_create)
                                 83                 :                :         {
                                 84                 :                :             /*
                                 85                 :                :              * Transaction that dropped an object committed. Drop the stats
                                 86                 :                :              * too.
                                 87                 :                :              */
  353 michael@paquier.xyz        88         [ +  + ]:          42277 :             if (!pgstat_drop_entry(it->kind, it->dboid, objid))
 1249 andres@anarazel.de         89                 :           4720 :                 not_freed_count++;
                                 90                 :                :         }
                                 91   [ +  +  +  + ]:          74716 :         else if (!isCommit && pending->is_create)
                                 92                 :                :         {
                                 93                 :                :             /*
                                 94                 :                :              * Transaction that created an object aborted. Drop the stats
                                 95                 :                :              * associated with the object.
                                 96                 :                :              */
  353 michael@paquier.xyz        97         [ -  + ]:           2384 :             if (!pgstat_drop_entry(it->kind, it->dboid, objid))
 1249 andres@anarazel.de         98                 :UBC           0 :                 not_freed_count++;
                                 99                 :                :         }
                                100                 :                : 
 1039 drowley@postgresql.o      101                 :CBC      112273 :         dclist_delete_from(&xact_state->pending_drops, &pending->node);
 1249 andres@anarazel.de        102                 :         112273 :         pfree(pending);
                                103                 :                :     }
                                104                 :                : 
                                105         [ +  + ]:          42852 :     if (not_freed_count > 0)
                                106                 :           1827 :         pgstat_request_entry_refs_gc();
                                107                 :                : }
                                108                 :                : 
                                109                 :                : /*
                                110                 :                :  * Called from access/transam/xact.c at subtransaction commit/abort.
                                111                 :                :  */
                                112                 :                : void
                                113                 :           9090 : 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                 :           9090 :     xact_state = pgStatXactStack;
                                119         [ +  + ]:           9090 :     if (xact_state != NULL &&
                                120         [ +  + ]:           3760 :         xact_state->nest_level >= nestDepth)
                                121                 :                :     {
                                122                 :                :         /* delink xact_state from stack immediately to simplify reuse case */
                                123                 :           3293 :         pgStatXactStack = xact_state->prev;
                                124                 :                : 
                                125                 :           3293 :         AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth);
                                126                 :           3293 :         AtEOSubXact_PgStat_DroppedStats(xact_state, isCommit, nestDepth);
                                127                 :                : 
                                128                 :           3293 :         pfree(xact_state);
                                129                 :                :     }
                                130                 :           9090 : }
                                131                 :                : 
                                132                 :                : /*
                                133                 :                :  * Like AtEOXact_PgStat_DroppedStats(), but for subtransactions.
                                134                 :                :  */
                                135                 :                : static void
                                136                 :           3293 : AtEOSubXact_PgStat_DroppedStats(PgStat_SubXactStatus *xact_state,
                                137                 :                :                                 bool isCommit, int nestDepth)
                                138                 :                : {
                                139                 :                :     PgStat_SubXactStatus *parent_xact_state;
                                140                 :                :     dlist_mutable_iter iter;
                                141                 :           3293 :     int         not_freed_count = 0;
                                142                 :                : 
 1039 drowley@postgresql.o      143         [ +  + ]:           3293 :     if (dclist_count(&xact_state->pending_drops) == 0)
 1249 andres@anarazel.de        144                 :           3221 :         return;
                                145                 :                : 
                                146                 :             72 :     parent_xact_state = pgstat_get_xact_stack_level(nestDepth - 1);
                                147                 :                : 
 1039 drowley@postgresql.o      148   [ +  -  +  + ]:            211 :     dclist_foreach_modify(iter, &xact_state->pending_drops)
                                149                 :                :     {
 1249 andres@anarazel.de        150                 :            139 :         PgStat_PendingDroppedStatsItem *pending =
  841 tgl@sss.pgh.pa.us         151                 :            139 :             dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
 1249 andres@anarazel.de        152                 :            139 :         xl_xact_stats_item *it = &pending->item;
  353 michael@paquier.xyz       153                 :            139 :         uint64      objid = ((uint64) it->objid_hi) << 32 | it->objid_lo;
                                154                 :                : 
 1039 drowley@postgresql.o      155                 :            139 :         dclist_delete_from(&xact_state->pending_drops, &pending->node);
                                156                 :                : 
 1249 andres@anarazel.de        157   [ +  +  +  + ]:            139 :         if (!isCommit && pending->is_create)
                                158                 :                :         {
                                159                 :                :             /*
                                160                 :                :              * Subtransaction creating a new stats object aborted. Drop the
                                161                 :                :              * stats object.
                                162                 :                :              */
  353 michael@paquier.xyz       163         [ -  + ]:             69 :             if (!pgstat_drop_entry(it->kind, it->dboid, objid))
 1249 andres@anarazel.de        164                 :UBC           0 :                 not_freed_count++;
 1249 andres@anarazel.de        165                 :CBC          69 :             pfree(pending);
                                166                 :                :         }
                                167         [ +  + ]:             70 :         else if (isCommit)
                                168                 :                :         {
                                169                 :                :             /*
                                170                 :                :              * Subtransaction dropping a stats object committed. Can't yet
                                171                 :                :              * remove the stats object, the surrounding transaction might
                                172                 :                :              * still abort. Pass it on to the parent.
                                173                 :                :              */
 1039 drowley@postgresql.o      174                 :             49 :             dclist_push_tail(&parent_xact_state->pending_drops, &pending->node);
                                175                 :                :         }
                                176                 :                :         else
                                177                 :                :         {
 1249 andres@anarazel.de        178                 :             21 :             pfree(pending);
                                179                 :                :         }
                                180                 :                :     }
                                181                 :                : 
 1039 drowley@postgresql.o      182         [ -  + ]:             72 :     Assert(dclist_count(&xact_state->pending_drops) == 0);
 1249 andres@anarazel.de        183         [ -  + ]:             72 :     if (not_freed_count > 0)
 1249 andres@anarazel.de        184                 :UBC           0 :         pgstat_request_entry_refs_gc();
                                185                 :                : }
                                186                 :                : 
                                187                 :                : /*
                                188                 :                :  * Save the transactional stats state at 2PC transaction prepare.
                                189                 :                :  */
                                190                 :                : void
 1249 andres@anarazel.de        191                 :CBC         288 : AtPrepare_PgStat(void)
                                192                 :                : {
                                193                 :                :     PgStat_SubXactStatus *xact_state;
                                194                 :                : 
                                195                 :            288 :     xact_state = pgStatXactStack;
                                196         [ +  + ]:            288 :     if (xact_state != NULL)
                                197                 :                :     {
                                198         [ -  + ]:            281 :         Assert(xact_state->nest_level == 1);
                                199         [ -  + ]:            281 :         Assert(xact_state->prev == NULL);
                                200                 :                : 
                                201                 :            281 :         AtPrepare_PgStat_Relations(xact_state);
                                202                 :                :     }
                                203                 :            288 : }
                                204                 :                : 
                                205                 :                : /*
                                206                 :                :  * Clean up after successful PREPARE.
                                207                 :                :  *
                                208                 :                :  * Note: AtEOXact_PgStat is not called during PREPARE.
                                209                 :                :  */
                                210                 :                : void
                                211                 :            288 : PostPrepare_PgStat(void)
                                212                 :                : {
                                213                 :                :     PgStat_SubXactStatus *xact_state;
                                214                 :                : 
                                215                 :                :     /*
                                216                 :                :      * We don't bother to free any of the transactional state, since it's all
                                217                 :                :      * in TopTransactionContext and will go away anyway.
                                218                 :                :      */
                                219                 :            288 :     xact_state = pgStatXactStack;
                                220         [ +  + ]:            288 :     if (xact_state != NULL)
                                221                 :                :     {
                                222         [ -  + ]:            281 :         Assert(xact_state->nest_level == 1);
                                223         [ -  + ]:            281 :         Assert(xact_state->prev == NULL);
                                224                 :                : 
                                225                 :            281 :         PostPrepare_PgStat_Relations(xact_state);
                                226                 :                :     }
                                227                 :            288 :     pgStatXactStack = NULL;
                                228                 :                : 
                                229                 :                :     /* Make sure any stats snapshot is thrown away */
                                230                 :            288 :     pgstat_clear_snapshot();
                                231                 :            288 : }
                                232                 :                : 
                                233                 :                : /*
                                234                 :                :  * Ensure (sub)transaction stack entry for the given nest_level exists, adding
                                235                 :                :  * it if needed.
                                236                 :                :  */
                                237                 :                : PgStat_SubXactStatus *
                                238                 :         456554 : pgstat_get_xact_stack_level(int nest_level)
                                239                 :                : {
                                240                 :                :     PgStat_SubXactStatus *xact_state;
                                241                 :                : 
                                242                 :         456554 :     xact_state = pgStatXactStack;
                                243   [ +  +  +  + ]:         456554 :     if (xact_state == NULL || xact_state->nest_level != nest_level)
                                244                 :                :     {
                                245                 :                :         xact_state = (PgStat_SubXactStatus *)
                                246                 :         128182 :             MemoryContextAlloc(TopTransactionContext,
                                247                 :                :                                sizeof(PgStat_SubXactStatus));
 1039 drowley@postgresql.o      248                 :         128182 :         dclist_init(&xact_state->pending_drops);
 1249 andres@anarazel.de        249                 :         128182 :         xact_state->nest_level = nest_level;
                                250                 :         128182 :         xact_state->prev = pgStatXactStack;
                                251                 :         128182 :         xact_state->first = NULL;
                                252                 :         128182 :         pgStatXactStack = xact_state;
                                253                 :                :     }
                                254                 :         456554 :     return xact_state;
                                255                 :                : }
                                256                 :                : 
                                257                 :                : /*
                                258                 :                :  * Get stat items that need to be dropped at commit / abort.
                                259                 :                :  *
                                260                 :                :  * When committing, stats for objects that have been dropped in the
                                261                 :                :  * transaction are returned. When aborting, stats for newly created objects are
                                262                 :                :  * returned.
                                263                 :                :  *
                                264                 :                :  * Used by COMMIT / ABORT and 2PC PREPARE processing when building their
                                265                 :                :  * respective WAL records, to ensure stats are dropped in case of a crash / on
                                266                 :                :  * standbys.
                                267                 :                :  *
                                268                 :                :  * The list of items is allocated in CurrentMemoryContext and must be freed by
                                269                 :                :  * the caller (directly or via memory context reset).
                                270                 :                :  */
                                271                 :                : int
                                272                 :         298498 : pgstat_get_transactional_drops(bool isCommit, xl_xact_stats_item **items)
                                273                 :                : {
                                274                 :         298498 :     PgStat_SubXactStatus *xact_state = pgStatXactStack;
                                275                 :         298498 :     int         nitems = 0;
                                276                 :                :     dlist_iter  iter;
                                277                 :                : 
                                278         [ +  + ]:         298498 :     if (xact_state == NULL)
                                279                 :         172687 :         return 0;
                                280                 :                : 
                                281                 :                :     /*
                                282                 :                :      * We expect to be called for subtransaction abort (which logs a WAL
                                283                 :                :      * record), but not for subtransaction commit (which doesn't).
                                284                 :                :      */
                                285   [ +  +  -  + ]:         125811 :     Assert(!isCommit || xact_state->nest_level == 1);
                                286   [ +  +  -  + ]:         125811 :     Assert(!isCommit || xact_state->prev == NULL);
                                287                 :                : 
 1039 drowley@postgresql.o      288                 :         125811 :     *items = palloc(dclist_count(&xact_state->pending_drops)
                                289                 :                :                     * sizeof(xl_xact_stats_item));
                                290                 :                : 
                                291   [ +  -  +  + ]:         238895 :     dclist_foreach(iter, &xact_state->pending_drops)
                                292                 :                :     {
 1249 andres@anarazel.de        293                 :         113084 :         PgStat_PendingDroppedStatsItem *pending =
  841 tgl@sss.pgh.pa.us         294                 :         113084 :             dclist_container(PgStat_PendingDroppedStatsItem, node, iter.cur);
                                295                 :                : 
 1249 andres@anarazel.de        296   [ +  +  +  + ]:         113084 :         if (isCommit && pending->is_create)
                                297                 :          71900 :             continue;
                                298   [ +  +  +  + ]:          41184 :         if (!isCommit && !pending->is_create)
                                299                 :            494 :             continue;
                                300                 :                : 
 1039 drowley@postgresql.o      301         [ -  + ]:          40690 :         Assert(nitems < dclist_count(&xact_state->pending_drops));
 1249 andres@anarazel.de        302                 :          40690 :         (*items)[nitems++] = pending->item;
                                303                 :                :     }
                                304                 :                : 
                                305                 :         125811 :     return nitems;
                                306                 :                : }
                                307                 :                : 
                                308                 :                : /*
                                309                 :                :  * Execute scheduled drops post-commit. Called from xact_redo_commit() /
                                310                 :                :  * xact_redo_abort() during recovery, and from FinishPreparedTransaction()
                                311                 :                :  * during normal 2PC COMMIT/ABORT PREPARED processing.
                                312                 :                :  */
                                313                 :                : void
                                314                 :           3337 : pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo)
                                315                 :                : {
                                316                 :           3337 :     int         not_freed_count = 0;
                                317                 :                : 
                                318         [ +  + ]:           3337 :     if (ndrops == 0)
                                319                 :            288 :         return;
                                320                 :                : 
                                321         [ +  + ]:          12249 :     for (int i = 0; i < ndrops; i++)
                                322                 :                :     {
                                323                 :           9200 :         xl_xact_stats_item *it = &items[i];
  353 michael@paquier.xyz       324                 :           9200 :         uint64      objid = ((uint64) it->objid_hi) << 32 | it->objid_lo;
                                325                 :                : 
                                326         [ +  + ]:           9200 :         if (!pgstat_drop_entry(it->kind, it->dboid, objid))
 1249 andres@anarazel.de        327                 :              2 :             not_freed_count++;
                                328                 :                :     }
                                329                 :                : 
                                330         [ +  + ]:           3049 :     if (not_freed_count > 0)
                                331                 :              2 :         pgstat_request_entry_refs_gc();
                                332                 :                : }
                                333                 :                : 
                                334                 :                : static void
  353 michael@paquier.xyz       335                 :         112401 : create_drop_transactional_internal(PgStat_Kind kind, Oid dboid, uint64 objid, bool is_create)
                                336                 :                : {
 1249 andres@anarazel.de        337                 :         112401 :     int         nest_level = GetCurrentTransactionNestLevel();
                                338                 :                :     PgStat_SubXactStatus *xact_state;
                                339                 :                :     PgStat_PendingDroppedStatsItem *drop = (PgStat_PendingDroppedStatsItem *)
  841 tgl@sss.pgh.pa.us         340                 :         112401 :         MemoryContextAlloc(TopTransactionContext, sizeof(PgStat_PendingDroppedStatsItem));
                                341                 :                : 
 1249 andres@anarazel.de        342                 :         112401 :     xact_state = pgstat_get_xact_stack_level(nest_level);
                                343                 :                : 
                                344                 :         112401 :     drop->is_create = is_create;
                                345                 :         112401 :     drop->item.kind = kind;
                                346                 :         112401 :     drop->item.dboid = dboid;
  353 michael@paquier.xyz       347                 :         112401 :     drop->item.objid_lo = (uint32) objid;
                                348                 :         112401 :     drop->item.objid_hi = (uint32) (objid >> 32);
                                349                 :                : 
 1039 drowley@postgresql.o      350                 :         112401 :     dclist_push_tail(&xact_state->pending_drops, &drop->node);
 1249 andres@anarazel.de        351                 :         112401 : }
                                352                 :                : 
                                353                 :                : /*
                                354                 :                :  * Create a stats entry for a newly created database object in a transactional
                                355                 :                :  * manner.
                                356                 :                :  *
                                357                 :                :  * I.e. if the current (sub-)transaction aborts, the stats entry will also be
                                358                 :                :  * dropped.
                                359                 :                :  */
                                360                 :                : void
  353 michael@paquier.xyz       361                 :          74353 : pgstat_create_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
                                362                 :                : {
                                363         [ -  + ]:          74353 :     if (pgstat_get_entry_ref(kind, dboid, objid, false, NULL))
                                364                 :                :     {
 1249 andres@anarazel.de        365         [ #  # ]:UBC           0 :         ereport(WARNING,
                                366                 :                :                 errmsg("resetting existing statistics for kind %s, db=%u, oid=%" PRIu64,
                                367                 :                :                        (pgstat_get_kind_info(kind))->name, dboid,
                                368                 :                :                        objid));
                                369                 :                : 
  353 michael@paquier.xyz       370                 :              0 :         pgstat_reset(kind, dboid, objid);
                                371                 :                :     }
                                372                 :                : 
  353 michael@paquier.xyz       373                 :CBC       74353 :     create_drop_transactional_internal(kind, dboid, objid, /* create */ true);
 1249 andres@anarazel.de        374                 :          74353 : }
                                375                 :                : 
                                376                 :                : /*
                                377                 :                :  * Drop a stats entry for a just dropped database object in a transactional
                                378                 :                :  * manner.
                                379                 :                :  *
                                380                 :                :  * I.e. if the current (sub-)transaction aborts, the stats entry will stay
                                381                 :                :  * alive.
                                382                 :                :  */
                                383                 :                : void
  353 michael@paquier.xyz       384                 :          38048 : pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
                                385                 :                : {
                                386                 :          38048 :     create_drop_transactional_internal(kind, dboid, objid, /* create */ false);
 1249 andres@anarazel.de        387                 :          38048 : }
        

Generated by: LCOV version 2.4-beta