LCOV - code coverage report
Current view: top level - src/backend/utils/activity - backend_status.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 96.5 % 347 335
Test Date: 2026-02-17 17:20:33 Functions: 100.0 % 25 25
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1