1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-11 10:01:57 +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:
Andres Freund
2021-04-03 11:42:52 -07:00
parent 8d3a4c3eae
commit e1025044cd
11 changed files with 1598 additions and 1392 deletions

View File

@ -12,11 +12,10 @@
#define PGSTAT_H
#include "datatype/timestamp.h"
#include "libpq/pqcomm.h"
#include "miscadmin.h"
#include "port/atomics.h"
#include "portability/instr_time.h"
#include "postmaster/pgarch.h"
#include "postmaster/pgarch.h" /* for MAX_XFN_CHARS */
#include "utils/backend_progress.h" /* for backward compatibility */
#include "utils/backend_status.h" /* for backward compatibility */
#include "utils/hsearch.h"
#include "utils/relcache.h"
#include "utils/wait_event.h" /* for backward compatibility */
@ -882,262 +881,6 @@ typedef struct PgStat_ReplSlotStats
TimestampTz stat_reset_timestamp;
} PgStat_ReplSlotStats;
/* ----------
* Backend states
* ----------
*/
typedef enum BackendState
{
STATE_UNDEFINED,
STATE_IDLE,
STATE_RUNNING,
STATE_IDLEINTRANSACTION,
STATE_FASTPATH,
STATE_IDLEINTRANSACTION_ABORTED,
STATE_DISABLED
} BackendState;
/* ----------
* Command type for progress reporting purposes
* ----------
*/
typedef enum ProgressCommandType
{
PROGRESS_COMMAND_INVALID,
PROGRESS_COMMAND_VACUUM,
PROGRESS_COMMAND_ANALYZE,
PROGRESS_COMMAND_CLUSTER,
PROGRESS_COMMAND_CREATE_INDEX,
PROGRESS_COMMAND_BASEBACKUP,
PROGRESS_COMMAND_COPY
} ProgressCommandType;
#define PGSTAT_NUM_PROGRESS_PARAM 20
/* ----------
* 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;
/*
* Working state needed to accumulate per-function-call timing statistics.
@ -1160,10 +903,8 @@ typedef struct PgStat_FunctionCallUsage
* GUC parameters
* ----------
*/
extern PGDLLIMPORT bool pgstat_track_activities;
extern PGDLLIMPORT bool pgstat_track_counts;
extern PGDLLIMPORT int pgstat_track_functions;
extern PGDLLIMPORT int pgstat_track_activity_query_size;
extern char *pgstat_stat_directory;
extern char *pgstat_stat_tmpname;
extern char *pgstat_stat_filename;
@ -1184,6 +925,14 @@ extern PgStat_MsgWal WalStats;
extern PgStat_Counter pgStatBlockReadTime;
extern PgStat_Counter pgStatBlockWriteTime;
/*
* Updated by pgstat_count_conn_*_time macros, called by
* pgstat_report_activity().
*/
extern PgStat_Counter pgStatActiveTime;
extern PgStat_Counter pgStatTransactionIdleTime;
/*
* Updated by the traffic cop and in errfinish()
*/
@ -1193,9 +942,6 @@ extern SessionEndType pgStatSessionEndCause;
* Functions called from postmaster
* ----------
*/
extern Size BackendStatusShmemSize(void);
extern void CreateSharedBackendStatus(void);
extern void pgstat_init(void);
extern int pgstat_start(void);
extern void pgstat_reset_all(void);
@ -1241,30 +987,13 @@ extern void pgstat_report_replslot(const char *slotname, PgStat_Counter spilltxn
extern void pgstat_report_replslot_drop(const char *slotname);
extern void pgstat_initialize(void);
extern void pgstat_bestart(void);
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);
extern void pgstat_progress_start_command(ProgressCommandType cmdtype,
Oid relid);
extern void pgstat_progress_update_param(int index, int64 val);
extern void pgstat_progress_update_multi_param(int nparam, const int *index,
const int64 *val);
extern void pgstat_progress_end_command(void);
extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id);
extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id);
extern void pgstat_initstats(Relation rel);
extern char *pgstat_clip_activity(const char *raw_activity);
/* nontransactional event counts are simple enough to inline */
#define pgstat_count_heap_scan(rel) \
@ -1306,6 +1035,10 @@ extern char *pgstat_clip_activity(const char *raw_activity);
(pgStatBlockReadTime += (n))
#define pgstat_count_buffer_write_time(n) \
(pgStatBlockWriteTime += (n))
#define pgstat_count_conn_active_time(n) \
(pgStatActiveTime += (n))
#define pgstat_count_conn_txn_idle_time(n) \
(pgStatTransactionIdleTime += (n))
extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
extern void pgstat_count_heap_update(Relation rel, bool hot);
@ -1342,10 +1075,7 @@ extern bool pgstat_send_wal(bool force);
*/
extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
extern PgBackendStatus *pgstat_fetch_stat_beentry(int beid);
extern LocalPgBackendStatus *pgstat_fetch_stat_local_beentry(int beid);
extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
extern int pgstat_fetch_stat_numbackends(void);
extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
extern PgStat_GlobalStats *pgstat_fetch_global(void);
extern PgStat_WalStats *pgstat_fetch_stat_wal(void);