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

Generated by: LCOV version 2.0-1