/* ---------- * backend_status.h * Definitions related to backend status reporting * * Copyright (c) 2001-2021, PostgreSQL Global Development Group * * src/include/utils/backend_status.h * ---------- */ #ifndef BACKEND_STATUS_H #define BACKEND_STATUS_H #include "datatype/timestamp.h" #include "libpq/pqcomm.h" #include "miscadmin.h" /* for BackendType */ #include "utils/backend_progress.h" /* ---------- * Backend states * ---------- */ typedef enum BackendState { STATE_UNDEFINED, STATE_IDLE, STATE_RUNNING, STATE_IDLEINTRANSACTION, STATE_FASTPATH, STATE_IDLEINTRANSACTION_ABORTED, STATE_DISABLED } BackendState; /* ---------- * Shared-memory data structures * ---------- */ /* * PgBackendSSLStatus * * For each backend, we keep the SSL status in a separate struct, that * is only filled in if SSL is enabled. * * All char arrays must be null-terminated. */ typedef struct PgBackendSSLStatus { /* Information about SSL connection */ int ssl_bits; char ssl_version[NAMEDATALEN]; char ssl_cipher[NAMEDATALEN]; char ssl_client_dn[NAMEDATALEN]; /* * serial number is max "20 octets" per RFC 5280, so this size should be * fine */ char ssl_client_serial[NAMEDATALEN]; char ssl_issuer_dn[NAMEDATALEN]; } PgBackendSSLStatus; /* * PgBackendGSSStatus * * For each backend, we keep the GSS status in a separate struct, that * is only filled in if GSS is enabled. * * All char arrays must be null-terminated. */ typedef struct PgBackendGSSStatus { /* Information about GSSAPI connection */ char gss_princ[NAMEDATALEN]; /* GSSAPI Principal used to auth */ bool gss_auth; /* If GSSAPI authentication was used */ bool gss_enc; /* If encryption is being used */ } PgBackendGSSStatus; /* ---------- * PgBackendStatus * * Each live backend maintains a PgBackendStatus struct in shared memory * showing its current activity. (The structs are allocated according to * BackendId, but that is not critical.) Note that the collector process * has no involvement in, or even access to, these structs. * * Each auxiliary process also maintains a PgBackendStatus struct in shared * memory. * ---------- */ typedef struct PgBackendStatus { /* * To avoid locking overhead, we use the following protocol: a backend * increments st_changecount before modifying its entry, and again after * finishing a modification. A would-be reader should note the value of * st_changecount, copy the entry into private memory, then check * st_changecount again. If the value hasn't changed, and if it's even, * the copy is valid; otherwise start over. This makes updates cheap * while reads are potentially expensive, but that's the tradeoff we want. * * The above protocol needs memory barriers to ensure that the apparent * order of execution is as it desires. Otherwise, for example, the CPU * might rearrange the code so that st_changecount is incremented twice * before the modification on a machine with weak memory ordering. Hence, * use the macros defined below for manipulating st_changecount, rather * than touching it directly. */ int st_changecount; /* The entry is valid iff st_procpid > 0, unused if st_procpid == 0 */ int st_procpid; /* Type of backends */ BackendType st_backendType; /* Times when current backend, transaction, and activity started */ TimestampTz st_proc_start_timestamp; TimestampTz st_xact_start_timestamp; TimestampTz st_activity_start_timestamp; TimestampTz st_state_start_timestamp; /* Database OID, owning user's OID, connection client address */ Oid st_databaseid; Oid st_userid; SockAddr st_clientaddr; char *st_clienthostname; /* MUST be null-terminated */ /* Information about SSL connection */ bool st_ssl; PgBackendSSLStatus *st_sslstatus; /* Information about GSSAPI connection */ bool st_gss; PgBackendGSSStatus *st_gssstatus; /* current state */ BackendState st_state; /* application name; MUST be null-terminated */ char *st_appname; /* * Current command string; MUST be null-terminated. Note that this string * possibly is truncated in the middle of a multi-byte character. As * activity strings are stored more frequently than read, that allows to * move the cost of correct truncation to the display side. Use * pgstat_clip_activity() to truncate correctly. */ char *st_activity_raw; /* * Command progress reporting. Any command which wishes can advertise * that it is running by setting st_progress_command, * st_progress_command_target, and st_progress_param[]. * st_progress_command_target should be the OID of the relation which the * command targets (we assume there's just one, as this is meant for * utility commands), but the meaning of each element in the * st_progress_param array is command-specific. */ ProgressCommandType st_progress_command; Oid st_progress_command_target; int64 st_progress_param[PGSTAT_NUM_PROGRESS_PARAM]; /* query identifier, optionally computed using post_parse_analyze_hook */ uint64 st_query_id; } PgBackendStatus; /* * Macros to load and store st_changecount with appropriate memory barriers. * * Use PGSTAT_BEGIN_WRITE_ACTIVITY() before, and PGSTAT_END_WRITE_ACTIVITY() * after, modifying the current process's PgBackendStatus data. Note that, * since there is no mechanism for cleaning up st_changecount after an error, * THESE MACROS FORM A CRITICAL SECTION. Any error between them will be * promoted to PANIC, causing a database restart to clean up shared memory! * Hence, keep the critical section as short and straight-line as possible. * Aside from being safer, that minimizes the window in which readers will * have to loop. * * Reader logic should follow this sketch: * * for (;;) * { * int before_ct, after_ct; * * pgstat_begin_read_activity(beentry, before_ct); * ... copy beentry data to local memory ... * pgstat_end_read_activity(beentry, after_ct); * if (pgstat_read_activity_complete(before_ct, after_ct)) * break; * CHECK_FOR_INTERRUPTS(); * } * * For extra safety, we generally use volatile beentry pointers, although * the memory barriers should theoretically be sufficient. */ #define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry) \ do { \ START_CRIT_SECTION(); \ (beentry)->st_changecount++; \ pg_write_barrier(); \ } while (0) #define PGSTAT_END_WRITE_ACTIVITY(beentry) \ do { \ pg_write_barrier(); \ (beentry)->st_changecount++; \ Assert(((beentry)->st_changecount & 1) == 0); \ END_CRIT_SECTION(); \ } while (0) #define pgstat_begin_read_activity(beentry, before_changecount) \ do { \ (before_changecount) = (beentry)->st_changecount; \ pg_read_barrier(); \ } while (0) #define pgstat_end_read_activity(beentry, after_changecount) \ do { \ pg_read_barrier(); \ (after_changecount) = (beentry)->st_changecount; \ } while (0) #define pgstat_read_activity_complete(before_changecount, after_changecount) \ ((before_changecount) == (after_changecount) && \ ((before_changecount) & 1) == 0) /* ---------- * LocalPgBackendStatus * * When we build the backend status array, we use LocalPgBackendStatus to be * able to add new values to the struct when needed without adding new fields * to the shared memory. It contains the backend status as a first member. * ---------- */ typedef struct LocalPgBackendStatus { /* * Local version of the backend status entry. */ PgBackendStatus backendStatus; /* * The xid of the current transaction if available, InvalidTransactionId * if not. */ TransactionId backend_xid; /* * The xmin of the current session if available, InvalidTransactionId if * not. */ TransactionId backend_xmin; } LocalPgBackendStatus; /* ---------- * GUC parameters * ---------- */ extern PGDLLIMPORT bool pgstat_track_activities; extern PGDLLIMPORT int pgstat_track_activity_query_size; /* ---------- * Other global variables * ---------- */ extern PGDLLIMPORT PgBackendStatus *MyBEEntry; /* ---------- * Functions called from postmaster * ---------- */ extern Size BackendStatusShmemSize(void); extern void CreateSharedBackendStatus(void); /* ---------- * Functions called from backends * ---------- */ /* Initialization functions */ extern void pgstat_beinit(void); extern void pgstat_bestart(void); extern void pgstat_clear_backend_activity_snapshot(void); /* Activity reporting functions */ extern void pgstat_report_activity(BackendState state, const char *cmd_str); extern void pgstat_report_query_id(uint64 query_id, bool force); extern void pgstat_report_tempfile(size_t filesize); extern void pgstat_report_appname(const char *appname); extern void pgstat_report_xact_timestamp(TimestampTz tstamp); extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser); extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen); extern uint64 pgstat_get_my_query_id(void); /* ---------- * Support functions for the SQL-callable functions to * generate the pgstat* views. * ---------- */ extern int pgstat_fetch_stat_numbackends(void); extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid); extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid); extern char *pgstat_clip_activity(const char *raw_activity); #endif /* BACKEND_STATUS_H */