|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* pgstatfuncs.c
|
|
|
|
* Functions for accessing the statistics collector data
|
|
|
|
*
|
|
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/utils/adt/pgstatfuncs.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
#include "access/htup_details.h"
|
|
|
|
#include "access/xlog.h"
|
|
|
|
#include "catalog/pg_authid.h"
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "common/ip.h"
|
|
|
|
#include "funcapi.h"
|
|
|
|
#include "miscadmin.h"
|
|
|
|
#include "pgstat.h"
|
|
|
|
#include "postmaster/bgworker_internals.h"
|
|
|
|
#include "postmaster/postmaster.h"
|
|
|
|
#include "storage/proc.h"
|
|
|
|
#include "storage/procarray.h"
|
|
|
|
#include "utils/acl.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/inet.h"
|
|
|
|
#include "utils/timestamp.h"
|
|
|
|
|
|
|
|
#define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var))))
|
|
|
|
|
|
|
|
#define HAS_PGSTAT_PERMISSIONS(role) (is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
|
|
|
|
|
|
|
|
/* Global bgwriter statistics, from bgwriter.c */
|
|
|
|
extern PgStat_MsgBgWriter bgwriterStats;
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_numscans(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->numscans);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_returned);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_inserted);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_updated(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_updated);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_deleted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_deleted);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_tuples_hot_updated(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->tuples_hot_updated);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_live_tuples(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->n_live_tuples);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_dead_tuples(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->n_dead_tuples);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_mod_since_analyze(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->changes_since_analyze);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Trigger autovacuum based on number of INSERTs
Traditionally autovacuum has only ever invoked a worker based on the
estimated number of dead tuples in a table and for anti-wraparound
purposes. For the latter, with certain classes of tables such as
insert-only tables, anti-wraparound vacuums could be the first vacuum that
the table ever receives. This could often lead to autovacuum workers being
busy for extended periods of time due to having to potentially freeze
every page in the table. This could be particularly bad for very large
tables. New clusters, or recently pg_restored clusters could suffer even
more as many large tables may have the same relfrozenxid, which could
result in large numbers of tables requiring an anti-wraparound vacuum all
at once.
Here we aim to reduce the work required by anti-wraparound and aggressive
vacuums in general, by triggering autovacuum when the table has received
enough INSERTs. This is controlled by adding two new GUCs and reloptions;
autovacuum_vacuum_insert_threshold and
autovacuum_vacuum_insert_scale_factor. These work exactly the same as the
existing scale factor and threshold controls, only base themselves off the
number of inserts since the last vacuum, rather than the number of dead
tuples. New controls were added rather than reusing the existing
controls, to allow these new vacuums to be tuned independently and perhaps
even completely disabled altogether, which can be done by setting
autovacuum_vacuum_insert_threshold to -1.
We make no attempt to skip index cleanup operations on these vacuums as
they may trigger for an insert-mostly table which continually doesn't have
enough dead tuples to trigger an autovacuum for the purpose of removing
those dead tuples. If we were to skip cleaning the indexes in this case,
then it is possible for the index(es) to become bloated over time.
There are additional benefits to triggering autovacuums based on inserts,
as tables which never contain enough dead tuples to trigger an autovacuum
are now more likely to receive a vacuum, which can mark more of the table
as "allvisible" and encourage the query planner to make use of Index Only
Scans.
Currently, we still obey vacuum_freeze_min_age when triggering these new
autovacuums based on INSERTs. For large insert-only tables, it may be
beneficial to lower the table's autovacuum_freeze_min_age so that tuples
are eligible to be frozen sooner. Here we've opted not to zero that for
these types of vacuums, since the table may just be insert-mostly and we
may otherwise freeze tuples that are still destined to be updated or
removed in the near future.
There was some debate to what exactly the new scale factor and threshold
should default to. For now, these are set to 0.2 and 1000, respectively.
There may be some motivation to adjust these before the release.
Author: Laurenz Albe, Darafei Praliaskouski
Reviewed-by: Alvaro Herrera, Masahiko Sawada, Chris Travers, Andres Freund, Justin Pryzby
Discussion: https://postgr.es/m/CAC8Q8t%2Bj36G_bLF%3D%2B0iMo6jGNWnLnWb1tujXuJr-%2Bx8ZCCTqoQ%40mail.gmail.com
5 years ago
|
|
|
Datum
|
|
|
|
pg_stat_get_ins_since_vacuum(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->inserts_since_vacuum);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_blocks_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->blocks_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_blocks_hit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->blocks_hit);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_last_vacuum_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = tabentry->vacuum_timestamp;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_last_autovacuum_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = tabentry->autovac_vacuum_timestamp;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_last_analyze_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = tabentry->analyze_timestamp;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_last_autoanalyze_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = tabentry->autovac_analyze_timestamp;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_vacuum_count(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->vacuum_count);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_autovacuum_count(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->autovac_vacuum_count);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_analyze_count(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->analyze_count);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_autoanalyze_count(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatTabEntry *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->autovac_analyze_count);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_function_calls(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_StatFuncEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_INT64(funcentry->f_numcalls);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_function_total_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_StatFuncEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
PG_RETURN_FLOAT8(((double) funcentry->f_total_time) / 1000.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_function_self_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_StatFuncEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = pgstat_fetch_stat_funcentry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
PG_RETURN_FLOAT8(((double) funcentry->f_self_time) / 1000.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
int *fctx;
|
|
|
|
int32 result;
|
|
|
|
|
|
|
|
/* stuff done only on the first call of the function */
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
{
|
|
|
|
/* create a function context for cross-call persistence */
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
|
|
|
|
fctx = MemoryContextAlloc(funcctx->multi_call_memory_ctx,
|
|
|
|
2 * sizeof(int));
|
|
|
|
funcctx->user_fctx = fctx;
|
|
|
|
|
|
|
|
fctx[0] = 0;
|
|
|
|
fctx[1] = pgstat_fetch_stat_numbackends();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* stuff done on every call of the function */
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
|
|
|
fctx = funcctx->user_fctx;
|
|
|
|
|
|
|
|
fctx[0] += 1;
|
|
|
|
result = fctx[0];
|
|
|
|
|
|
|
|
if (result <= fctx[1])
|
|
|
|
{
|
|
|
|
/* do when there is more left to send */
|
|
|
|
SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* do when there is no more left */
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
/*
|
|
|
|
* Returns command progress information for the named command.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_stat_get_progress_info(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
#define PG_STAT_GET_PROGRESS_COLS PGSTAT_NUM_PROGRESS_PARAM + 3
|
|
|
|
int num_backends = pgstat_fetch_stat_numbackends();
|
|
|
|
int curr_backend;
|
|
|
|
char *cmd = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
|
|
ProgressCommandType cmdtype;
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
TupleDesc tupdesc;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
/* Translate command name into command type code. */
|
|
|
|
if (pg_strcasecmp(cmd, "VACUUM") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_VACUUM;
|
|
|
|
else if (pg_strcasecmp(cmd, "ANALYZE") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_ANALYZE;
|
|
|
|
else if (pg_strcasecmp(cmd, "CLUSTER") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_CLUSTER;
|
Report progress of CREATE INDEX operations
This uses the progress reporting infrastructure added by c16dc1aca5e0,
adding support for CREATE INDEX and CREATE INDEX CONCURRENTLY.
There are two pieces to this: one is index-AM-agnostic, and the other is
AM-specific. The latter is fairly elaborate for btrees, including
reportage for parallel index builds and the separate phases that btree
index creation uses; other index AMs, which are much simpler in their
building procedures, have simplistic reporting only, but that seems
sufficient, at least for non-concurrent builds.
The index-AM-agnostic part is fairly complete, providing insight into
the CONCURRENTLY wait phases as well as block-based progress during the
index validation table scan. (The index validation index scan requires
patching each AM, which has not been included here.)
Reviewers: Rahila Syed, Pavan Deolasee, Tatsuro Yamada
Discussion: https://postgr.es/m/20181220220022.mg63bhk26zdpvmcj@alvherre.pgsql
6 years ago
|
|
|
else if (pg_strcasecmp(cmd, "CREATE INDEX") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_CREATE_INDEX;
|
|
|
|
else if (pg_strcasecmp(cmd, "BASEBACKUP") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_BASEBACKUP;
|
|
|
|
else if (pg_strcasecmp(cmd, "COPY") == 0)
|
|
|
|
cmdtype = PROGRESS_COMMAND_COPY;
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
errmsg("invalid command name: \"%s\"", cmd)));
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
/* 1-based index */
|
|
|
|
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
|
|
|
|
{
|
|
|
|
LocalPgBackendStatus *local_beentry;
|
|
|
|
PgBackendStatus *beentry;
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
Datum values[PG_STAT_GET_PROGRESS_COLS];
|
|
|
|
bool nulls[PG_STAT_GET_PROGRESS_COLS];
|
|
|
|
int i;
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
|
|
|
|
|
|
|
|
if (!local_beentry)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
beentry = &local_beentry->backendStatus;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Report values for only those backends which are running the given
|
|
|
|
* command.
|
|
|
|
*/
|
|
|
|
if (!beentry || beentry->st_progress_command != cmdtype)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Value available to all callers */
|
|
|
|
values[0] = Int32GetDatum(beentry->st_procpid);
|
|
|
|
values[1] = ObjectIdGetDatum(beentry->st_databaseid);
|
|
|
|
|
|
|
|
/* show rest of the values including relid only to role members */
|
|
|
|
if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
{
|
|
|
|
values[2] = ObjectIdGetDatum(beentry->st_progress_command_target);
|
|
|
|
for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
|
|
|
|
values[i + 3] = Int64GetDatum(beentry->st_progress_param[i]);
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nulls[2] = true;
|
|
|
|
for (i = 0; i < PGSTAT_NUM_PROGRESS_PARAM; i++)
|
|
|
|
nulls[i + 3] = true;
|
Add a generic command progress reporting facility.
Using this facility, any utility command can report the target relation
upon which it is operating, if there is one, and up to 10 64-bit
counters; the intent of this is that users should be able to figure out
what a utility command is doing without having to resort to ugly hacks
like attaching strace to a backend.
As a demonstration, this adds very crude reporting to lazy vacuum; we
just report the target relation and nothing else. A forthcoming patch
will make VACUUM report a bunch of additional data that will make this
much more interesting. But this gets the basic framework in place.
Vinayak Pokale, Rahila Syed, Amit Langote, Robert Haas, reviewed by
Kyotaro Horiguchi, Jim Nasby, Thom Brown, Masahiko Sawada, Fujii Masao,
and Masanori Oyama.
9 years ago
|
|
|
}
|
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up and return the tuplestore */
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns activity of PG backends.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_stat_get_activity(PG_FUNCTION_ARGS)
|
|
|
|
{
|
Make use of in-core query id added by commit 5fd9dfa5f5
Use the in-core query id computation for pg_stat_activity,
log_line_prefix, and EXPLAIN VERBOSE.
Similar to other fields in pg_stat_activity, only the queryid from the
top level statements are exposed, and if the backends status isn't
active then the queryid from the last executed statements is displayed.
Add a %Q placeholder to include the queryid in log_line_prefix, which
will also only expose top level statements.
For EXPLAIN VERBOSE, if a query identifier has been computed, either by
enabling compute_query_id or using a third-party module, display it.
Bump catalog version.
Discussion: https://postgr.es/m/20210407125726.tkvjdbw76hxnpwfi@nol
Author: Julien Rouhaud
Reviewed-by: Alvaro Herrera, Nitin Jadhav, Zhihong Yu
4 years ago
|
|
|
#define PG_STAT_GET_ACTIVITY_COLS 30
|
|
|
|
int num_backends = pgstat_fetch_stat_numbackends();
|
|
|
|
int curr_backend;
|
|
|
|
int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
/* 1-based index */
|
|
|
|
for (curr_backend = 1; curr_backend <= num_backends; curr_backend++)
|
|
|
|
{
|
|
|
|
/* for each row */
|
|
|
|
Datum values[PG_STAT_GET_ACTIVITY_COLS];
|
|
|
|
bool nulls[PG_STAT_GET_ACTIVITY_COLS];
|
|
|
|
LocalPgBackendStatus *local_beentry;
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
PGPROC *proc;
|
|
|
|
const char *wait_event_type = NULL;
|
|
|
|
const char *wait_event = NULL;
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
/* Get the next one in the list */
|
|
|
|
local_beentry = pgstat_fetch_stat_local_beentry(curr_backend);
|
|
|
|
if (!local_beentry)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Ignore missing entries if looking for specific PID */
|
|
|
|
if (pid != -1)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (i = 0; i < lengthof(nulls); i++)
|
|
|
|
nulls[i] = true;
|
|
|
|
|
|
|
|
nulls[5] = false;
|
|
|
|
values[5] = CStringGetTextDatum("<backend information not available>");
|
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
beentry = &local_beentry->backendStatus;
|
|
|
|
|
|
|
|
/* If looking for specific PID, ignore all the others */
|
|
|
|
if (pid != -1 && beentry->st_procpid != pid)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Values available to all callers */
|
|
|
|
if (beentry->st_databaseid != InvalidOid)
|
|
|
|
values[0] = ObjectIdGetDatum(beentry->st_databaseid);
|
|
|
|
else
|
|
|
|
nulls[0] = true;
|
|
|
|
|
|
|
|
values[1] = Int32GetDatum(beentry->st_procpid);
|
|
|
|
|
|
|
|
if (beentry->st_userid != InvalidOid)
|
|
|
|
values[2] = ObjectIdGetDatum(beentry->st_userid);
|
|
|
|
else
|
|
|
|
nulls[2] = true;
|
|
|
|
|
|
|
|
if (beentry->st_appname)
|
|
|
|
values[3] = CStringGetTextDatum(beentry->st_appname);
|
|
|
|
else
|
|
|
|
nulls[3] = true;
|
|
|
|
|
|
|
|
if (TransactionIdIsValid(local_beentry->backend_xid))
|
|
|
|
values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
|
|
|
|
else
|
|
|
|
nulls[15] = true;
|
|
|
|
|
|
|
|
if (TransactionIdIsValid(local_beentry->backend_xmin))
|
|
|
|
values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
|
|
|
|
else
|
|
|
|
nulls[16] = true;
|
|
|
|
|
|
|
|
/* Values only available to role member or pg_read_all_stats */
|
|
|
|
if (HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
{
|
|
|
|
SockAddr zero_clientaddr;
|
|
|
|
char *clipped_activity;
|
|
|
|
|
|
|
|
switch (beentry->st_state)
|
|
|
|
{
|
|
|
|
case STATE_IDLE:
|
|
|
|
values[4] = CStringGetTextDatum("idle");
|
|
|
|
break;
|
|
|
|
case STATE_RUNNING:
|
|
|
|
values[4] = CStringGetTextDatum("active");
|
|
|
|
break;
|
|
|
|
case STATE_IDLEINTRANSACTION:
|
|
|
|
values[4] = CStringGetTextDatum("idle in transaction");
|
|
|
|
break;
|
|
|
|
case STATE_FASTPATH:
|
|
|
|
values[4] = CStringGetTextDatum("fastpath function call");
|
|
|
|
break;
|
|
|
|
case STATE_IDLEINTRANSACTION_ABORTED:
|
|
|
|
values[4] = CStringGetTextDatum("idle in transaction (aborted)");
|
|
|
|
break;
|
|
|
|
case STATE_DISABLED:
|
|
|
|
values[4] = CStringGetTextDatum("disabled");
|
|
|
|
break;
|
|
|
|
case STATE_UNDEFINED:
|
|
|
|
nulls[4] = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
clipped_activity = pgstat_clip_activity(beentry->st_activity_raw);
|
|
|
|
values[5] = CStringGetTextDatum(clipped_activity);
|
|
|
|
pfree(clipped_activity);
|
|
|
|
|
|
|
|
/* leader_pid */
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
nulls[28] = true;
|
|
|
|
|
|
|
|
proc = BackendPidGetProc(beentry->st_procpid);
|
|
|
|
|
|
|
|
if (proc == NULL && (beentry->st_backendType != B_BACKEND))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For an auxiliary process, retrieve process info from
|
|
|
|
* AuxiliaryProcs stored in shared-memory.
|
|
|
|
*/
|
|
|
|
proc = AuxiliaryPidGetProc(beentry->st_procpid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a PGPROC entry was retrieved, display wait events and lock
|
|
|
|
* group leader information if any. To avoid extra overhead, no
|
|
|
|
* extra lock is being held, so there is no guarantee of
|
|
|
|
* consistency across multiple rows.
|
|
|
|
*/
|
|
|
|
if (proc != NULL)
|
|
|
|
{
|
|
|
|
uint32 raw_wait_event;
|
|
|
|
PGPROC *leader;
|
|
|
|
|
|
|
|
raw_wait_event = UINT32_ACCESS_ONCE(proc->wait_event_info);
|
|
|
|
wait_event_type = pgstat_get_wait_event_type(raw_wait_event);
|
|
|
|
wait_event = pgstat_get_wait_event(raw_wait_event);
|
|
|
|
|
|
|
|
leader = proc->lockGroupLeader;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show the leader only for active parallel workers. This
|
|
|
|
* leaves the field as NULL for the leader of a parallel
|
|
|
|
* group.
|
|
|
|
*/
|
|
|
|
if (leader && leader->pid != beentry->st_procpid)
|
|
|
|
{
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[28] = Int32GetDatum(leader->pid);
|
|
|
|
nulls[28] = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wait_event_type)
|
|
|
|
values[6] = CStringGetTextDatum(wait_event_type);
|
|
|
|
else
|
|
|
|
nulls[6] = true;
|
|
|
|
|
|
|
|
if (wait_event)
|
|
|
|
values[7] = CStringGetTextDatum(wait_event);
|
|
|
|
else
|
|
|
|
nulls[7] = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't expose transaction time for walsenders; it confuses
|
|
|
|
* monitoring, particularly because we don't keep the time up-to-
|
|
|
|
* date.
|
|
|
|
*/
|
|
|
|
if (beentry->st_xact_start_timestamp != 0 &&
|
|
|
|
beentry->st_backendType != B_WAL_SENDER)
|
|
|
|
values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
|
|
|
|
else
|
|
|
|
nulls[8] = true;
|
|
|
|
|
|
|
|
if (beentry->st_activity_start_timestamp != 0)
|
|
|
|
values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
|
|
|
|
else
|
|
|
|
nulls[9] = true;
|
|
|
|
|
|
|
|
if (beentry->st_proc_start_timestamp != 0)
|
|
|
|
values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
|
|
|
|
else
|
|
|
|
nulls[10] = true;
|
|
|
|
|
|
|
|
if (beentry->st_state_start_timestamp != 0)
|
|
|
|
values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
|
|
|
|
else
|
|
|
|
nulls[11] = true;
|
|
|
|
|
|
|
|
/* A zeroed client addr means we don't know */
|
|
|
|
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
|
|
|
|
if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
|
|
|
|
sizeof(zero_clientaddr)) == 0)
|
|
|
|
{
|
|
|
|
nulls[12] = true;
|
|
|
|
nulls[13] = true;
|
|
|
|
nulls[14] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (beentry->st_clientaddr.addr.ss_family == AF_INET
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
|| beentry->st_clientaddr.addr.ss_family == AF_INET6
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
char remote_host[NI_MAXHOST];
|
|
|
|
char remote_port[NI_MAXSERV];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
remote_host[0] = '\0';
|
|
|
|
remote_port[0] = '\0';
|
|
|
|
ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
|
|
|
|
beentry->st_clientaddr.salen,
|
|
|
|
remote_host, sizeof(remote_host),
|
|
|
|
remote_port, sizeof(remote_port),
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV);
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
|
|
|
|
values[12] = DirectFunctionCall1(inet_in,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
8 years ago
|
|
|
CStringGetDatum(remote_host));
|
|
|
|
if (beentry->st_clienthostname &&
|
|
|
|
beentry->st_clienthostname[0])
|
|
|
|
values[13] = CStringGetTextDatum(beentry->st_clienthostname);
|
|
|
|
else
|
|
|
|
nulls[13] = true;
|
|
|
|
values[14] = Int32GetDatum(atoi(remote_port));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nulls[12] = true;
|
|
|
|
nulls[13] = true;
|
|
|
|
nulls[14] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Unix sockets always reports NULL for host and -1 for
|
|
|
|
* port, so it's possible to tell the difference to
|
|
|
|
* connections we have no permissions to view, or with
|
|
|
|
* errors.
|
|
|
|
*/
|
|
|
|
nulls[12] = true;
|
|
|
|
nulls[13] = true;
|
|
|
|
values[14] = Int32GetDatum(-1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Unknown address type, should never happen */
|
|
|
|
nulls[12] = true;
|
|
|
|
nulls[13] = true;
|
|
|
|
nulls[14] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Add backend type */
|
|
|
|
if (beentry->st_backendType == B_BG_WORKER)
|
|
|
|
{
|
|
|
|
const char *bgw_type;
|
|
|
|
|
|
|
|
bgw_type = GetBackgroundWorkerTypeByPid(beentry->st_procpid);
|
|
|
|
if (bgw_type)
|
|
|
|
values[17] = CStringGetTextDatum(bgw_type);
|
|
|
|
else
|
|
|
|
nulls[17] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
values[17] =
|
|
|
|
CStringGetTextDatum(GetBackendTypeDesc(beentry->st_backendType));
|
|
|
|
|
|
|
|
/* SSL information */
|
|
|
|
if (beentry->st_ssl)
|
|
|
|
{
|
|
|
|
values[18] = BoolGetDatum(true); /* ssl */
|
|
|
|
values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
|
|
|
|
values[20] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
|
|
|
|
values[21] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
|
|
|
|
|
|
|
|
if (beentry->st_sslstatus->ssl_client_dn[0])
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_client_dn);
|
|
|
|
else
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
nulls[22] = true;
|
|
|
|
|
|
|
|
if (beentry->st_sslstatus->ssl_client_serial[0])
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[23] = DirectFunctionCall3(numeric_in,
|
|
|
|
CStringGetDatum(beentry->st_sslstatus->ssl_client_serial),
|
|
|
|
ObjectIdGetDatum(InvalidOid),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
else
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
nulls[23] = true;
|
|
|
|
|
|
|
|
if (beentry->st_sslstatus->ssl_issuer_dn[0])
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[24] = CStringGetTextDatum(beentry->st_sslstatus->ssl_issuer_dn);
|
|
|
|
else
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
nulls[24] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
values[18] = BoolGetDatum(false); /* ssl */
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
nulls[19] = nulls[20] = nulls[21] = nulls[22] = nulls[23] = nulls[24] = true;
|
|
|
|
}
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
6 years ago
|
|
|
|
|
|
|
/* GSSAPI information */
|
|
|
|
if (beentry->st_gss)
|
|
|
|
{
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[25] = BoolGetDatum(beentry->st_gssstatus->gss_auth); /* gss_auth */
|
|
|
|
values[26] = CStringGetTextDatum(beentry->st_gssstatus->gss_princ);
|
|
|
|
values[27] = BoolGetDatum(beentry->st_gssstatus->gss_enc); /* GSS Encryption in use */
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
6 years ago
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Remove support for SSL compression
PostgreSQL disabled compression as of e3bdb2d and the documentation
recommends against using it since. Additionally, SSL compression has
been disabled in OpenSSL since version 1.1.0, and was disabled in many
distributions long before that. The most recent TLS version, TLSv1.3,
disallows compression at the protocol level.
This commit removes the feature itself, removing support for the libpq
parameter sslcompression (parameter still listed for compatibility
reasons with existing connection strings, just ignored), and removes
the equivalent field in pg_stat_ssl and de facto PgBackendSSLStatus.
Note that, on top of removing the ability to activate compression by
configuration, compression is actively disabled in both frontend and
backend to avoid overrides from local configurations.
A TAP test is added for deprecated SSL parameters to check after
backwards compatibility.
Bump catalog version.
Author: Daniel Gustafsson
Reviewed-by: Peter Eisentraut, Magnus Hagander, Michael Paquier
Discussion: https://postgr.es/m/7E384D48-11C5-441B-9EC3-F7DB1F8518F6@yesql.se
4 years ago
|
|
|
values[25] = BoolGetDatum(false); /* gss_auth */
|
|
|
|
nulls[26] = true; /* No GSS principal */
|
|
|
|
values[27] = BoolGetDatum(false); /* GSS Encryption not in
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
6 years ago
|
|
|
* use */
|
|
|
|
}
|
Make use of in-core query id added by commit 5fd9dfa5f5
Use the in-core query id computation for pg_stat_activity,
log_line_prefix, and EXPLAIN VERBOSE.
Similar to other fields in pg_stat_activity, only the queryid from the
top level statements are exposed, and if the backends status isn't
active then the queryid from the last executed statements is displayed.
Add a %Q placeholder to include the queryid in log_line_prefix, which
will also only expose top level statements.
For EXPLAIN VERBOSE, if a query identifier has been computed, either by
enabling compute_query_id or using a third-party module, display it.
Bump catalog version.
Discussion: https://postgr.es/m/20210407125726.tkvjdbw76hxnpwfi@nol
Author: Julien Rouhaud
Reviewed-by: Alvaro Herrera, Nitin Jadhav, Zhihong Yu
4 years ago
|
|
|
if (beentry->st_queryid == 0)
|
|
|
|
nulls[29] = true;
|
|
|
|
else
|
|
|
|
values[29] = DatumGetUInt64(beentry->st_queryid);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No permissions to view data about this session */
|
|
|
|
values[5] = CStringGetTextDatum("<insufficient privilege>");
|
|
|
|
nulls[4] = true;
|
|
|
|
nulls[6] = true;
|
|
|
|
nulls[7] = true;
|
|
|
|
nulls[8] = true;
|
|
|
|
nulls[9] = true;
|
|
|
|
nulls[10] = true;
|
|
|
|
nulls[11] = true;
|
|
|
|
nulls[12] = true;
|
|
|
|
nulls[13] = true;
|
|
|
|
nulls[14] = true;
|
|
|
|
nulls[17] = true;
|
|
|
|
nulls[18] = true;
|
|
|
|
nulls[19] = true;
|
|
|
|
nulls[20] = true;
|
|
|
|
nulls[21] = true;
|
|
|
|
nulls[22] = true;
|
|
|
|
nulls[23] = true;
|
|
|
|
nulls[24] = true;
|
|
|
|
nulls[25] = true;
|
GSSAPI encryption support
On both the frontend and backend, prepare for GSSAPI encryption
support by moving common code for error handling into a separate file.
Fix a TODO for handling multiple status messages in the process.
Eliminate the OIDs, which have not been needed for some time.
Add frontend and backend encryption support functions. Keep the
context initiation for authentication-only separate on both the
frontend and backend in order to avoid concerns about changing the
requested flags to include encryption support.
In postmaster, pull GSSAPI authorization checking into a shared
function. Also share the initiator name between the encryption and
non-encryption codepaths.
For HBA, add "hostgssenc" and "hostnogssenc" entries that behave
similarly to their SSL counterparts. "hostgssenc" requires either
"gss", "trust", or "reject" for its authentication.
Similarly, add a "gssencmode" parameter to libpq. Supported values are
"disable", "require", and "prefer". Notably, negotiation will only be
attempted if credentials can be acquired. Move credential acquisition
into its own function to support this behavior.
Add a simple pg_stat_gssapi view similar to pg_stat_ssl, for monitoring
if GSSAPI authentication was used, what principal was used, and if
encryption is being used on the connection.
Finally, add documentation for everything new, and update existing
documentation on connection security.
Thanks to Michael Paquier for the Windows fixes.
Author: Robbie Harwood, with changes to the read/write functions by me.
Reviewed in various forms and at different times by: Michael Paquier,
Andres Freund, David Steele.
Discussion: https://www.postgresql.org/message-id/flat/jlg1tgq1ktm.fsf@thriss.redhat.com
6 years ago
|
|
|
nulls[26] = true;
|
|
|
|
nulls[27] = true;
|
|
|
|
nulls[28] = true;
|
Make use of in-core query id added by commit 5fd9dfa5f5
Use the in-core query id computation for pg_stat_activity,
log_line_prefix, and EXPLAIN VERBOSE.
Similar to other fields in pg_stat_activity, only the queryid from the
top level statements are exposed, and if the backends status isn't
active then the queryid from the last executed statements is displayed.
Add a %Q placeholder to include the queryid in log_line_prefix, which
will also only expose top level statements.
For EXPLAIN VERBOSE, if a query identifier has been computed, either by
enabling compute_query_id or using a third-party module, display it.
Bump catalog version.
Discussion: https://postgr.es/m/20210407125726.tkvjdbw76hxnpwfi@nol
Author: Julien Rouhaud
Reviewed-by: Alvaro Herrera, Nitin Jadhav, Zhihong Yu
4 years ago
|
|
|
nulls[29] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
|
|
|
|
/* If only a single backend was requested, and we found it, break. */
|
|
|
|
if (pid != -1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up and return the tuplestore */
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_backend_pid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT32(MyProcPid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_pid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_INT32(beentry->st_procpid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_dbid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_OID(beentry->st_databaseid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_userid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_OID(beentry->st_userid);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_activity(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
const char *activity;
|
|
|
|
char *clipped_activity;
|
|
|
|
text *ret;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
activity = "<backend information not available>";
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
activity = "<insufficient privilege>";
|
|
|
|
else if (*(beentry->st_activity_raw) == '\0')
|
|
|
|
activity = "<command string not enabled>";
|
|
|
|
else
|
|
|
|
activity = beentry->st_activity_raw;
|
|
|
|
|
|
|
|
clipped_activity = pgstat_clip_activity(activity);
|
|
|
|
ret = cstring_to_text(activity);
|
|
|
|
pfree(clipped_activity);
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_wait_event_type(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
PGPROC *proc;
|
|
|
|
const char *wait_event_type = NULL;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
wait_event_type = "<backend information not available>";
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
wait_event_type = "<insufficient privilege>";
|
|
|
|
else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
|
|
|
|
wait_event_type = pgstat_get_wait_event_type(proc->wait_event_info);
|
|
|
|
|
|
|
|
if (!wait_event_type)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(wait_event_type));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_wait_event(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
PGPROC *proc;
|
|
|
|
const char *wait_event = NULL;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
wait_event = "<backend information not available>";
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
wait_event = "<insufficient privilege>";
|
|
|
|
else if ((proc = BackendPidGetProc(beentry->st_procpid)) != NULL)
|
|
|
|
wait_event = pgstat_get_wait_event(proc->wait_event_info);
|
|
|
|
|
|
|
|
if (!wait_event)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TEXT_P(cstring_to_text(wait_event));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
result = beentry->st_activity_start_timestamp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No time recorded for start of current query -- this is the case if the
|
|
|
|
* user hasn't enabled query-level stats collection.
|
|
|
|
*/
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_xact_start(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
result = beentry->st_xact_start_timestamp;
|
|
|
|
|
|
|
|
if (result == 0) /* not in a transaction */
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_start(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
result = beentry->st_proc_start_timestamp;
|
|
|
|
|
|
|
|
if (result == 0) /* probably can't happen? */
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
SockAddr zero_clientaddr;
|
|
|
|
char remote_host[NI_MAXHOST];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
/* A zeroed client addr means we don't know */
|
|
|
|
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
|
|
|
|
if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
|
|
|
|
sizeof(zero_clientaddr)) == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
switch (beentry->st_clientaddr.addr.ss_family)
|
|
|
|
{
|
|
|
|
case AF_INET:
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
case AF_INET6:
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
remote_host[0] = '\0';
|
|
|
|
ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
|
|
|
|
beentry->st_clientaddr.salen,
|
|
|
|
remote_host, sizeof(remote_host),
|
|
|
|
NULL, 0,
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV);
|
|
|
|
if (ret != 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
|
|
|
|
|
|
|
|
PG_RETURN_INET_P(DirectFunctionCall1(inet_in,
|
|
|
|
CStringGetDatum(remote_host)));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_backend_client_port(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
int32 beid = PG_GETARG_INT32(0);
|
|
|
|
PgBackendStatus *beentry;
|
|
|
|
SockAddr zero_clientaddr;
|
|
|
|
char remote_port[NI_MAXSERV];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
else if (!HAS_PGSTAT_PERMISSIONS(beentry->st_userid))
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
/* A zeroed client addr means we don't know */
|
|
|
|
memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
|
|
|
|
if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
|
|
|
|
sizeof(zero_clientaddr)) == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
switch (beentry->st_clientaddr.addr.ss_family)
|
|
|
|
{
|
|
|
|
case AF_INET:
|
|
|
|
#ifdef HAVE_IPV6
|
|
|
|
case AF_INET6:
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
case AF_UNIX:
|
|
|
|
PG_RETURN_INT32(-1);
|
|
|
|
default:
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
|
|
|
remote_port[0] = '\0';
|
|
|
|
ret = pg_getnameinfo_all(&beentry->st_clientaddr.addr,
|
|
|
|
beentry->st_clientaddr.salen,
|
|
|
|
NULL, 0,
|
|
|
|
remote_port, sizeof(remote_port),
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV);
|
|
|
|
if (ret != 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_DATUM(DirectFunctionCall1(int4in,
|
|
|
|
CStringGetDatum(remote_port)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int32 result;
|
|
|
|
int tot_backends = pgstat_fetch_stat_numbackends();
|
|
|
|
int beid;
|
|
|
|
|
|
|
|
result = 0;
|
|
|
|
for (beid = 1; beid <= tot_backends; beid++)
|
|
|
|
{
|
|
|
|
PgBackendStatus *beentry = pgstat_fetch_stat_beentry(beid);
|
|
|
|
|
|
|
|
if (beentry && beentry->st_databaseid == dbid)
|
|
|
|
result++;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT32(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_xact_commit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_xact_commit);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_xact_rollback(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_xact_rollback);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_blocks_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_blocks_hit);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_tuples_returned(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_tuples_returned);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_tuples_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_tuples_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_tuples_inserted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_tuples_inserted);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_tuples_updated(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_tuples_updated);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_tuples_deleted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_tuples_deleted);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_stat_reset_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = dbentry->stat_reset_timestamp;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_temp_files(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = dbentry->n_temp_files;
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_temp_bytes(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = dbentry->n_temp_bytes;
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_tablespace(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_tablespace);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_lock(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_lock);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_snapshot(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_snapshot);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_bufferpin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_bufferpin);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_startup_deadlock(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_startup_deadlock);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_conflict_all(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_conflict_tablespace +
|
|
|
|
dbentry->n_conflict_lock +
|
|
|
|
dbentry->n_conflict_snapshot +
|
|
|
|
dbentry->n_conflict_bufferpin +
|
|
|
|
dbentry->n_conflict_startup_deadlock);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_deadlocks(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_deadlocks);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_checksum_failures(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if (!DataChecksumsEnabled())
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (dbentry->n_checksum_failures);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_checksum_last_failure(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
TimestampTz result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if (!DataChecksumsEnabled())
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = dbentry->last_checksum_failure;
|
|
|
|
|
|
|
|
if (result == 0)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
else
|
|
|
|
PG_RETURN_TIMESTAMPTZ(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_blk_read_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
double result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = ((double) dbentry->n_block_read_time) / 1000.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
double result;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = ((double) dbentry->n_block_write_time) / 1000.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_session_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
double result = 0.0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = ((double) dbentry->total_session_time) / 1000.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_active_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
double result = 0.0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = ((double) dbentry->total_active_time) / 1000.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_idle_in_transaction_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
double result = 0.0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
/* convert counter from microsec to millisec for display */
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = ((double) dbentry->total_idle_in_xact_time) / 1000.0;
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_sessions(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result = 0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = (int64) (dbentry->n_sessions);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_sessions_abandoned(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result = 0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = (int64) (dbentry->n_sessions_abandoned);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_sessions_fatal(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result = 0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = (int64) (dbentry->n_sessions_fatal);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dbid = PG_GETARG_OID(0);
|
|
|
|
int64 result = 0;
|
|
|
|
PgStat_StatDBEntry *dbentry;
|
|
|
|
|
|
|
|
if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) != NULL)
|
|
|
|
result = (int64) (dbentry->n_sessions_killed);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* time is already in msec, just convert to double for presentation */
|
|
|
|
PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* time is already in msec, just convert to double for presentation */
|
|
|
|
PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns statistics of WAL activity
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_stat_get_wal(PG_FUNCTION_ARGS)
|
|
|
|
{
|
Track total amounts of times spent writing and syncing WAL data to disk.
This commit adds new GUC track_wal_io_timing. When this is enabled,
the total amounts of time XLogWrite writes and issue_xlog_fsync syncs
WAL data to disk are counted in pg_stat_wal. This information would be
useful to check how much WAL write and sync affect the performance.
Enabling track_wal_io_timing will make the server query the operating
system for the current time every time WAL is written or synced,
which may cause significant overhead on some platforms. To avoid such
additional overhead in the server with track_io_timing enabled,
this commit introduces track_wal_io_timing as a separate parameter from
track_io_timing.
Note that WAL write and sync activity by walreceiver has not been tracked yet.
This commit makes the server also track the numbers of times XLogWrite
writes and issue_xlog_fsync syncs WAL data to disk, in pg_stat_wal,
regardless of the setting of track_wal_io_timing. This counters can be
used to calculate the WAL write and sync time per request, for example.
Bump PGSTAT_FILE_FORMAT_ID.
Bump catalog version.
Author: Masahiro Ikeda
Reviewed-By: Japin Li, Hayato Kuroda, Masahiko Sawada, David Johnston, Fujii Masao
Discussion: https://postgr.es/m/0509ad67b585a5b86a83d445dfa75392@oss.nttdata.com
4 years ago
|
|
|
#define PG_STAT_GET_WAL_COLS 9
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Datum values[PG_STAT_GET_WAL_COLS];
|
|
|
|
bool nulls[PG_STAT_GET_WAL_COLS];
|
|
|
|
char buf[256];
|
|
|
|
PgStat_WalStats *wal_stats;
|
|
|
|
|
|
|
|
/* Initialise values and NULL flags arrays */
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
/* Initialise attributes information in the tuple descriptor */
|
|
|
|
tupdesc = CreateTemplateTupleDesc(PG_STAT_GET_WAL_COLS);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "wal_records",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "wal_fpi",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes",
|
|
|
|
NUMERICOID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full",
|
|
|
|
INT8OID, -1, 0);
|
Track total amounts of times spent writing and syncing WAL data to disk.
This commit adds new GUC track_wal_io_timing. When this is enabled,
the total amounts of time XLogWrite writes and issue_xlog_fsync syncs
WAL data to disk are counted in pg_stat_wal. This information would be
useful to check how much WAL write and sync affect the performance.
Enabling track_wal_io_timing will make the server query the operating
system for the current time every time WAL is written or synced,
which may cause significant overhead on some platforms. To avoid such
additional overhead in the server with track_io_timing enabled,
this commit introduces track_wal_io_timing as a separate parameter from
track_io_timing.
Note that WAL write and sync activity by walreceiver has not been tracked yet.
This commit makes the server also track the numbers of times XLogWrite
writes and issue_xlog_fsync syncs WAL data to disk, in pg_stat_wal,
regardless of the setting of track_wal_io_timing. This counters can be
used to calculate the WAL write and sync time per request, for example.
Bump PGSTAT_FILE_FORMAT_ID.
Bump catalog version.
Author: Masahiro Ikeda
Reviewed-By: Japin Li, Hayato Kuroda, Masahiko Sawada, David Johnston, Fujii Masao
Discussion: https://postgr.es/m/0509ad67b585a5b86a83d445dfa75392@oss.nttdata.com
4 years ago
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_write",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "wal_sync",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 7, "wal_write_time",
|
|
|
|
FLOAT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 8, "wal_sync_time",
|
|
|
|
FLOAT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 9, "stats_reset",
|
|
|
|
TIMESTAMPTZOID, -1, 0);
|
|
|
|
|
|
|
|
BlessTupleDesc(tupdesc);
|
|
|
|
|
|
|
|
/* Get statistics about WAL activity */
|
|
|
|
wal_stats = pgstat_fetch_stat_wal();
|
|
|
|
|
|
|
|
/* Fill values and NULLs */
|
|
|
|
values[0] = Int64GetDatum(wal_stats->wal_records);
|
|
|
|
values[1] = Int64GetDatum(wal_stats->wal_fpi);
|
|
|
|
|
|
|
|
/* Convert to numeric. */
|
|
|
|
snprintf(buf, sizeof buf, UINT64_FORMAT, wal_stats->wal_bytes);
|
|
|
|
values[2] = DirectFunctionCall3(numeric_in,
|
|
|
|
CStringGetDatum(buf),
|
|
|
|
ObjectIdGetDatum(0),
|
|
|
|
Int32GetDatum(-1));
|
|
|
|
|
|
|
|
values[3] = Int64GetDatum(wal_stats->wal_buffers_full);
|
Track total amounts of times spent writing and syncing WAL data to disk.
This commit adds new GUC track_wal_io_timing. When this is enabled,
the total amounts of time XLogWrite writes and issue_xlog_fsync syncs
WAL data to disk are counted in pg_stat_wal. This information would be
useful to check how much WAL write and sync affect the performance.
Enabling track_wal_io_timing will make the server query the operating
system for the current time every time WAL is written or synced,
which may cause significant overhead on some platforms. To avoid such
additional overhead in the server with track_io_timing enabled,
this commit introduces track_wal_io_timing as a separate parameter from
track_io_timing.
Note that WAL write and sync activity by walreceiver has not been tracked yet.
This commit makes the server also track the numbers of times XLogWrite
writes and issue_xlog_fsync syncs WAL data to disk, in pg_stat_wal,
regardless of the setting of track_wal_io_timing. This counters can be
used to calculate the WAL write and sync time per request, for example.
Bump PGSTAT_FILE_FORMAT_ID.
Bump catalog version.
Author: Masahiro Ikeda
Reviewed-By: Japin Li, Hayato Kuroda, Masahiko Sawada, David Johnston, Fujii Masao
Discussion: https://postgr.es/m/0509ad67b585a5b86a83d445dfa75392@oss.nttdata.com
4 years ago
|
|
|
values[4] = Int64GetDatum(wal_stats->wal_write);
|
|
|
|
values[5] = Int64GetDatum(wal_stats->wal_sync);
|
|
|
|
|
|
|
|
/* Convert counters from microsec to millisec for display */
|
|
|
|
values[6] = Float8GetDatum(((double) wal_stats->wal_write_time) / 1000.0);
|
|
|
|
values[7] = Float8GetDatum(((double) wal_stats->wal_sync_time) / 1000.0);
|
|
|
|
|
|
|
|
values[8] = TimestampTzGetDatum(wal_stats->stat_reset_timestamp);
|
|
|
|
|
|
|
|
/* Returns the record as Datum */
|
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
|
|
|
}
|
|
|
|
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
/*
|
|
|
|
* Returns statistics of SLRU caches.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_stat_get_slru(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
#define PG_STAT_GET_SLRU_COLS 9
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
int i;
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
PgStat_SLRUStats *stats;
|
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
/* request SLRU stats from the stat collector */
|
|
|
|
stats = pgstat_fetch_slru();
|
|
|
|
|
|
|
|
for (i = 0;; i++)
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
{
|
|
|
|
/* for each row */
|
|
|
|
Datum values[PG_STAT_GET_SLRU_COLS];
|
|
|
|
bool nulls[PG_STAT_GET_SLRU_COLS];
|
|
|
|
PgStat_SLRUStats stat = stats[i];
|
Improve management of SLRU statistics collection.
Instead of re-identifying which statistics bucket to use for a given
SLRU on every counter increment, do it once during shmem initialization.
This saves a fair number of cycles, and there's no real cost because
we could not have a bucket assignment that varies over time or across
backends anyway.
Also, get rid of the ill-considered decision to let pgstat.c pry
directly into SLRU's shared state; it's cleaner just to have slru.c
pass the stats bucket number.
In consequence of these changes, there's no longer any need to store
an SLRU's LWLock tranche info in shared memory, so get rid of that,
making this a net reduction in shmem consumption. (That partly
reverts fe702a7b3.)
This is basically code review for 28cac71bd, so I also cleaned up
some comments, removed a dangling extern declaration, fixed some
things that should be static and/or const, etc.
Discussion: https://postgr.es/m/3618.1589313035@sss.pgh.pa.us
5 years ago
|
|
|
const char *name;
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
|
|
|
|
name = pgstat_slru_name(i);
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
break;
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
values[0] = PointerGetDatum(cstring_to_text(name));
|
|
|
|
values[1] = Int64GetDatum(stat.blocks_zeroed);
|
|
|
|
values[2] = Int64GetDatum(stat.blocks_hit);
|
|
|
|
values[3] = Int64GetDatum(stat.blocks_read);
|
|
|
|
values[4] = Int64GetDatum(stat.blocks_written);
|
|
|
|
values[5] = Int64GetDatum(stat.blocks_exists);
|
|
|
|
values[6] = Int64GetDatum(stat.flush);
|
|
|
|
values[7] = Int64GetDatum(stat.truncate);
|
|
|
|
values[8] = TimestampTzGetDatum(stat.stat_reset_timestamp);
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up and return the tuplestore */
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_numscans);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_tuples_returned);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_tuples_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_inserted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
PgStat_TableXactStatus *trans;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = tabentry->t_counts.t_tuples_inserted;
|
|
|
|
/* live subtransactions' counts aren't in t_tuples_inserted yet */
|
|
|
|
for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
|
|
|
|
result += trans->tuples_inserted;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_updated(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
PgStat_TableXactStatus *trans;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = tabentry->t_counts.t_tuples_updated;
|
|
|
|
/* live subtransactions' counts aren't in t_tuples_updated yet */
|
|
|
|
for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
|
|
|
|
result += trans->tuples_updated;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_deleted(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
PgStat_TableXactStatus *trans;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result = tabentry->t_counts.t_tuples_deleted;
|
|
|
|
/* live subtransactions' counts aren't in t_tuples_deleted yet */
|
|
|
|
for (trans = tabentry->trans; trans != NULL; trans = trans->upper)
|
|
|
|
result += trans->tuples_deleted;
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_tuples_hot_updated(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_tuples_hot_updated);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_blocks_fetched(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_blocks_fetched);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_blocks_hit(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid relid = PG_GETARG_OID(0);
|
|
|
|
int64 result;
|
|
|
|
PgStat_TableStatus *tabentry;
|
|
|
|
|
|
|
|
if ((tabentry = find_tabstat_entry(relid)) == NULL)
|
|
|
|
result = 0;
|
|
|
|
else
|
|
|
|
result = (int64) (tabentry->t_counts.t_blocks_hit);
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_function_calls(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_BackendFunctionEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = find_funcstat_entry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_INT64(funcentry->f_counts.f_numcalls);
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_function_total_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_BackendFunctionEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = find_funcstat_entry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_total_time));
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_xact_function_self_time(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcid = PG_GETARG_OID(0);
|
|
|
|
PgStat_BackendFunctionEntry *funcentry;
|
|
|
|
|
|
|
|
if ((funcentry = find_funcstat_entry(funcid)) == NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
PG_RETURN_FLOAT8(INSTR_TIME_GET_MILLISEC(funcentry->f_counts.f_self_time));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Get the timestamp of the current statistics snapshot */
|
|
|
|
Datum
|
|
|
|
pg_stat_get_snapshot_timestamp(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stats_timestamp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Discard the active statistics snapshot */
|
|
|
|
Datum
|
|
|
|
pg_stat_clear_snapshot(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
pgstat_clear_snapshot();
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Reset all counters for the current database */
|
|
|
|
Datum
|
|
|
|
pg_stat_reset(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
pgstat_reset_counters();
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset some shared cluster-wide counters */
|
|
|
|
Datum
|
|
|
|
pg_stat_reset_shared(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *target = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
|
|
|
|
|
|
pgstat_reset_shared_counters(target);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset a single counter in the current database */
|
|
|
|
Datum
|
|
|
|
pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid taboid = PG_GETARG_OID(0);
|
|
|
|
|
|
|
|
pgstat_reset_single_counter(taboid, RESET_TABLE);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid funcoid = PG_GETARG_OID(0);
|
|
|
|
|
|
|
|
pgstat_reset_single_counter(funcoid, RESET_FUNCTION);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
Collect statistics about SLRU caches
There's a number of SLRU caches used to access important data like clog,
commit timestamps, multixact, asynchronous notifications, etc. Until now
we had no easy way to monitor these shared caches, compute hit ratios,
number of reads/writes etc.
This commit extends the statistics collector to track this information
for a predefined list of SLRUs, and also introduces a new system view
pg_stat_slru displaying the data.
The list of built-in SLRUs is fixed, but additional SLRUs may be defined
in extensions. Unfortunately, there's no suitable registry of SLRUs, so
this patch simply defines a fixed list of SLRUs with entries for the
built-in ones and one entry for all additional SLRUs. Extensions adding
their own SLRU are fairly rare, so this seems acceptable.
This patch only allows monitoring of SLRUs, not tuning. The SLRU sizes
are still fixed (hard-coded in the code) and it's not entirely clear
which of the SLRUs might need a GUC to tune size. In a way, allowing us
to determine that is one of the goals of this patch.
Bump catversion as the patch introduces new functions and system view.
Author: Tomas Vondra
Reviewed-by: Alvaro Herrera
Discussion: https://www.postgresql.org/message-id/flat/20200119143707.gyinppnigokesjok@development
5 years ago
|
|
|
/* Reset SLRU counters (a specific one or all of them). */
|
|
|
|
Datum
|
|
|
|
pg_stat_reset_slru(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *target = NULL;
|
|
|
|
|
|
|
|
if (!PG_ARGISNULL(0))
|
|
|
|
target = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
|
|
|
|
|
|
pgstat_reset_slru_counter(target);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset replication slots stats (a specific one or all of them). */
|
|
|
|
Datum
|
|
|
|
pg_stat_reset_replication_slot(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *target = NULL;
|
|
|
|
|
|
|
|
if (!PG_ARGISNULL(0))
|
|
|
|
target = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
|
|
|
|
|
|
|
pgstat_reset_replslot_counter(target);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
Datum
|
|
|
|
pg_stat_get_archiver(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Datum values[7];
|
|
|
|
bool nulls[7];
|
|
|
|
PgStat_ArchiverStats *archiver_stats;
|
|
|
|
|
|
|
|
/* Initialise values and NULL flags arrays */
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
/* Initialise attributes information in the tuple descriptor */
|
Remove WITH OIDS support, change oid catalog column visibility.
Previously tables declared WITH OIDS, including a significant fraction
of the catalog tables, stored the oid column not as a normal column,
but as part of the tuple header.
This special column was not shown by default, which was somewhat odd,
as it's often (consider e.g. pg_class.oid) one of the more important
parts of a row. Neither pg_dump nor COPY included the contents of the
oid column by default.
The fact that the oid column was not an ordinary column necessitated a
significant amount of special case code to support oid columns. That
already was painful for the existing, but upcoming work aiming to make
table storage pluggable, would have required expanding and duplicating
that "specialness" significantly.
WITH OIDS has been deprecated since 2005 (commit ff02d0a05280e0).
Remove it.
Removing includes:
- CREATE TABLE and ALTER TABLE syntax for declaring the table to be
WITH OIDS has been removed (WITH (oids[ = true]) will error out)
- pg_dump does not support dumping tables declared WITH OIDS and will
issue a warning when dumping one (and ignore the oid column).
- restoring an pg_dump archive with pg_restore will warn when
restoring a table with oid contents (and ignore the oid column)
- COPY will refuse to load binary dump that includes oids.
- pg_upgrade will error out when encountering tables declared WITH
OIDS, they have to be altered to remove the oid column first.
- Functionality to access the oid of the last inserted row (like
plpgsql's RESULT_OID, spi's SPI_lastoid, ...) has been removed.
The syntax for declaring a table WITHOUT OIDS (or WITH (oids = false)
for CREATE TABLE) is still supported. While that requires a bit of
support code, it seems unnecessary to break applications / dumps that
do not use oids, and are explicit about not using them.
The biggest user of WITH OID columns was postgres' catalog. This
commit changes all 'magic' oid columns to be columns that are normally
declared and stored. To reduce unnecessary query breakage all the
newly added columns are still named 'oid', even if a table's column
naming scheme would indicate 'reloid' or such. This obviously
requires adapting a lot code, mostly replacing oid access via
HeapTupleGetOid() with access to the underlying Form_pg_*->oid column.
The bootstrap process now assigns oids for all oid columns in
genbki.pl that do not have an explicit value (starting at the largest
oid previously used), only oids assigned later by oids will be above
FirstBootstrapObjectId. As the oid column now is a normal column the
special bootstrap syntax for oids has been removed.
Oids are not automatically assigned during insertion anymore, all
backend code explicitly assigns oids with GetNewOidWithIndex(). For
the rare case that insertions into the catalog via SQL are called for
the new pg_nextoid() function can be used (which only works on catalog
tables).
The fact that oid columns on system tables are now normal columns
means that they will be included in the set of columns expanded
by * (i.e. SELECT * FROM pg_class will now include the table's oid,
previously it did not). It'd not technically be hard to hide oid
column by default, but that'd mean confusing behavior would either
have to be carried forward forever, or it'd cause breakage down the
line.
While it's not unlikely that further adjustments are needed, the
scope/invasiveness of the patch makes it worthwhile to get merge this
now. It's painful to maintain externally, too complicated to commit
after the code code freeze, and a dependency of a number of other
patches.
Catversion bump, for obvious reasons.
Author: Andres Freund, with contributions by John Naylor
Discussion: https://postgr.es/m/20180930034810.ywp2c7awz7opzcfr@alap3.anarazel.de
7 years ago
|
|
|
tupdesc = CreateTemplateTupleDesc(7);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal",
|
|
|
|
TEXTOID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "last_archived_time",
|
|
|
|
TIMESTAMPTZOID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "failed_count",
|
|
|
|
INT8OID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "last_failed_wal",
|
|
|
|
TEXTOID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time",
|
|
|
|
TIMESTAMPTZOID, -1, 0);
|
|
|
|
TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset",
|
|
|
|
TIMESTAMPTZOID, -1, 0);
|
|
|
|
|
|
|
|
BlessTupleDesc(tupdesc);
|
|
|
|
|
|
|
|
/* Get statistics about the archiver process */
|
|
|
|
archiver_stats = pgstat_fetch_stat_archiver();
|
|
|
|
|
|
|
|
/* Fill values and NULLs */
|
|
|
|
values[0] = Int64GetDatum(archiver_stats->archived_count);
|
|
|
|
if (*(archiver_stats->last_archived_wal) == '\0')
|
|
|
|
nulls[1] = true;
|
|
|
|
else
|
|
|
|
values[1] = CStringGetTextDatum(archiver_stats->last_archived_wal);
|
|
|
|
|
|
|
|
if (archiver_stats->last_archived_timestamp == 0)
|
|
|
|
nulls[2] = true;
|
|
|
|
else
|
|
|
|
values[2] = TimestampTzGetDatum(archiver_stats->last_archived_timestamp);
|
|
|
|
|
|
|
|
values[3] = Int64GetDatum(archiver_stats->failed_count);
|
|
|
|
if (*(archiver_stats->last_failed_wal) == '\0')
|
|
|
|
nulls[4] = true;
|
|
|
|
else
|
|
|
|
values[4] = CStringGetTextDatum(archiver_stats->last_failed_wal);
|
|
|
|
|
|
|
|
if (archiver_stats->last_failed_timestamp == 0)
|
|
|
|
nulls[5] = true;
|
|
|
|
else
|
|
|
|
values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp);
|
|
|
|
|
|
|
|
if (archiver_stats->stat_reset_timestamp == 0)
|
|
|
|
nulls[6] = true;
|
|
|
|
else
|
|
|
|
values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp);
|
|
|
|
|
|
|
|
/* Returns the record as Datum */
|
|
|
|
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the statistics for the replication slots */
|
|
|
|
Datum
|
|
|
|
pg_stat_get_replication_slots(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
#define PG_STAT_GET_REPLICATION_SLOT_COLS 8
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
PgStat_ReplSlotStats *slotstats;
|
|
|
|
int nstats;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
slotstats = pgstat_fetch_replslot(&nstats);
|
|
|
|
for (i = 0; i < nstats; i++)
|
|
|
|
{
|
|
|
|
Datum values[PG_STAT_GET_REPLICATION_SLOT_COLS];
|
|
|
|
bool nulls[PG_STAT_GET_REPLICATION_SLOT_COLS];
|
|
|
|
PgStat_ReplSlotStats *s = &(slotstats[i]);
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
values[0] = PointerGetDatum(cstring_to_text(s->slotname));
|
|
|
|
values[1] = Int64GetDatum(s->spill_txns);
|
|
|
|
values[2] = Int64GetDatum(s->spill_count);
|
|
|
|
values[3] = Int64GetDatum(s->spill_bytes);
|
|
|
|
values[4] = Int64GetDatum(s->stream_txns);
|
|
|
|
values[5] = Int64GetDatum(s->stream_count);
|
|
|
|
values[6] = Int64GetDatum(s->stream_bytes);
|
|
|
|
|
|
|
|
if (s->stat_reset_timestamp == 0)
|
|
|
|
nulls[7] = true;
|
|
|
|
else
|
|
|
|
values[7] = TimestampTzGetDatum(s->stat_reset_timestamp);
|
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|