LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - backend_status.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.9 % 339 315 1 1 7 15 2 39 11 263 7 51
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 20 20 6 3 11 8
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

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