mirror of https://github.com/postgres/postgres
injection_points: Add some fixed-numbered statistics
Like75534436a4
, this acts mainly as a template to show what can be achieved with fixed-numbered stats (like WAL, bgwriter, etc.) with the pluggable cumulative statistics APIs introduced in7949d95945
. Fixed-numbered stats are defined in their own file, named injection_stats_fixed.c, separated entirely from the variable-numbered case in injection_stats.c. This is mainly for clarity as having both examples in the same file would be confusing. Note that this commit uses the helper routines added in2eff9e678d
. The stats stored track globally the number of times injection points have been attached, detached or run. Two more fields should be added later for the number of times a point has been cached or loaded, but what's here is enough as a template. More TAP tests are added, providing coverage for fixed-numbered custom stats. Author: Michael Paquier Reviewed-by: Dmitry Dolgov, Bertrand Drouvot Discussion: https://postgr.es/m/Zmqm9j5EO0I4W8dx@paquier.xyz
This commit is contained in:
parent
75534436a4
commit
f68cd847fa
|
@ -4,7 +4,8 @@ MODULE_big = injection_points
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$(WIN32RES) \
|
$(WIN32RES) \
|
||||||
injection_points.o \
|
injection_points.o \
|
||||||
injection_stats.o
|
injection_stats.o \
|
||||||
|
injection_stats_fixed.o
|
||||||
EXTENSION = injection_points
|
EXTENSION = injection_points
|
||||||
DATA = injection_points--1.0.sql
|
DATA = injection_points--1.0.sql
|
||||||
PGFILEDESC = "injection_points - facility for injection points"
|
PGFILEDESC = "injection_points - facility for injection points"
|
||||||
|
|
|
@ -84,3 +84,14 @@ CREATE FUNCTION injection_points_stats_numcalls(IN point_name TEXT)
|
||||||
RETURNS bigint
|
RETURNS bigint
|
||||||
AS 'MODULE_PATHNAME', 'injection_points_stats_numcalls'
|
AS 'MODULE_PATHNAME', 'injection_points_stats_numcalls'
|
||||||
LANGUAGE C STRICT;
|
LANGUAGE C STRICT;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- injection_points_stats_fixed()
|
||||||
|
--
|
||||||
|
-- Reports fixed-numbered statistics for injection points.
|
||||||
|
CREATE FUNCTION injection_points_stats_fixed(OUT numattach int8,
|
||||||
|
OUT numdetach int8,
|
||||||
|
OUT numrun int8)
|
||||||
|
RETURNS record
|
||||||
|
AS 'MODULE_PATHNAME', 'injection_points_stats_fixed'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
|
|
@ -297,6 +297,7 @@ injection_points_attach(PG_FUNCTION_ARGS)
|
||||||
condition.pid = MyProcPid;
|
condition.pid = MyProcPid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pgstat_report_inj_fixed(1, 0, 0);
|
||||||
InjectionPointAttach(name, "injection_points", function, &condition,
|
InjectionPointAttach(name, "injection_points", function, &condition,
|
||||||
sizeof(InjectionPointCondition));
|
sizeof(InjectionPointCondition));
|
||||||
|
|
||||||
|
@ -342,6 +343,7 @@ injection_points_run(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||||
|
|
||||||
|
pgstat_report_inj_fixed(0, 0, 1);
|
||||||
INJECTION_POINT(name);
|
INJECTION_POINT(name);
|
||||||
|
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
|
@ -432,6 +434,7 @@ injection_points_detach(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
|
||||||
|
|
||||||
|
pgstat_report_inj_fixed(0, 1, 0);
|
||||||
if (!InjectionPointDetach(name))
|
if (!InjectionPointDetach(name))
|
||||||
elog(ERROR, "could not detach injection point \"%s\"", name);
|
elog(ERROR, "could not detach injection point \"%s\"", name);
|
||||||
|
|
||||||
|
@ -459,4 +462,5 @@ _PG_init(void)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pgstat_register_inj();
|
pgstat_register_inj();
|
||||||
|
pgstat_register_inj_fixed();
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,9 +15,16 @@
|
||||||
#ifndef INJECTION_STATS
|
#ifndef INJECTION_STATS
|
||||||
#define INJECTION_STATS
|
#define INJECTION_STATS
|
||||||
|
|
||||||
|
/* injection_stats.c */
|
||||||
extern void pgstat_register_inj(void);
|
extern void pgstat_register_inj(void);
|
||||||
extern void pgstat_create_inj(const char *name);
|
extern void pgstat_create_inj(const char *name);
|
||||||
extern void pgstat_drop_inj(const char *name);
|
extern void pgstat_drop_inj(const char *name);
|
||||||
extern void pgstat_report_inj(const char *name);
|
extern void pgstat_report_inj(const char *name);
|
||||||
|
|
||||||
|
/* injection_stats_fixed.c */
|
||||||
|
extern void pgstat_register_inj_fixed(void);
|
||||||
|
extern void pgstat_report_inj_fixed(uint32 numattach,
|
||||||
|
uint32 numdetach,
|
||||||
|
uint32 numrun);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* injection_stats_fixed.c
|
||||||
|
* Code for fixed-numbered statistics of injection points.
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* src/test/modules/injection_points/injection_stats_fixed.c
|
||||||
|
*
|
||||||
|
* -------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "fmgr.h"
|
||||||
|
|
||||||
|
#include "common/hashfn.h"
|
||||||
|
#include "funcapi.h"
|
||||||
|
#include "injection_stats.h"
|
||||||
|
#include "pgstat.h"
|
||||||
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/pgstat_internal.h"
|
||||||
|
|
||||||
|
/* Structures for statistics of injection points, fixed-size */
|
||||||
|
typedef struct PgStat_StatInjFixedEntry
|
||||||
|
{
|
||||||
|
PgStat_Counter numattach; /* number of points attached */
|
||||||
|
PgStat_Counter numdetach; /* number of points detached */
|
||||||
|
PgStat_Counter numrun; /* number of points run */
|
||||||
|
TimestampTz stat_reset_timestamp;
|
||||||
|
} PgStat_StatInjFixedEntry;
|
||||||
|
|
||||||
|
typedef struct PgStatShared_InjectionPointFixed
|
||||||
|
{
|
||||||
|
LWLock lock; /* protects all the counters */
|
||||||
|
uint32 changecount;
|
||||||
|
PgStat_StatInjFixedEntry stats;
|
||||||
|
PgStat_StatInjFixedEntry reset_offset;
|
||||||
|
} PgStatShared_InjectionPointFixed;
|
||||||
|
|
||||||
|
/* Callbacks for fixed-numbered stats */
|
||||||
|
static void injection_stats_fixed_init_shmem_cb(void *stats);
|
||||||
|
static void injection_stats_fixed_reset_all_cb(TimestampTz ts);
|
||||||
|
static void injection_stats_fixed_snapshot_cb(void);
|
||||||
|
|
||||||
|
static const PgStat_KindInfo injection_stats_fixed = {
|
||||||
|
.name = "injection_points_fixed",
|
||||||
|
.fixed_amount = true,
|
||||||
|
|
||||||
|
.shared_size = sizeof(PgStat_StatInjFixedEntry),
|
||||||
|
.shared_data_off = offsetof(PgStatShared_InjectionPointFixed, stats),
|
||||||
|
.shared_data_len = sizeof(((PgStatShared_InjectionPointFixed *) 0)->stats),
|
||||||
|
|
||||||
|
.init_shmem_cb = injection_stats_fixed_init_shmem_cb,
|
||||||
|
.reset_all_cb = injection_stats_fixed_reset_all_cb,
|
||||||
|
.snapshot_cb = injection_stats_fixed_snapshot_cb,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Kind ID reserved for statistics of injection points.
|
||||||
|
*/
|
||||||
|
#define PGSTAT_KIND_INJECTION_FIXED 130
|
||||||
|
|
||||||
|
/* Track if fixed-numbered stats are loaded */
|
||||||
|
static bool inj_fixed_loaded = false;
|
||||||
|
|
||||||
|
static void
|
||||||
|
injection_stats_fixed_init_shmem_cb(void *stats)
|
||||||
|
{
|
||||||
|
PgStatShared_InjectionPointFixed *stats_shmem =
|
||||||
|
(PgStatShared_InjectionPointFixed *) stats;
|
||||||
|
|
||||||
|
LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
injection_stats_fixed_reset_all_cb(TimestampTz ts)
|
||||||
|
{
|
||||||
|
PgStatShared_InjectionPointFixed *stats_shmem =
|
||||||
|
pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
|
||||||
|
LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
|
||||||
|
pgstat_copy_changecounted_stats(&stats_shmem->reset_offset,
|
||||||
|
&stats_shmem->stats,
|
||||||
|
sizeof(stats_shmem->stats),
|
||||||
|
&stats_shmem->changecount);
|
||||||
|
stats_shmem->stats.stat_reset_timestamp = ts;
|
||||||
|
LWLockRelease(&stats_shmem->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
injection_stats_fixed_snapshot_cb(void)
|
||||||
|
{
|
||||||
|
PgStatShared_InjectionPointFixed *stats_shmem =
|
||||||
|
pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
PgStat_StatInjFixedEntry *stat_snap =
|
||||||
|
pgstat_get_custom_snapshot_data(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
PgStat_StatInjFixedEntry *reset_offset = &stats_shmem->reset_offset;
|
||||||
|
PgStat_StatInjFixedEntry reset;
|
||||||
|
|
||||||
|
pgstat_copy_changecounted_stats(stat_snap,
|
||||||
|
&stats_shmem->stats,
|
||||||
|
sizeof(stats_shmem->stats),
|
||||||
|
&stats_shmem->changecount);
|
||||||
|
|
||||||
|
LWLockAcquire(&stats_shmem->lock, LW_SHARED);
|
||||||
|
memcpy(&reset, reset_offset, sizeof(stats_shmem->stats));
|
||||||
|
LWLockRelease(&stats_shmem->lock);
|
||||||
|
|
||||||
|
/* compensate by reset offsets */
|
||||||
|
#define FIXED_COMP(fld) stat_snap->fld -= reset.fld;
|
||||||
|
FIXED_COMP(numattach);
|
||||||
|
FIXED_COMP(numdetach);
|
||||||
|
FIXED_COMP(numrun);
|
||||||
|
#undef FIXED_COMP
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Workhorse to do the registration work, called in _PG_init().
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pgstat_register_inj_fixed(void)
|
||||||
|
{
|
||||||
|
pgstat_register_kind(PGSTAT_KIND_INJECTION_FIXED, &injection_stats_fixed);
|
||||||
|
|
||||||
|
/* mark stats as loaded */
|
||||||
|
inj_fixed_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report fixed number of statistics for an injection point.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pgstat_report_inj_fixed(uint32 numattach,
|
||||||
|
uint32 numdetach,
|
||||||
|
uint32 numrun)
|
||||||
|
{
|
||||||
|
PgStatShared_InjectionPointFixed *stats_shmem;
|
||||||
|
|
||||||
|
/* leave if disabled */
|
||||||
|
if (!inj_fixed_loaded)
|
||||||
|
return;
|
||||||
|
|
||||||
|
stats_shmem = pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
|
||||||
|
pgstat_begin_changecount_write(&stats_shmem->changecount);
|
||||||
|
stats_shmem->stats.numattach += numattach;
|
||||||
|
stats_shmem->stats.numdetach += numdetach;
|
||||||
|
stats_shmem->stats.numrun += numrun;
|
||||||
|
pgstat_end_changecount_write(&stats_shmem->changecount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SQL function returning fixed-numbered statistics for injection points.
|
||||||
|
*/
|
||||||
|
PG_FUNCTION_INFO_V1(injection_points_stats_fixed);
|
||||||
|
Datum
|
||||||
|
injection_points_stats_fixed(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
TupleDesc tupdesc;
|
||||||
|
Datum values[3] = {0};
|
||||||
|
bool nulls[3] = {0};
|
||||||
|
PgStat_StatInjFixedEntry *stats;
|
||||||
|
|
||||||
|
if (!inj_fixed_loaded)
|
||||||
|
PG_RETURN_NULL();
|
||||||
|
|
||||||
|
pgstat_snapshot_fixed(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
stats = pgstat_get_custom_snapshot_data(PGSTAT_KIND_INJECTION_FIXED);
|
||||||
|
|
||||||
|
/* Initialise attributes information in the tuple descriptor */
|
||||||
|
tupdesc = CreateTemplateTupleDesc(3);
|
||||||
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "numattach",
|
||||||
|
INT8OID, -1, 0);
|
||||||
|
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "numdetach",
|
||||||
|
INT8OID, -1, 0);
|
||||||
|
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "numrun",
|
||||||
|
INT8OID, -1, 0);
|
||||||
|
BlessTupleDesc(tupdesc);
|
||||||
|
|
||||||
|
values[0] = Int64GetDatum(stats->numattach);
|
||||||
|
values[1] = Int64GetDatum(stats->numdetach);
|
||||||
|
values[2] = Int64GetDatum(stats->numrun);
|
||||||
|
nulls[0] = false;
|
||||||
|
nulls[1] = false;
|
||||||
|
nulls[2] = false;
|
||||||
|
|
||||||
|
/* Returns the record as Datum */
|
||||||
|
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ endif
|
||||||
injection_points_sources = files(
|
injection_points_sources = files(
|
||||||
'injection_points.c',
|
'injection_points.c',
|
||||||
'injection_stats.c',
|
'injection_stats.c',
|
||||||
|
'injection_stats_fixed.c',
|
||||||
)
|
)
|
||||||
|
|
||||||
if host_system == 'windows'
|
if host_system == 'windows'
|
||||||
|
|
|
@ -33,18 +33,27 @@ $node->safe_psql('postgres', "SELECT injection_points_run('stats-notice');");
|
||||||
my $numcalls = $node->safe_psql('postgres',
|
my $numcalls = $node->safe_psql('postgres',
|
||||||
"SELECT injection_points_stats_numcalls('stats-notice');");
|
"SELECT injection_points_stats_numcalls('stats-notice');");
|
||||||
is($numcalls, '2', 'number of stats calls');
|
is($numcalls, '2', 'number of stats calls');
|
||||||
|
my $fixedstats = $node->safe_psql('postgres',
|
||||||
|
"SELECT * FROM injection_points_stats_fixed();");
|
||||||
|
is($fixedstats, '1|0|2', 'number of fixed stats');
|
||||||
|
|
||||||
# Restart the node cleanly, stats should still be around.
|
# Restart the node cleanly, stats should still be around.
|
||||||
$node->restart;
|
$node->restart;
|
||||||
$numcalls = $node->safe_psql('postgres',
|
$numcalls = $node->safe_psql('postgres',
|
||||||
"SELECT injection_points_stats_numcalls('stats-notice');");
|
"SELECT injection_points_stats_numcalls('stats-notice');");
|
||||||
is($numcalls, '2', 'number of stats after clean restart');
|
is($numcalls, '2', 'number of stats after clean restart');
|
||||||
|
$fixedstats = $node->safe_psql('postgres',
|
||||||
|
"SELECT * FROM injection_points_stats_fixed();");
|
||||||
|
is($fixedstats, '1|0|2', 'number of fixed stats after clean restart');
|
||||||
|
|
||||||
# On crash the stats are gone.
|
# On crash the stats are gone.
|
||||||
$node->stop('immediate');
|
$node->stop('immediate');
|
||||||
$node->start;
|
$node->start;
|
||||||
$numcalls = $node->safe_psql('postgres',
|
$numcalls = $node->safe_psql('postgres',
|
||||||
"SELECT injection_points_stats_numcalls('stats-notice');");
|
"SELECT injection_points_stats_numcalls('stats-notice');");
|
||||||
is($numcalls, '', 'number of stats after clean restart');
|
is($numcalls, '', 'number of stats after crash');
|
||||||
|
$fixedstats = $node->safe_psql('postgres',
|
||||||
|
"SELECT * FROM injection_points_stats_fixed();");
|
||||||
|
is($fixedstats, '0|0|0', 'number of fixed stats after crash');
|
||||||
|
|
||||||
done_testing();
|
done_testing();
|
||||||
|
|
|
@ -2120,6 +2120,7 @@ PgStatShared_Database
|
||||||
PgStatShared_Function
|
PgStatShared_Function
|
||||||
PgStatShared_HashEntry
|
PgStatShared_HashEntry
|
||||||
PgStatShared_InjectionPoint
|
PgStatShared_InjectionPoint
|
||||||
|
PgStatShared_InjectionPointFixed
|
||||||
PgStatShared_IO
|
PgStatShared_IO
|
||||||
PgStatShared_Relation
|
PgStatShared_Relation
|
||||||
PgStatShared_ReplSlot
|
PgStatShared_ReplSlot
|
||||||
|
@ -2152,6 +2153,7 @@ PgStat_SnapshotEntry
|
||||||
PgStat_StatDBEntry
|
PgStat_StatDBEntry
|
||||||
PgStat_StatFuncEntry
|
PgStat_StatFuncEntry
|
||||||
PgStat_StatInjEntry
|
PgStat_StatInjEntry
|
||||||
|
PgStat_StatInjFixedEntry
|
||||||
PgStat_StatReplSlotEntry
|
PgStat_StatReplSlotEntry
|
||||||
PgStat_StatSubEntry
|
PgStat_StatSubEntry
|
||||||
PgStat_StatTabEntry
|
PgStat_StatTabEntry
|
||||||
|
|
Loading…
Reference in New Issue