LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - backend_status.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.9 % 339 315 1 1 7 15 2 39 11 263 7 51
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 20 20 6 3 11 8
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 100.0 % 1 1 1
Legend: Lines: hit not hit (180,240] days: 90.9 % 11 10 1 10
(240..) days: 93.0 % 327 304 1 7 15 2 39 263 7 44
Function coverage date bins:
(180,240] days: 100.0 % 2 2 2
(240..) days: 72.0 % 25 18 6 1 11 7

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /* ----------
                                  2                 :  * backend_status.c
                                  3                 :  *    Backend status reporting infrastructure.
                                  4                 :  *
                                  5                 :  * Copyright (c) 2001-2023, PostgreSQL Global Development Group
                                  6                 :  *
                                  7                 :  *
                                  8                 :  * IDENTIFICATION
                                  9                 :  *    src/backend/utils/activity/backend_status.c
                                 10                 :  * ----------
                                 11                 :  */
                                 12                 : #include "postgres.h"
                                 13                 : 
                                 14                 : #include "access/xact.h"
                                 15                 : #include "libpq/libpq.h"
                                 16                 : #include "miscadmin.h"
                                 17                 : #include "pg_trace.h"
                                 18                 : #include "pgstat.h"
                                 19                 : #include "port/atomics.h"     /* for memory barriers */
                                 20                 : #include "storage/ipc.h"
                                 21                 : #include "storage/proc.h"     /* for MyProc */
                                 22                 : #include "storage/sinvaladt.h"
                                 23                 : #include "utils/ascii.h"
                                 24                 : #include "utils/backend_status.h"
                                 25                 : #include "utils/guc.h"            /* for application_name */
                                 26                 : #include "utils/memutils.h"
                                 27                 : 
                                 28                 : 
                                 29                 : /* ----------
                                 30                 :  * Total number of backends including auxiliary
                                 31                 :  *
                                 32                 :  * We reserve a slot for each possible BackendId, plus one for each
                                 33                 :  * possible auxiliary process type.  (This scheme assumes there is not
                                 34                 :  * more than one of any auxiliary process type at a time.) MaxBackends
                                 35                 :  * includes autovacuum workers and background workers as well.
                                 36                 :  * ----------
                                 37                 :  */
                                 38                 : #define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
                                 39                 : 
                                 40                 : 
                                 41                 : /* ----------
                                 42                 :  * GUC parameters
                                 43                 :  * ----------
                                 44                 :  */
                                 45                 : bool        pgstat_track_activities = false;
                                 46                 : int         pgstat_track_activity_query_size = 1024;
                                 47                 : 
                                 48                 : 
                                 49                 : /* exposed so that backend_progress.c can access it */
                                 50                 : PgBackendStatus *MyBEEntry = NULL;
                                 51                 : 
                                 52                 : 
                                 53                 : static PgBackendStatus *BackendStatusArray = NULL;
                                 54                 : static char *BackendAppnameBuffer = NULL;
                                 55                 : static char *BackendClientHostnameBuffer = NULL;
                                 56                 : static char *BackendActivityBuffer = NULL;
                                 57                 : static Size BackendActivityBufferSize = 0;
                                 58                 : #ifdef USE_SSL
                                 59                 : static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
                                 60                 : #endif
                                 61                 : #ifdef ENABLE_GSS
                                 62                 : static PgBackendGSSStatus *BackendGssStatusBuffer = NULL;
                                 63                 : #endif
                                 64                 : 
                                 65                 : 
                                 66                 : /* Status for backends including auxiliary */
                                 67                 : static LocalPgBackendStatus *localBackendStatusTable = NULL;
                                 68                 : 
                                 69                 : /* Total number of backends including auxiliary */
                                 70                 : static int  localNumBackends = 0;
                                 71                 : 
                                 72                 : static MemoryContext backendStatusSnapContext;
                                 73                 : 
                                 74                 : 
                                 75                 : static void pgstat_beshutdown_hook(int code, Datum arg);
                                 76                 : static void pgstat_read_current_status(void);
                                 77                 : static void pgstat_setup_backend_status_context(void);
                                 78                 : 
                                 79                 : 
                                 80                 : /*
                                 81                 :  * Report shared-memory space needed by CreateSharedBackendStatus.
                                 82                 :  */
                                 83                 : Size
  736 andres                     84 CBC        2738 : BackendStatusShmemSize(void)
                                 85                 : {
                                 86                 :     Size        size;
                                 87                 : 
                                 88                 :     /* BackendStatusArray: */
  362 rhaas                      89            2738 :     size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
                                 90                 :     /* BackendAppnameBuffer: */
  736 andres                     91            2738 :     size = add_size(size,
  362 rhaas                      92            2738 :                     mul_size(NAMEDATALEN, NumBackendStatSlots));
                                 93                 :     /* BackendClientHostnameBuffer: */
  736 andres                     94            2738 :     size = add_size(size,
  362 rhaas                      95            2738 :                     mul_size(NAMEDATALEN, NumBackendStatSlots));
                                 96                 :     /* BackendActivityBuffer: */
  736 andres                     97            2738 :     size = add_size(size,
  362 rhaas                      98            2738 :                     mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
                                 99                 : #ifdef USE_SSL
                                100                 :     /* BackendSslStatusBuffer: */
  736 andres                    101            2738 :     size = add_size(size,
  362 rhaas                     102            2738 :                     mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
                                103                 : #endif
                                104                 : #ifdef ENABLE_GSS
                                105                 :     /* BackendGssStatusBuffer: */
  736 andres                    106            2738 :     size = add_size(size,
  362 rhaas                     107            2738 :                     mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
                                108                 : #endif
  736 andres                    109            2738 :     return size;
                                110                 : }
                                111                 : 
                                112                 : /*
                                113                 :  * Initialize the shared status array and several string buffers
                                114                 :  * during postmaster startup.
                                115                 :  */
                                116                 : void
                                117            1826 : CreateSharedBackendStatus(void)
                                118                 : {
                                119                 :     Size        size;
                                120                 :     bool        found;
                                121                 :     int         i;
                                122                 :     char       *buffer;
                                123                 : 
                                124                 :     /* Create or attach to the shared array */
  362 rhaas                     125            1826 :     size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
  736 andres                    126            1826 :     BackendStatusArray = (PgBackendStatus *)
                                127            1826 :         ShmemInitStruct("Backend Status Array", size, &found);
                                128                 : 
                                129            1826 :     if (!found)
                                130                 :     {
                                131                 :         /*
                                132                 :          * We're the first - initialize.
                                133                 :          */
                                134            1826 :         MemSet(BackendStatusArray, 0, size);
                                135                 :     }
                                136                 : 
                                137                 :     /* Create or attach to the shared appname buffer */
  362 rhaas                     138            1826 :     size = mul_size(NAMEDATALEN, NumBackendStatSlots);
  736 andres                    139            1826 :     BackendAppnameBuffer = (char *)
                                140            1826 :         ShmemInitStruct("Backend Application Name Buffer", size, &found);
                                141                 : 
                                142            1826 :     if (!found)
                                143                 :     {
                                144            1826 :         MemSet(BackendAppnameBuffer, 0, size);
                                145                 : 
                                146                 :         /* Initialize st_appname pointers. */
                                147            1826 :         buffer = BackendAppnameBuffer;
  362 rhaas                     148          204159 :         for (i = 0; i < NumBackendStatSlots; i++)
                                149                 :         {
  736 andres                    150          202333 :             BackendStatusArray[i].st_appname = buffer;
                                151          202333 :             buffer += NAMEDATALEN;
                                152                 :         }
                                153                 :     }
                                154                 : 
                                155                 :     /* Create or attach to the shared client hostname buffer */
  362 rhaas                     156            1826 :     size = mul_size(NAMEDATALEN, NumBackendStatSlots);
  736 andres                    157            1826 :     BackendClientHostnameBuffer = (char *)
                                158            1826 :         ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
                                159                 : 
                                160            1826 :     if (!found)
                                161                 :     {
                                162            1826 :         MemSet(BackendClientHostnameBuffer, 0, size);
                                163                 : 
                                164                 :         /* Initialize st_clienthostname pointers. */
                                165            1826 :         buffer = BackendClientHostnameBuffer;
  362 rhaas                     166          204159 :         for (i = 0; i < NumBackendStatSlots; i++)
                                167                 :         {
  736 andres                    168          202333 :             BackendStatusArray[i].st_clienthostname = buffer;
                                169          202333 :             buffer += NAMEDATALEN;
                                170                 :         }
                                171                 :     }
                                172                 : 
                                173                 :     /* Create or attach to the shared activity buffer */
                                174            3652 :     BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
  362 rhaas                     175            1826 :                                          NumBackendStatSlots);
  736 andres                    176            1826 :     BackendActivityBuffer = (char *)
                                177            1826 :         ShmemInitStruct("Backend Activity Buffer",
                                178                 :                         BackendActivityBufferSize,
                                179                 :                         &found);
                                180                 : 
                                181            1826 :     if (!found)
                                182                 :     {
                                183            1826 :         MemSet(BackendActivityBuffer, 0, BackendActivityBufferSize);
                                184                 : 
                                185                 :         /* Initialize st_activity pointers. */
                                186            1826 :         buffer = BackendActivityBuffer;
  362 rhaas                     187          204159 :         for (i = 0; i < NumBackendStatSlots; i++)
                                188                 :         {
  736 andres                    189          202333 :             BackendStatusArray[i].st_activity_raw = buffer;
                                190          202333 :             buffer += pgstat_track_activity_query_size;
                                191                 :         }
                                192                 :     }
                                193                 : 
                                194                 : #ifdef USE_SSL
                                195                 :     /* Create or attach to the shared SSL status buffer */
  362 rhaas                     196            1826 :     size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
  736 andres                    197            1826 :     BackendSslStatusBuffer = (PgBackendSSLStatus *)
                                198            1826 :         ShmemInitStruct("Backend SSL Status Buffer", size, &found);
                                199                 : 
                                200            1826 :     if (!found)
                                201                 :     {
                                202                 :         PgBackendSSLStatus *ptr;
                                203                 : 
                                204            1826 :         MemSet(BackendSslStatusBuffer, 0, size);
                                205                 : 
                                206                 :         /* Initialize st_sslstatus pointers. */
                                207            1826 :         ptr = BackendSslStatusBuffer;
  362 rhaas                     208          204159 :         for (i = 0; i < NumBackendStatSlots; i++)
                                209                 :         {
  736 andres                    210          202333 :             BackendStatusArray[i].st_sslstatus = ptr;
                                211          202333 :             ptr++;
                                212                 :         }
                                213                 :     }
                                214                 : #endif
                                215                 : 
                                216                 : #ifdef ENABLE_GSS
                                217                 :     /* Create or attach to the shared GSSAPI status buffer */
  362 rhaas                     218            1826 :     size = mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots);
  736 andres                    219            1826 :     BackendGssStatusBuffer = (PgBackendGSSStatus *)
                                220            1826 :         ShmemInitStruct("Backend GSS Status Buffer", size, &found);
                                221                 : 
                                222            1826 :     if (!found)
                                223                 :     {
                                224                 :         PgBackendGSSStatus *ptr;
                                225                 : 
                                226            1826 :         MemSet(BackendGssStatusBuffer, 0, size);
                                227                 : 
                                228                 :         /* Initialize st_gssstatus pointers. */
                                229            1826 :         ptr = BackendGssStatusBuffer;
  362 rhaas                     230          204159 :         for (i = 0; i < NumBackendStatSlots; i++)
                                231                 :         {
  736 andres                    232          202333 :             BackendStatusArray[i].st_gssstatus = ptr;
                                233          202333 :             ptr++;
                                234                 :         }
                                235                 :     }
                                236                 : #endif
                                237            1826 : }
                                238                 : 
                                239                 : /*
                                240                 :  * Initialize pgstats backend activity state, and set up our on-proc-exit
                                241                 :  * hook.  Called from InitPostgres and AuxiliaryProcessMain. For auxiliary
                                242                 :  * process, MyBackendId is invalid. Otherwise, MyBackendId must be set, but we
                                243                 :  * must not have started any transaction yet (since the exit hook must run
                                244                 :  * after the last transaction exit).
                                245                 :  *
                                246                 :  * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
                                247                 :  */
                                248                 : void
                                249           13291 : pgstat_beinit(void)
                                250                 : {
                                251                 :     /* Initialize MyBEEntry */
                                252           13291 :     if (MyBackendId != InvalidBackendId)
                                253                 :     {
  362 rhaas                     254           11507 :         Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
  736 andres                    255           11507 :         MyBEEntry = &BackendStatusArray[MyBackendId - 1];
                                256                 :     }
                                257                 :     else
                                258                 :     {
                                259                 :         /* Must be an auxiliary process */
                                260            1784 :         Assert(MyAuxProcType != NotAnAuxProcess);
                                261                 : 
                                262                 :         /*
                                263                 :          * Assign the MyBEEntry for an auxiliary process.  Since it doesn't
                                264                 :          * have a BackendId, the slot is statically allocated based on the
                                265                 :          * auxiliary process type (MyAuxProcType).  Backends use slots indexed
                                266                 :          * in the range from 1 to MaxBackends (inclusive), so we use
                                267                 :          * MaxBackends + AuxBackendType + 1 as the index of the slot for an
                                268                 :          * auxiliary process.
                                269                 :          */
  362 rhaas                     270            1784 :         MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
                                271                 :     }
                                272                 : 
                                273                 :     /* Set up a process-exit hook to clean up */
  736 andres                    274           13291 :     on_shmem_exit(pgstat_beshutdown_hook, 0);
                                275           13291 : }
                                276                 : 
                                277                 : 
                                278                 : /* ----------
                                279                 :  * pgstat_bestart() -
                                280                 :  *
                                281                 :  *  Initialize this backend's entry in the PgBackendStatus array.
                                282                 :  *  Called from InitPostgres.
                                283                 :  *
                                284                 :  *  Apart from auxiliary processes, MyBackendId, MyDatabaseId,
                                285                 :  *  session userid, and application_name must be set for a
                                286                 :  *  backend (hence, this cannot be combined with pgbestat_beinit).
                                287                 :  *  Note also that we must be inside a transaction if this isn't an aux
                                288                 :  *  process, as we may need to do encoding conversion on some strings.
                                289                 :  * ----------
                                290                 :  */
                                291                 : void
                                292           12907 : pgstat_bestart(void)
                                293                 : {
                                294           12907 :     volatile PgBackendStatus *vbeentry = MyBEEntry;
                                295                 :     PgBackendStatus lbeentry;
                                296                 : #ifdef USE_SSL
                                297                 :     PgBackendSSLStatus lsslstatus;
                                298                 : #endif
                                299                 : #ifdef ENABLE_GSS
                                300                 :     PgBackendGSSStatus lgssstatus;
                                301                 : #endif
                                302                 : 
                                303                 :     /* pgstats state must be initialized from pgstat_beinit() */
                                304           12907 :     Assert(vbeentry != NULL);
                                305                 : 
                                306                 :     /*
                                307                 :      * To minimize the time spent modifying the PgBackendStatus entry, and
                                308                 :      * avoid risk of errors inside the critical section, we first copy the
                                309                 :      * shared-memory struct to a local variable, then modify the data in the
                                310                 :      * local variable, then copy the local variable back to shared memory.
                                311                 :      * Only the last step has to be inside the critical section.
                                312                 :      *
                                313                 :      * Most of the data we copy from shared memory is just going to be
                                314                 :      * overwritten, but the struct's not so large that it's worth the
                                315                 :      * maintenance hassle to copy only the needful fields.
                                316                 :      */
                                317           12907 :     memcpy(&lbeentry,
                                318           12907 :            unvolatize(PgBackendStatus *, vbeentry),
                                319                 :            sizeof(PgBackendStatus));
                                320                 : 
                                321                 :     /* These structs can just start from zeroes each time, though */
                                322                 : #ifdef USE_SSL
                                323           12907 :     memset(&lsslstatus, 0, sizeof(lsslstatus));
                                324                 : #endif
                                325                 : #ifdef ENABLE_GSS
                                326           12907 :     memset(&lgssstatus, 0, sizeof(lgssstatus));
                                327                 : #endif
                                328                 : 
                                329                 :     /*
                                330                 :      * Now fill in all the fields of lbeentry, except for strings that are
                                331                 :      * out-of-line data.  Those have to be handled separately, below.
                                332                 :      */
                                333           12907 :     lbeentry.st_procpid = MyProcPid;
                                334           12907 :     lbeentry.st_backendType = MyBackendType;
                                335           12907 :     lbeentry.st_proc_start_timestamp = MyStartTimestamp;
                                336           12907 :     lbeentry.st_activity_start_timestamp = 0;
                                337           12907 :     lbeentry.st_state_start_timestamp = 0;
                                338           12907 :     lbeentry.st_xact_start_timestamp = 0;
                                339           12907 :     lbeentry.st_databaseid = MyDatabaseId;
                                340                 : 
                                341                 :     /* We have userid for client-backends, wal-sender and bgworker processes */
                                342           12907 :     if (lbeentry.st_backendType == B_BACKEND
                                343            5184 :         || lbeentry.st_backendType == B_WAL_SENDER
                                344            4353 :         || lbeentry.st_backendType == B_BG_WORKER)
                                345           10489 :         lbeentry.st_userid = GetSessionUserId();
                                346                 :     else
                                347            2418 :         lbeentry.st_userid = InvalidOid;
                                348                 : 
                                349                 :     /*
                                350                 :      * We may not have a MyProcPort (eg, if this is the autovacuum process).
                                351                 :      * If so, use all-zeroes client address, which is dealt with specially in
                                352                 :      * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
                                353                 :      */
                                354           12907 :     if (MyProcPort)
                                355            8554 :         memcpy(&lbeentry.st_clientaddr, &MyProcPort->raddr,
                                356                 :                sizeof(lbeentry.st_clientaddr));
                                357                 :     else
                                358           78354 :         MemSet(&lbeentry.st_clientaddr, 0, sizeof(lbeentry.st_clientaddr));
                                359                 : 
                                360                 : #ifdef USE_SSL
                                361           12907 :     if (MyProcPort && MyProcPort->ssl_in_use)
                                362                 :     {
                                363              76 :         lbeentry.st_ssl = true;
                                364              76 :         lsslstatus.ssl_bits = be_tls_get_cipher_bits(MyProcPort);
                                365              76 :         strlcpy(lsslstatus.ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
                                366              76 :         strlcpy(lsslstatus.ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
                                367              76 :         be_tls_get_peer_subject_name(MyProcPort, lsslstatus.ssl_client_dn, NAMEDATALEN);
                                368              76 :         be_tls_get_peer_serial(MyProcPort, lsslstatus.ssl_client_serial, NAMEDATALEN);
                                369              76 :         be_tls_get_peer_issuer_name(MyProcPort, lsslstatus.ssl_issuer_dn, NAMEDATALEN);
                                370                 :     }
                                371                 :     else
                                372                 :     {
                                373           12831 :         lbeentry.st_ssl = false;
                                374                 :     }
                                375                 : #else
                                376                 :     lbeentry.st_ssl = false;
                                377                 : #endif
                                378                 : 
                                379                 : #ifdef ENABLE_GSS
                                380           12907 :     if (MyProcPort && MyProcPort->gss != NULL)
                                381              17 :     {
                                382              17 :         const char *princ = be_gssapi_get_princ(MyProcPort);
                                383                 : 
                                384              17 :         lbeentry.st_gss = true;
                                385              17 :         lgssstatus.gss_auth = be_gssapi_get_auth(MyProcPort);
                                386              17 :         lgssstatus.gss_enc = be_gssapi_get_enc(MyProcPort);
                                387              17 :         if (princ)
                                388              17 :             strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
                                389                 :     }
                                390                 :     else
                                391                 :     {
                                392           12890 :         lbeentry.st_gss = false;
                                393                 :     }
                                394                 : #else
                                395                 :     lbeentry.st_gss = false;
                                396                 : #endif
                                397                 : 
                                398           12907 :     lbeentry.st_state = STATE_UNDEFINED;
                                399           12907 :     lbeentry.st_progress_command = PROGRESS_COMMAND_INVALID;
                                400           12907 :     lbeentry.st_progress_command_target = InvalidOid;
  719 bruce                     401           12907 :     lbeentry.st_query_id = UINT64CONST(0);
                                402                 : 
                                403                 :     /*
                                404                 :      * we don't zero st_progress_param here to save cycles; nobody should
                                405                 :      * examine it until st_progress_command has been set to something other
                                406                 :      * than PROGRESS_COMMAND_INVALID
                                407                 :      */
                                408                 : 
                                409                 :     /*
                                410                 :      * We're ready to enter the critical section that fills the shared-memory
                                411                 :      * status entry.  We follow the protocol of bumping st_changecount before
                                412                 :      * and after; and make sure it's even afterwards.  We use a volatile
                                413                 :      * pointer here to ensure the compiler doesn't try to get cute.
                                414                 :      */
  736 andres                    415           12907 :     PGSTAT_BEGIN_WRITE_ACTIVITY(vbeentry);
                                416                 : 
                                417                 :     /* make sure we'll memcpy the same st_changecount back */
                                418           12907 :     lbeentry.st_changecount = vbeentry->st_changecount;
                                419                 : 
                                420           12907 :     memcpy(unvolatize(PgBackendStatus *, vbeentry),
                                421                 :            &lbeentry,
                                422                 :            sizeof(PgBackendStatus));
                                423                 : 
                                424                 :     /*
                                425                 :      * We can write the out-of-line strings and structs using the pointers
                                426                 :      * that are in lbeentry; this saves some de-volatilizing messiness.
                                427                 :      */
                                428           12907 :     lbeentry.st_appname[0] = '\0';
                                429           12907 :     if (MyProcPort && MyProcPort->remote_hostname)
                                430              76 :         strlcpy(lbeentry.st_clienthostname, MyProcPort->remote_hostname,
                                431                 :                 NAMEDATALEN);
                                432                 :     else
                                433           12831 :         lbeentry.st_clienthostname[0] = '\0';
                                434           12907 :     lbeentry.st_activity_raw[0] = '\0';
                                435                 :     /* Also make sure the last byte in each string area is always 0 */
                                436           12907 :     lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
                                437           12907 :     lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
                                438           12907 :     lbeentry.st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
                                439                 : 
                                440                 : #ifdef USE_SSL
                                441           12907 :     memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
                                442                 : #endif
                                443                 : #ifdef ENABLE_GSS
                                444           12907 :     memcpy(lbeentry.st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
                                445                 : #endif
                                446                 : 
                                447           12907 :     PGSTAT_END_WRITE_ACTIVITY(vbeentry);
                                448                 : 
                                449                 :     /* Update app name to current GUC setting */
                                450           12907 :     if (application_name)
                                451           12907 :         pgstat_report_appname(application_name);
                                452           12907 : }
                                453                 : 
                                454                 : /*
                                455                 :  * Clear out our entry in the PgBackendStatus array.
                                456                 :  */
                                457                 : static void
                                458           13291 : pgstat_beshutdown_hook(int code, Datum arg)
                                459                 : {
                                460           13291 :     volatile PgBackendStatus *beentry = MyBEEntry;
                                461                 : 
                                462                 :     /*
                                463                 :      * Clear my status entry, following the protocol of bumping st_changecount
                                464                 :      * before and after.  We use a volatile pointer here to ensure the
                                465                 :      * compiler doesn't try to get cute.
                                466                 :      */
                                467           13291 :     PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
                                468                 : 
                                469           13291 :     beentry->st_procpid = 0; /* mark invalid */
                                470                 : 
                                471           13291 :     PGSTAT_END_WRITE_ACTIVITY(beentry);
                                472                 : 
                                473                 :     /* so that functions can check if backend_status.c is up via MyBEEntry */
  598                           474           13291 :     MyBEEntry = NULL;
  736                           475           13291 : }
                                476                 : 
                                477                 : /*
                                478                 :  * Discard any data collected in the current transaction.  Any subsequent
                                479                 :  * request will cause new snapshots to be read.
                                480                 :  *
                                481                 :  * This is also invoked during transaction commit or abort to discard the
                                482                 :  * no-longer-wanted snapshot.
                                483                 :  */
                                484                 : void
                                485          486568 : pgstat_clear_backend_activity_snapshot(void)
                                486                 : {
                                487                 :     /* Release memory, if any was allocated */
                                488          486568 :     if (backendStatusSnapContext)
                                489                 :     {
                                490             582 :         MemoryContextDelete(backendStatusSnapContext);
                                491             582 :         backendStatusSnapContext = NULL;
                                492                 :     }
                                493                 : 
                                494                 :     /* Reset variables */
                                495          486568 :     localBackendStatusTable = NULL;
                                496          486568 :     localNumBackends = 0;
                                497          486568 : }
                                498                 : 
                                499                 : static void
                                500             582 : pgstat_setup_backend_status_context(void)
                                501                 : {
                                502             582 :     if (!backendStatusSnapContext)
                                503             582 :         backendStatusSnapContext = AllocSetContextCreate(TopMemoryContext,
                                504                 :                                                          "Backend Status Snapshot",
                                505                 :                                                          ALLOCSET_SMALL_SIZES);
                                506             582 : }
                                507                 : 
                                508                 : 
                                509                 : /* ----------
                                510                 :  * pgstat_report_activity() -
                                511                 :  *
                                512                 :  *  Called from tcop/postgres.c to report what the backend is actually doing
                                513                 :  *  (but note cmd_str can be NULL for certain cases).
                                514                 :  *
                                515                 :  * All updates of the status entry follow the protocol of bumping
                                516                 :  * st_changecount before and after.  We use a volatile pointer here to
                                517                 :  * ensure the compiler doesn't try to get cute.
                                518                 :  * ----------
                                519                 :  */
                                520                 : void
                                521          935081 : pgstat_report_activity(BackendState state, const char *cmd_str)
                                522                 : {
                                523          935081 :     volatile PgBackendStatus *beentry = MyBEEntry;
                                524                 :     TimestampTz start_timestamp;
                                525                 :     TimestampTz current_timestamp;
                                526          935081 :     int         len = 0;
                                527                 : 
                                528                 :     TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
                                529                 : 
                                530          935081 :     if (!beentry)
  736 andres                    531 UBC           0 :         return;
                                532                 : 
  736 andres                    533 CBC      935081 :     if (!pgstat_track_activities)
                                534                 :     {
  736 andres                    535 UBC           0 :         if (beentry->st_state != STATE_DISABLED)
                                536                 :         {
                                537               0 :             volatile PGPROC *proc = MyProc;
                                538                 : 
                                539                 :             /*
                                540                 :              * track_activities is disabled, but we last reported a
                                541                 :              * non-disabled state.  As our final update, change the state and
                                542                 :              * clear fields we will not be updating anymore.
                                543                 :              */
                                544               0 :             PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
                                545               0 :             beentry->st_state = STATE_DISABLED;
                                546               0 :             beentry->st_state_start_timestamp = 0;
                                547               0 :             beentry->st_activity_raw[0] = '\0';
                                548               0 :             beentry->st_activity_start_timestamp = 0;
                                549                 :             /* st_xact_start_timestamp and wait_event_info are also disabled */
                                550               0 :             beentry->st_xact_start_timestamp = 0;
  719 bruce                     551               0 :             beentry->st_query_id = UINT64CONST(0);
  736 andres                    552               0 :             proc->wait_event_info = 0;
                                553               0 :             PGSTAT_END_WRITE_ACTIVITY(beentry);
                                554                 :         }
                                555               0 :         return;
                                556                 :     }
                                557                 : 
                                558                 :     /*
                                559                 :      * To minimize the time spent modifying the entry, and avoid risk of
                                560                 :      * errors inside the critical section, fetch all the needed data first.
                                561                 :      */
  736 andres                    562 CBC      935081 :     start_timestamp = GetCurrentStatementStartTimestamp();
                                563          935081 :     if (cmd_str != NULL)
                                564                 :     {
                                565                 :         /*
                                566                 :          * Compute length of to-be-stored string unaware of multi-byte
                                567                 :          * characters. For speed reasons that'll get corrected on read, rather
                                568                 :          * than computed every write.
                                569                 :          */
                                570          468556 :         len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
                                571                 :     }
                                572          935081 :     current_timestamp = GetCurrentTimestamp();
                                573                 : 
                                574                 :     /*
                                575                 :      * If the state has changed from "active" or "idle in transaction",
                                576                 :      * calculate the duration.
                                577                 :      */
                                578          935081 :     if ((beentry->st_state == STATE_RUNNING ||
                                579          466823 :          beentry->st_state == STATE_FASTPATH ||
                                580          465760 :          beentry->st_state == STATE_IDLEINTRANSACTION ||
                                581          410069 :          beentry->st_state == STATE_IDLEINTRANSACTION_ABORTED) &&
                                582          525811 :         state != beentry->st_state)
                                583                 :     {
                                584                 :         long        secs;
                                585                 :         int         usecs;
                                586                 : 
                                587          511419 :         TimestampDifference(beentry->st_state_start_timestamp,
                                588                 :                             current_timestamp,
                                589                 :                             &secs, &usecs);
                                590                 : 
                                591          511419 :         if (beentry->st_state == STATE_RUNNING ||
                                592           57551 :             beentry->st_state == STATE_FASTPATH)
  570                           593          454931 :             pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
                                594                 :         else
                                595           56488 :             pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
                                596                 :     }
                                597                 : 
                                598                 :     /*
                                599                 :      * Now update the status entry
                                600                 :      */
  736                           601          935081 :     PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
                                602                 : 
                                603          935081 :     beentry->st_state = state;
                                604          935081 :     beentry->st_state_start_timestamp = current_timestamp;
                                605                 : 
                                606                 :     /*
                                607                 :      * If a new query is started, we reset the query identifier as it'll only
                                608                 :      * be known after parse analysis, to avoid reporting last query's
                                609                 :      * identifier.
                                610                 :      */
  732 bruce                     611          935081 :     if (state == STATE_RUNNING)
  719                           612          469820 :         beentry->st_query_id = UINT64CONST(0);
                                613                 : 
  736 andres                    614          935081 :     if (cmd_str != NULL)
                                615                 :     {
                                616          468556 :         memcpy((char *) beentry->st_activity_raw, cmd_str, len);
                                617          468556 :         beentry->st_activity_raw[len] = '\0';
                                618          468556 :         beentry->st_activity_start_timestamp = start_timestamp;
                                619                 :     }
                                620                 : 
                                621          935081 :     PGSTAT_END_WRITE_ACTIVITY(beentry);
                                622                 : }
                                623                 : 
                                624                 : /* --------
                                625                 :  * pgstat_report_query_id() -
                                626                 :  *
                                627                 :  * Called to update top-level query identifier.
                                628                 :  * --------
                                629                 :  */
                                630                 : void
  719 bruce                     631         1318018 : pgstat_report_query_id(uint64 query_id, bool force)
                                632                 : {
  732                           633         1318018 :     volatile PgBackendStatus *beentry = MyBEEntry;
                                634                 : 
                                635                 :     /*
                                636                 :      * if track_activities is disabled, st_query_id should already have been
                                637                 :      * reset
                                638                 :      */
                                639         1318018 :     if (!beentry || !pgstat_track_activities)
  732 bruce                     640 UBC           0 :         return;
                                641                 : 
                                642                 :     /*
                                643                 :      * We only report the top-level query identifiers.  The stored query_id is
                                644                 :      * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
                                645                 :      * with an explicit call to this function using the force flag.  If the
                                646                 :      * saved query identifier is not zero it means that it's not a top-level
                                647                 :      * command, so ignore the one provided unless it's an explicit call to
                                648                 :      * reset the identifier.
                                649                 :      */
  719 bruce                     650 CBC     1318018 :     if (beentry->st_query_id != 0 && !force)
  732                           651           50747 :         return;
                                652                 : 
                                653                 :     /*
                                654                 :      * Update my status entry, following the protocol of bumping
                                655                 :      * st_changecount before and after.  We use a volatile pointer here to
                                656                 :      * ensure the compiler doesn't try to get cute.
                                657                 :      */
                                658         1267271 :     PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
  719                           659         1267271 :     beentry->st_query_id = query_id;
  732                           660         1267271 :     PGSTAT_END_WRITE_ACTIVITY(beentry);
                                661                 : }
                                662                 : 
                                663                 : 
                                664                 : /* ----------
                                665                 :  * pgstat_report_appname() -
                                666                 :  *
                                667                 :  *  Called to update our application name.
                                668                 :  * ----------
                                669                 :  */
                                670                 : void
  736 andres                    671           25066 : pgstat_report_appname(const char *appname)
                                672                 : {
                                673           25066 :     volatile PgBackendStatus *beentry = MyBEEntry;
                                674                 :     int         len;
                                675                 : 
                                676           25066 :     if (!beentry)
                                677            1857 :         return;
                                678                 : 
                                679                 :     /* This should be unnecessary if GUC did its job, but be safe */
                                680           23209 :     len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
                                681                 : 
                                682                 :     /*
                                683                 :      * Update my status entry, following the protocol of bumping
                                684                 :      * st_changecount before and after.  We use a volatile pointer here to
                                685                 :      * ensure the compiler doesn't try to get cute.
                                686                 :      */
                                687           23209 :     PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
                                688                 : 
                                689           23209 :     memcpy((char *) beentry->st_appname, appname, len);
                                690           23209 :     beentry->st_appname[len] = '\0';
                                691                 : 
                                692           23209 :     PGSTAT_END_WRITE_ACTIVITY(beentry);
                                693                 : }
                                694                 : 
                                695                 : /*
                                696                 :  * Report current transaction start timestamp as the specified value.
                                697                 :  * Zero means there is no active transaction.
                                698                 :  */
                                699                 : void
                                700          972392 : pgstat_report_xact_timestamp(TimestampTz tstamp)
                                701                 : {
                                702          972392 :     volatile PgBackendStatus *beentry = MyBEEntry;
                                703                 : 
                                704          972392 :     if (!pgstat_track_activities || !beentry)
  736 andres                    705 UBC           0 :         return;
                                706                 : 
                                707                 :     /*
                                708                 :      * Update my status entry, following the protocol of bumping
                                709                 :      * st_changecount before and after.  We use a volatile pointer here to
                                710                 :      * ensure the compiler doesn't try to get cute.
                                711                 :      */
  736 andres                    712 CBC      972392 :     PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
                                713                 : 
                                714          972392 :     beentry->st_xact_start_timestamp = tstamp;
                                715                 : 
                                716          972392 :     PGSTAT_END_WRITE_ACTIVITY(beentry);
                                717                 : }
                                718                 : 
                                719                 : /* ----------
                                720                 :  * pgstat_read_current_status() -
                                721                 :  *
                                722                 :  *  Copy the current contents of the PgBackendStatus array to local memory,
                                723                 :  *  if not already done in this transaction.
                                724                 :  * ----------
                                725                 :  */
                                726                 : static void
                                727            4941 : pgstat_read_current_status(void)
                                728                 : {
                                729                 :     volatile PgBackendStatus *beentry;
                                730                 :     LocalPgBackendStatus *localtable;
                                731                 :     LocalPgBackendStatus *localentry;
                                732                 :     char       *localappname,
                                733                 :                *localclienthostname,
                                734                 :                *localactivity;
                                735                 : #ifdef USE_SSL
                                736                 :     PgBackendSSLStatus *localsslstatus;
                                737                 : #endif
                                738                 : #ifdef ENABLE_GSS
                                739                 :     PgBackendGSSStatus *localgssstatus;
                                740                 : #endif
                                741                 :     int         i;
                                742                 : 
                                743            4941 :     if (localBackendStatusTable)
                                744            4359 :         return;                 /* already done */
                                745                 : 
                                746             582 :     pgstat_setup_backend_status_context();
                                747                 : 
                                748                 :     /*
                                749                 :      * Allocate storage for local copy of state data.  We can presume that
                                750                 :      * none of these requests overflow size_t, because we already calculated
                                751                 :      * the same values using mul_size during shmem setup.  However, with
                                752                 :      * probably-silly values of pgstat_track_activity_query_size and
                                753                 :      * max_connections, the localactivity buffer could exceed 1GB, so use
                                754                 :      * "huge" allocation for that one.
                                755                 :      */
                                756                 :     localtable = (LocalPgBackendStatus *)
                                757             582 :         MemoryContextAlloc(backendStatusSnapContext,
  362 rhaas                     758             582 :                            sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
                                759                 :     localappname = (char *)
  736 andres                    760             582 :         MemoryContextAlloc(backendStatusSnapContext,
  362 rhaas                     761             582 :                            NAMEDATALEN * NumBackendStatSlots);
                                762                 :     localclienthostname = (char *)
  736 andres                    763             582 :         MemoryContextAlloc(backendStatusSnapContext,
  362 rhaas                     764             582 :                            NAMEDATALEN * NumBackendStatSlots);
                                765                 :     localactivity = (char *)
  736 andres                    766             582 :         MemoryContextAllocHuge(backendStatusSnapContext,
  362 rhaas                     767             582 :                                pgstat_track_activity_query_size * NumBackendStatSlots);
                                768                 : #ifdef USE_SSL
                                769                 :     localsslstatus = (PgBackendSSLStatus *)
  736 andres                    770             582 :         MemoryContextAlloc(backendStatusSnapContext,
  362 rhaas                     771             582 :                            sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
                                772                 : #endif
                                773                 : #ifdef ENABLE_GSS
                                774                 :     localgssstatus = (PgBackendGSSStatus *)
  736 andres                    775             582 :         MemoryContextAlloc(backendStatusSnapContext,
  362 rhaas                     776             582 :                            sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
                                777                 : #endif
                                778                 : 
  736 andres                    779             582 :     localNumBackends = 0;
                                780                 : 
                                781             582 :     beentry = BackendStatusArray;
                                782             582 :     localentry = localtable;
  362 rhaas                     783           26769 :     for (i = 1; i <= NumBackendStatSlots; i++)
                                784                 :     {
                                785                 :         /*
                                786                 :          * Follow the protocol of retrying if st_changecount changes while we
                                787                 :          * copy the entry, or if it's odd.  (The check for odd is needed to
                                788                 :          * cover the case where we are able to completely copy the entry while
                                789                 :          * the source backend is between increment steps.)  We use a volatile
                                790                 :          * pointer here to ensure the compiler doesn't try to get cute.
                                791                 :          */
                                792                 :         for (;;)
  736 andres                    793               1 :         {
                                794                 :             int         before_changecount;
                                795                 :             int         after_changecount;
                                796                 : 
                                797           26188 :             pgstat_begin_read_activity(beentry, before_changecount);
                                798                 : 
                                799           26188 :             localentry->backendStatus.st_procpid = beentry->st_procpid;
                                800                 :             /* Skip all the data-copying work if entry is not in use */
                                801           26188 :             if (localentry->backendStatus.st_procpid > 0)
                                802                 :             {
                                803            4285 :                 memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
                                804                 : 
                                805                 :                 /*
                                806                 :                  * For each PgBackendStatus field that is a pointer, copy the
                                807                 :                  * pointed-to data, then adjust the local copy of the pointer
                                808                 :                  * field to point at the local copy of the data.
                                809                 :                  *
                                810                 :                  * strcpy is safe even if the string is modified concurrently,
                                811                 :                  * because there's always a \0 at the end of the buffer.
                                812                 :                  */
                                813            4285 :                 strcpy(localappname, (char *) beentry->st_appname);
                                814            4285 :                 localentry->backendStatus.st_appname = localappname;
                                815            4285 :                 strcpy(localclienthostname, (char *) beentry->st_clienthostname);
                                816            4285 :                 localentry->backendStatus.st_clienthostname = localclienthostname;
                                817            4285 :                 strcpy(localactivity, (char *) beentry->st_activity_raw);
                                818            4285 :                 localentry->backendStatus.st_activity_raw = localactivity;
                                819                 : #ifdef USE_SSL
                                820            4285 :                 if (beentry->st_ssl)
                                821                 :                 {
                                822               7 :                     memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
                                823               7 :                     localentry->backendStatus.st_sslstatus = localsslstatus;
                                824                 :                 }
                                825                 : #endif
                                826                 : #ifdef ENABLE_GSS
                                827            4285 :                 if (beentry->st_gss)
                                828                 :                 {
                                829               8 :                     memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
                                830               8 :                     localentry->backendStatus.st_gssstatus = localgssstatus;
                                831                 :                 }
                                832                 : #endif
                                833                 :             }
                                834                 : 
                                835           26188 :             pgstat_end_read_activity(beentry, after_changecount);
                                836                 : 
                                837           26188 :             if (pgstat_read_activity_complete(before_changecount,
                                838                 :                                               after_changecount))
                                839           26187 :                 break;
                                840                 : 
                                841                 :             /* Make sure we can break out of loop if stuck... */
                                842               1 :             CHECK_FOR_INTERRUPTS();
                                843                 :         }
                                844                 : 
  736 andres                    845 ECB             :         /* Only valid entries get included into the local array */
  736 andres                    846 GIC       26187 :         if (localentry->backendStatus.st_procpid > 0)
                                847                 :         {
                                848                 :             /*
                                849                 :              * The BackendStatusArray index is exactly the BackendId of the
                                850                 :              * source backend.  Note that this means localBackendStatusTable
                                851                 :              * is in order by backend_id.  pgstat_fetch_stat_beentry() depends
                                852                 :              * on that.
                                853                 :              */
  192 tgl                       854 GNC        4284 :             localentry->backend_id = i;
  736 andres                    855 GIC        4284 :             BackendIdGetTransactionIds(i,
                                856                 :                                        &localentry->backend_xid,
                                857                 :                                        &localentry->backend_xmin,
                                858                 :                                        &localentry->backend_subxact_count,
                                859                 :                                        &localentry->backend_subxact_overflowed);
                                860                 : 
                                861            4284 :             localentry++;
  736 andres                    862 CBC        4284 :             localappname += NAMEDATALEN;
                                863            4284 :             localclienthostname += NAMEDATALEN;
  736 andres                    864 GIC        4284 :             localactivity += pgstat_track_activity_query_size;
                                865                 : #ifdef USE_SSL
                                866            4284 :             localsslstatus++;
                                867                 : #endif
                                868                 : #ifdef ENABLE_GSS
  736 andres                    869 CBC        4284 :             localgssstatus++;
  736 andres                    870 ECB             : #endif
  736 andres                    871 CBC        4284 :             localNumBackends++;
  736 andres                    872 ECB             :         }
                                873                 : 
  110 john.naylor               874 GNC       26187 :         beentry++;
                                875                 :     }
  736 andres                    876 ECB             : 
                                877                 :     /* Set the pointer only after completion of a valid table */
  736 andres                    878 GIC         582 :     localBackendStatusTable = localtable;
  736 andres                    879 ECB             : }
                                880                 : 
                                881                 : 
                                882                 : /* ----------
                                883                 :  * pgstat_get_backend_current_activity() -
                                884                 :  *
                                885                 :  *  Return a string representing the current activity of the backend with
                                886                 :  *  the specified PID.  This looks directly at the BackendStatusArray,
                                887                 :  *  and so will provide current information regardless of the age of our
                                888                 :  *  transaction's snapshot of the status array.
                                889                 :  *
                                890                 :  *  It is the caller's responsibility to invoke this only for backends whose
                                891                 :  *  state is expected to remain stable while the result is in use.  The
                                892                 :  *  only current use is in deadlock reporting, where we can expect that
                                893                 :  *  the target backend is blocked on a lock.  (There are corner cases
                                894                 :  *  where the target's wait could get aborted while we are looking at it,
                                895                 :  *  but the very worst consequence is to return a pointer to a string
                                896                 :  *  that's been changed, so we won't worry too much.)
                                897                 :  *
                                898                 :  *  Note: return strings for special cases match pg_stat_get_backend_activity.
                                899                 :  * ----------
                                900                 :  */
                                901                 : const char *
  736 andres                    902 GIC          17 : pgstat_get_backend_current_activity(int pid, bool checkUser)
                                903                 : {
                                904                 :     PgBackendStatus *beentry;
                                905                 :     int         i;
                                906                 : 
                                907              17 :     beentry = BackendStatusArray;
  362 rhaas                     908              95 :     for (i = 1; i <= MaxBackends; i++)
                                909                 :     {
                                910                 :         /*
                                911                 :          * Although we expect the target backend's entry to be stable, that
  736 andres                    912 ECB             :          * doesn't imply that anyone else's is.  To avoid identifying the
                                913                 :          * wrong backend, while we check for a match to the desired PID we
                                914                 :          * must follow the protocol of retrying if st_changecount changes
                                915                 :          * while we examine the entry, or if it's odd.  (This might be
                                916                 :          * unnecessary, since fetching or storing an int is almost certainly
                                917                 :          * atomic, but let's play it safe.)  We use a volatile pointer here to
                                918                 :          * ensure the compiler doesn't try to get cute.
                                919                 :          */
  736 andres                    920 GIC          95 :         volatile PgBackendStatus *vbeentry = beentry;
                                921                 :         bool        found;
                                922                 : 
                                923                 :         for (;;)
  736 andres                    924 UIC           0 :         {
                                925                 :             int         before_changecount;
                                926                 :             int         after_changecount;
                                927                 : 
  736 andres                    928 GIC          95 :             pgstat_begin_read_activity(vbeentry, before_changecount);
                                929                 : 
  736 andres                    930 CBC          95 :             found = (vbeentry->st_procpid == pid);
                                931                 : 
  736 andres                    932 GIC          95 :             pgstat_end_read_activity(vbeentry, after_changecount);
                                933                 : 
  736 andres                    934 GBC          95 :             if (pgstat_read_activity_complete(before_changecount,
                                935                 :                                               after_changecount))
  736 andres                    936 GIC          95 :                 break;
                                937                 : 
  736 andres                    938 ECB             :             /* Make sure we can break out of loop if stuck... */
  736 andres                    939 UIC           0 :             CHECK_FOR_INTERRUPTS();
  736 andres                    940 ECB             :         }
                                941                 : 
  736 andres                    942 CBC          95 :         if (found)
                                943                 :         {
  736 andres                    944 ECB             :             /* Now it is safe to use the non-volatile pointer */
  736 andres                    945 GIC          17 :             if (checkUser && !superuser() && beentry->st_userid != GetUserId())
  736 andres                    946 LBC           0 :                 return "<insufficient privilege>";
  736 andres                    947 GIC          17 :             else if (*(beentry->st_activity_raw) == '\0')
                                948               5 :                 return "<command string not enabled>";
  736 andres                    949 EUB             :             else
                                950                 :             {
                                951                 :                 /* this'll leak a bit of memory, but that seems acceptable */
  736 andres                    952 CBC          12 :                 return pgstat_clip_activity(beentry->st_activity_raw);
                                953                 :             }
                                954                 :         }
  736 andres                    955 ECB             : 
  736 andres                    956 GBC          78 :         beentry++;
  736 andres                    957 ECB             :     }
                                958                 : 
                                959                 :     /* If we get here, caller is in error ... */
  736 andres                    960 UIC           0 :     return "<backend information not available>";
                                961                 : }
  736 andres                    962 ECB             : 
                                963                 : /* ----------
                                964                 :  * pgstat_get_crashed_backend_activity() -
                                965                 :  *
                                966                 :  *  Return a string representing the current activity of the backend with
                                967                 :  *  the specified PID.  Like the function above, but reads shared memory with
                                968                 :  *  the expectation that it may be corrupt.  On success, copy the string
                                969                 :  *  into the "buffer" argument and return that pointer.  On failure,
  736 andres                    970 EUB             :  *  return NULL.
                                971                 :  *
                                972                 :  *  This function is only intended to be used by the postmaster to report the
                                973                 :  *  query that crashed a backend.  In particular, no attempt is made to
                                974                 :  *  follow the correct concurrency protocol when accessing the
                                975                 :  *  BackendStatusArray.  But that's OK, in the worst case we'll return a
                                976                 :  *  corrupted message.  We also must take care not to trip on ereport(ERROR).
                                977                 :  * ----------
                                978                 :  */
                                979                 : const char *
  736 andres                    980 GIC         838 : pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
                                981                 : {
                                982                 :     volatile PgBackendStatus *beentry;
                                983                 :     int         i;
                                984                 : 
                                985             838 :     beentry = BackendStatusArray;
                                986                 : 
                                987                 :     /*
                                988                 :      * We probably shouldn't get here before shared memory has been set up,
                                989                 :      * but be safe.
  736 andres                    990 ECB             :      */
  736 andres                    991 GIC         838 :     if (beentry == NULL || BackendActivityBuffer == NULL)
  736 andres                    992 UIC           0 :         return NULL;
                                993                 : 
  362 rhaas                     994 GIC       59736 :     for (i = 1; i <= MaxBackends; i++)
  736 andres                    995 ECB             :     {
  736 andres                    996 GIC       58958 :         if (beentry->st_procpid == pid)
                                997                 :         {
                                998                 :             /* Read pointer just once, so it can't change after validation */
                                999              60 :             const char *activity = beentry->st_activity_raw;
                               1000                 :             const char *activity_last;
  736 andres                   1001 ECB             : 
  736 andres                   1002 EUB             :             /*
                               1003                 :              * We mustn't access activity string before we verify that it
  736 andres                   1004 ECB             :              * falls within the BackendActivityBuffer. To make sure that the
                               1005                 :              * entire string including its ending is contained within the
                               1006                 :              * buffer, subtract one activity length from the buffer size.
                               1007                 :              */
  736 andres                   1008 GIC          60 :             activity_last = BackendActivityBuffer + BackendActivityBufferSize
  736 andres                   1009 CBC          60 :                 - pgstat_track_activity_query_size;
                               1010                 : 
  736 andres                   1011 GIC          60 :             if (activity < BackendActivityBuffer ||
                               1012                 :                 activity > activity_last)
  736 andres                   1013 UIC           0 :                 return NULL;
                               1014                 : 
                               1015                 :             /* If no string available, no point in a report */
  736 andres                   1016 GIC          60 :             if (activity[0] == '\0')
  736 andres                   1017 UIC           0 :                 return NULL;
  736 andres                   1018 ECB             : 
                               1019                 :             /*
                               1020                 :              * Copy only ASCII-safe characters so we don't run into encoding
                               1021                 :              * problems when reporting the message; and be sure not to run off
                               1022                 :              * the end of memory.  As only ASCII characters are reported, it
  736 andres                   1023 EUB             :              * doesn't seem necessary to perform multibyte aware clipping.
                               1024                 :              */
  736 andres                   1025 GIC          60 :             ascii_safe_strlcpy(buffer, activity,
  736 andres                   1026 CBC          60 :                                Min(buflen, pgstat_track_activity_query_size));
  736 andres                   1027 EUB             : 
  736 andres                   1028 GIC          60 :             return buffer;
                               1029                 :         }
                               1030                 : 
                               1031           58898 :         beentry++;
                               1032                 :     }
                               1033                 : 
                               1034                 :     /* PID not found */
  736 andres                   1035 CBC         778 :     return NULL;
  736 andres                   1036 ECB             : }
                               1037                 : 
  732 bruce                    1038                 : /* ----------
                               1039                 :  * pgstat_get_my_query_id() -
                               1040                 :  *
                               1041                 :  * Return current backend's query identifier.
                               1042                 :  */
                               1043                 : uint64
  719 bruce                    1044 GIC         363 : pgstat_get_my_query_id(void)
  732 bruce                    1045 ECB             : {
  732 bruce                    1046 GIC         363 :     if (!MyBEEntry)
                               1047              14 :         return 0;
                               1048                 : 
                               1049                 :     /*
                               1050                 :      * There's no need for a lock around pgstat_begin_read_activity /
                               1051                 :      * pgstat_end_read_activity here as it's only called from
                               1052                 :      * pg_stat_get_activity which is already protected, or from the same
                               1053                 :      * backend which means that there won't be concurrent writes.
  732 bruce                    1054 ECB             :      */
  719 bruce                    1055 GIC         349 :     return MyBEEntry->st_query_id;
  732 bruce                    1056 ECB             : }
                               1057                 : 
                               1058                 : /* ----------
                               1059                 :  * cmp_lbestatus
                               1060                 :  *
                               1061                 :  *  Comparison function for bsearch() on an array of LocalPgBackendStatus.
                               1062                 :  *  The backend_id field is used to compare the arguments.
                               1063                 :  * ----------
                               1064                 :  */
                               1065                 : static int
  192 tgl                      1066 GNC         107 : cmp_lbestatus(const void *a, const void *b)
                               1067                 : {
                               1068             107 :     const LocalPgBackendStatus *lbestatus1 = (const LocalPgBackendStatus *) a;
                               1069             107 :     const LocalPgBackendStatus *lbestatus2 = (const LocalPgBackendStatus *) b;
                               1070                 : 
                               1071             107 :     return lbestatus1->backend_id - lbestatus2->backend_id;
                               1072                 : }
                               1073                 : 
                               1074                 : /* ----------
                               1075                 :  * pgstat_fetch_stat_beentry() -
                               1076                 :  *
                               1077                 :  *  Support function for the SQL-callable pgstat* functions. Returns
                               1078                 :  *  our local copy of the current-activity entry for one backend,
                               1079                 :  *  or NULL if the given beid doesn't identify any known session.
                               1080                 :  *
                               1081                 :  *  The beid argument is the BackendId of the desired session
                               1082                 :  *  (note that this is unlike pgstat_fetch_stat_local_beentry()).
                               1083                 :  *
  736 andres                   1084 ECB             :  *  NB: caller is responsible for a check if the user is permitted to see
                               1085                 :  *  this info (especially the querystring).
                               1086                 :  * ----------
                               1087                 :  */
                               1088                 : PgBackendStatus *
  192 tgl                      1089 GNC          35 : pgstat_fetch_stat_beentry(BackendId beid)
                               1090                 : {
                               1091                 :     LocalPgBackendStatus key;
                               1092                 :     LocalPgBackendStatus *ret;
                               1093                 : 
  736 andres                   1094 GIC          35 :     pgstat_read_current_status();
                               1095                 : 
                               1096                 :     /*
                               1097                 :      * Since the localBackendStatusTable is in order by backend_id, we can use
                               1098                 :      * bsearch() to search it efficiently.
                               1099                 :      */
  192 tgl                      1100 GNC          35 :     key.backend_id = beid;
                               1101              35 :     ret = (LocalPgBackendStatus *) bsearch(&key, localBackendStatusTable,
                               1102                 :                                            localNumBackends,
                               1103                 :                                            sizeof(LocalPgBackendStatus),
                               1104                 :                                            cmp_lbestatus);
                               1105              35 :     if (ret)
                               1106              35 :         return &ret->backendStatus;
  736 andres                   1107 ECB             : 
  192 tgl                      1108 UNC           0 :     return NULL;
  736 andres                   1109 ECB             : }
                               1110                 : 
                               1111                 : 
                               1112                 : /* ----------
                               1113                 :  * pgstat_fetch_stat_local_beentry() -
                               1114                 :  *
                               1115                 :  *  Like pgstat_fetch_stat_beentry() but with locally computed additions (like
                               1116                 :  *  xid and xmin values of the backend)
                               1117                 :  *
                               1118                 :  *  The beid argument is a 1-based index in the localBackendStatusTable
                               1119                 :  *  (note that this is unlike pgstat_fetch_stat_beentry()).
                               1120                 :  *  Returns NULL if the argument is out of range (no current caller does that).
                               1121                 :  *
                               1122                 :  *  NB: caller is responsible for a check if the user is permitted to see
                               1123                 :  *  this info (especially the querystring).
                               1124                 :  * ----------
                               1125                 :  */
                               1126                 : LocalPgBackendStatus *
  736 andres                   1127 GIC        4288 : pgstat_fetch_stat_local_beentry(int beid)
                               1128                 : {
                               1129            4288 :     pgstat_read_current_status();
                               1130                 : 
                               1131            4288 :     if (beid < 1 || beid > localNumBackends)
  736 andres                   1132 UIC           0 :         return NULL;
                               1133                 : 
  736 andres                   1134 CBC        4288 :     return &localBackendStatusTable[beid - 1];
                               1135                 : }
                               1136                 : 
                               1137                 : 
                               1138                 : /* ----------
  736 andres                   1139 ECB             :  * pgstat_fetch_stat_numbackends() -
                               1140                 :  *
                               1141                 :  *  Support function for the SQL-callable pgstat* functions. Returns
                               1142                 :  *  the number of sessions known in the localBackendStatusTable, i.e.
                               1143                 :  *  the maximum 1-based index to pass to pgstat_fetch_stat_local_beentry().
                               1144                 :  * ----------
                               1145                 :  */
                               1146                 : int
  736 andres                   1147 CBC         618 : pgstat_fetch_stat_numbackends(void)
                               1148                 : {
  736 andres                   1149 GIC         618 :     pgstat_read_current_status();
                               1150                 : 
  736 andres                   1151 CBC         618 :     return localNumBackends;
  736 andres                   1152 ECB             : }
                               1153                 : 
  736 andres                   1154 EUB             : /*
                               1155                 :  * Convert a potentially unsafely truncated activity string (see
                               1156                 :  * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
                               1157                 :  * one.
                               1158                 :  *
                               1159                 :  * The returned string is allocated in the caller's memory context and may be
                               1160                 :  * freed.
                               1161                 :  */
                               1162                 : char *
  736 andres                   1163 GIC        4122 : pgstat_clip_activity(const char *raw_activity)
                               1164                 : {
                               1165                 :     char       *activity;
                               1166                 :     int         rawlen;
                               1167                 :     int         cliplen;
                               1168                 : 
                               1169                 :     /*
                               1170                 :      * Some callers, like pgstat_get_backend_current_activity(), do not
                               1171                 :      * guarantee that the buffer isn't concurrently modified. We try to take
                               1172                 :      * care that the buffer is always terminated by a NUL byte regardless, but
  736 andres                   1173 ECB             :      * let's still be paranoid about the string's length. In those cases the
                               1174                 :      * underlying buffer is guaranteed to be pgstat_track_activity_query_size
                               1175                 :      * large.
                               1176                 :      */
  736 andres                   1177 CBC        4122 :     activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
  736 andres                   1178 EUB             : 
                               1179                 :     /* now double-guaranteed to be NUL terminated */
  736 andres                   1180 CBC        4122 :     rawlen = strlen(activity);
                               1181                 : 
                               1182                 :     /*
                               1183                 :      * All supported server-encodings make it possible to determine the length
                               1184                 :      * of a multi-byte character from its first byte (this is not the case for
                               1185                 :      * client encodings, see GB18030). As st_activity is always stored using
                               1186                 :      * server encoding, this allows us to perform multi-byte aware truncation,
                               1187                 :      * even if the string earlier was truncated in the middle of a multi-byte
                               1188                 :      * character.
                               1189                 :      */
  736 andres                   1190 GIC        4122 :     cliplen = pg_mbcliplen(activity, rawlen,
                               1191                 :                            pgstat_track_activity_query_size - 1);
                               1192                 : 
  736 andres                   1193 CBC        4122 :     activity[cliplen] = '\0';
                               1194                 : 
                               1195            4122 :     return activity;
                               1196                 : }
        

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