mirror of
https://github.com/postgres/postgres.git
synced 2025-12-21 05:21:08 +03:00
Split backend status and progress related functionality out of pgstat.c.
Backend status (supporting pg_stat_activity) and command
progress (supporting pg_stat_progress*) related code is largely
independent from the rest of pgstat.[ch] (supporting views like
pg_stat_all_tables that accumulate data over time). See also
a333476b92.
This commit doesn't rename the function names to make the distinction
from the rest of pgstat_ clearer - that'd be more invasive and not
clearly beneficial. If we were to decide to do such a rename at some
point, it's better done separately from moving the code as well.
Robert's review was of an earlier version.
Reviewed-By: Robert Haas <robertmhaas@gmail.com>
Discussion: https://postgr.es/m/20210316195440.twxmlov24rr2nxrg@alap3.anarazel.de
This commit is contained in:
316
src/include/utils/backend_status.h
Normal file
316
src/include/utils/backend_status.h
Normal file
@@ -0,0 +1,316 @@
|
||||
/* ----------
|
||||
* 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];
|
||||
} 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_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);
|
||||
|
||||
|
||||
/* ----------
|
||||
* 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 */
|
||||
Reference in New Issue
Block a user