Generate pg_stat_get*() functions for tables using macros

The same code pattern is repeated 17 times for int64 counters (0 for
missing entry) and 5 times for timestamps (NULL for missing entry) on
table entries.  This code is switched to use a macro for the basic code
instead, shaving a few hundred lines of originally-duplicated code.  The
function names remain the same, but some fields of PgStat_StatTabEntry
have to be renamed to cope with the new style.

Author: Bertrand Drouvot
Reviewed-by: Nathan Bossart
Discussion: https:/postgr.es/m/20221204173207.GA2669116@nathanxps13
This commit is contained in:
Michael Paquier 2022-12-06 10:46:35 +09:00
parent 941aa6a626
commit 83a1a1b566
5 changed files with 139 additions and 396 deletions

View File

@ -271,7 +271,7 @@ physical tuple by eliminating an intermediate heap-only tuple or
replacing a physical root tuple by a redirect pointer, a decrement in replacing a physical root tuple by a redirect pointer, a decrement in
the table's number of dead tuples is reported to pgstats, which may the table's number of dead tuples is reported to pgstats, which may
postpone autovacuuming. Note that we do not count replacing a root tuple postpone autovacuuming. Note that we do not count replacing a root tuple
by a DEAD line pointer as decrementing n_dead_tuples; we still want by a DEAD line pointer as decrementing dead_tuples; we still want
autovacuum to run to clean up the index entries and DEAD item. autovacuum to run to clean up the index entries and DEAD item.
This area probably needs further work ... This area probably needs further work ...

View File

@ -3081,9 +3081,9 @@ relation_needs_vacanalyze(Oid relid,
if (PointerIsValid(tabentry) && AutoVacuumingActive()) if (PointerIsValid(tabentry) && AutoVacuumingActive())
{ {
reltuples = classForm->reltuples; reltuples = classForm->reltuples;
vactuples = tabentry->n_dead_tuples; vactuples = tabentry->dead_tuples;
instuples = tabentry->inserts_since_vacuum; instuples = tabentry->ins_since_vacuum;
anltuples = tabentry->changes_since_analyze; anltuples = tabentry->mod_since_analyze;
/* If the table hasn't yet been vacuumed, take reltuples as zero */ /* If the table hasn't yet been vacuumed, take reltuples as zero */
if (reltuples < 0) if (reltuples < 0)

View File

@ -231,8 +231,8 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats; shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats;
tabentry = &shtabentry->stats; tabentry = &shtabentry->stats;
tabentry->n_live_tuples = livetuples; tabentry->live_tuples = livetuples;
tabentry->n_dead_tuples = deadtuples; tabentry->dead_tuples = deadtuples;
/* /*
* It is quite possible that a non-aggressive VACUUM ended up skipping * It is quite possible that a non-aggressive VACUUM ended up skipping
@ -244,16 +244,16 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
* autovacuum. An anti-wraparound autovacuum will catch any persistent * autovacuum. An anti-wraparound autovacuum will catch any persistent
* stragglers. * stragglers.
*/ */
tabentry->inserts_since_vacuum = 0; tabentry->ins_since_vacuum = 0;
if (IsAutoVacuumWorkerProcess()) if (IsAutoVacuumWorkerProcess())
{ {
tabentry->autovac_vacuum_timestamp = ts; tabentry->last_autovacuum_time = ts;
tabentry->autovac_vacuum_count++; tabentry->autovacuum_count++;
} }
else else
{ {
tabentry->vacuum_timestamp = ts; tabentry->last_vacuum_time = ts;
tabentry->vacuum_count++; tabentry->vacuum_count++;
} }
@ -264,7 +264,7 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
* Report that the table was just analyzed. * Report that the table was just analyzed.
* *
* Caller must provide new live- and dead-tuples estimates, as well as a * Caller must provide new live- and dead-tuples estimates, as well as a
* flag indicating whether to reset the changes_since_analyze counter. * flag indicating whether to reset the mod_since_analyze counter.
*/ */
void void
pgstat_report_analyze(Relation rel, pgstat_report_analyze(Relation rel,
@ -318,25 +318,25 @@ pgstat_report_analyze(Relation rel,
shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats; shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats;
tabentry = &shtabentry->stats; tabentry = &shtabentry->stats;
tabentry->n_live_tuples = livetuples; tabentry->live_tuples = livetuples;
tabentry->n_dead_tuples = deadtuples; tabentry->dead_tuples = deadtuples;
/* /*
* If commanded, reset changes_since_analyze to zero. This forgets any * If commanded, reset mod_since_analyze to zero. This forgets any
* changes that were committed while the ANALYZE was in progress, but we * changes that were committed while the ANALYZE was in progress, but we
* have no good way to estimate how many of those there were. * have no good way to estimate how many of those there were.
*/ */
if (resetcounter) if (resetcounter)
tabentry->changes_since_analyze = 0; tabentry->mod_since_analyze = 0;
if (IsAutoVacuumWorkerProcess()) if (IsAutoVacuumWorkerProcess())
{ {
tabentry->autovac_analyze_timestamp = GetCurrentTimestamp(); tabentry->last_autoanalyze_time = GetCurrentTimestamp();
tabentry->autovac_analyze_count++; tabentry->autoanalyze_count++;
} }
else else
{ {
tabentry->analyze_timestamp = GetCurrentTimestamp(); tabentry->last_analyze_time = GetCurrentTimestamp();
tabentry->analyze_count++; tabentry->analyze_count++;
} }
@ -798,22 +798,22 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
*/ */
if (lstats->t_counts.t_truncdropped) if (lstats->t_counts.t_truncdropped)
{ {
tabentry->n_live_tuples = 0; tabentry->live_tuples = 0;
tabentry->n_dead_tuples = 0; tabentry->dead_tuples = 0;
tabentry->inserts_since_vacuum = 0; tabentry->ins_since_vacuum = 0;
} }
tabentry->n_live_tuples += lstats->t_counts.t_delta_live_tuples; tabentry->live_tuples += lstats->t_counts.t_delta_live_tuples;
tabentry->n_dead_tuples += lstats->t_counts.t_delta_dead_tuples; tabentry->dead_tuples += lstats->t_counts.t_delta_dead_tuples;
tabentry->changes_since_analyze += lstats->t_counts.t_changed_tuples; tabentry->mod_since_analyze += lstats->t_counts.t_changed_tuples;
tabentry->inserts_since_vacuum += lstats->t_counts.t_tuples_inserted; tabentry->ins_since_vacuum += lstats->t_counts.t_tuples_inserted;
tabentry->blocks_fetched += lstats->t_counts.t_blocks_fetched; tabentry->blocks_fetched += lstats->t_counts.t_blocks_fetched;
tabentry->blocks_hit += lstats->t_counts.t_blocks_hit; tabentry->blocks_hit += lstats->t_counts.t_blocks_hit;
/* Clamp n_live_tuples in case of negative delta_live_tuples */ /* Clamp live_tuples in case of negative delta_live_tuples */
tabentry->n_live_tuples = Max(tabentry->n_live_tuples, 0); tabentry->live_tuples = Max(tabentry->live_tuples, 0);
/* Likewise for n_dead_tuples */ /* Likewise for dead_tuples */
tabentry->n_dead_tuples = Max(tabentry->n_dead_tuples, 0); tabentry->dead_tuples = Max(tabentry->dead_tuples, 0);
pgstat_unlock_entry(entry_ref); pgstat_unlock_entry(entry_ref);

View File

@ -36,363 +36,106 @@
#define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role)) #define HAS_PGSTAT_PERMISSIONS(role) (has_privs_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
Datum #define PG_STAT_GET_RELENTRY_INT64(stat) \
pg_stat_get_numscans(PG_FUNCTION_ARGS) Datum \
{ CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
Oid relid = PG_GETARG_OID(0); { \
int64 result; Oid relid = PG_GETARG_OID(0); \
PgStat_StatTabEntry *tabentry; int64 result; \
PgStat_StatTabEntry *tabentry; \
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
result = 0; if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
else result = 0; \
result = (int64) (tabentry->numscans); else \
result = (int64) (tabentry->stat); \
PG_RETURN_INT64(result); \
} PG_RETURN_INT64(result); \
} \
Datum /* pg_stat_get_analyze_count */
pg_stat_get_lastscan(PG_FUNCTION_ARGS) PG_STAT_GET_RELENTRY_INT64(analyze_count);
{
Oid relid = PG_GETARG_OID(0); /* pg_stat_get_autoanalyze_count */
TimestampTz result; PG_STAT_GET_RELENTRY_INT64(autoanalyze_count);
PgStat_StatTabEntry *tabentry;
/* pg_stat_get_autovacuum_count */
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) PG_STAT_GET_RELENTRY_INT64(autovacuum_count);
result = 0;
else /* pg_stat_get_blocks_fetched */
result = tabentry->lastscan; PG_STAT_GET_RELENTRY_INT64(blocks_fetched);
if (result == 0) /* pg_stat_get_blocks_hit */
PG_RETURN_NULL(); PG_STAT_GET_RELENTRY_INT64(blocks_hit);
else
PG_RETURN_TIMESTAMPTZ(result); /* pg_stat_get_dead_tuples */
} PG_STAT_GET_RELENTRY_INT64(dead_tuples);
/* pg_stat_get_ins_since_vacuum */
Datum PG_STAT_GET_RELENTRY_INT64(ins_since_vacuum);
pg_stat_get_tuples_returned(PG_FUNCTION_ARGS)
{ /* pg_stat_get_live_tuples */
Oid relid = PG_GETARG_OID(0); PG_STAT_GET_RELENTRY_INT64(live_tuples);
int64 result;
PgStat_StatTabEntry *tabentry; /* pg_stat_get_mods_since_analyze */
PG_STAT_GET_RELENTRY_INT64(mod_since_analyze);
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL)
result = 0; /* pg_stat_get_numscans */
else PG_STAT_GET_RELENTRY_INT64(numscans);
result = (int64) (tabentry->tuples_returned);
/* pg_stat_get_tuples_deleted */
PG_RETURN_INT64(result); PG_STAT_GET_RELENTRY_INT64(tuples_deleted);
}
/* pg_stat_get_tuples_fetched */
PG_STAT_GET_RELENTRY_INT64(tuples_fetched);
Datum
pg_stat_get_tuples_fetched(PG_FUNCTION_ARGS) /* pg_stat_get_tuples_hot_updated */
{ PG_STAT_GET_RELENTRY_INT64(tuples_hot_updated);
Oid relid = PG_GETARG_OID(0);
int64 result; /* pg_stat_get_tuples_inserted */
PgStat_StatTabEntry *tabentry; PG_STAT_GET_RELENTRY_INT64(tuples_inserted);
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) /* pg_stat_get_tuples_returned */
result = 0; PG_STAT_GET_RELENTRY_INT64(tuples_returned);
else
result = (int64) (tabentry->tuples_fetched); /* pg_stat_get_tuples_updated */
PG_STAT_GET_RELENTRY_INT64(tuples_updated);
PG_RETURN_INT64(result);
} /* pg_stat_get_vacuum_count */
PG_STAT_GET_RELENTRY_INT64(vacuum_count);
Datum #define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat) \
pg_stat_get_tuples_inserted(PG_FUNCTION_ARGS) Datum \
{ CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \
Oid relid = PG_GETARG_OID(0); { \
int64 result; Oid relid = PG_GETARG_OID(0); \
PgStat_StatTabEntry *tabentry; TimestampTz result; \
PgStat_StatTabEntry *tabentry; \
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
result = 0; if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) \
else result = 0; \
result = (int64) (tabentry->tuples_inserted); else \
result = tabentry->stat; \
PG_RETURN_INT64(result); \
} if (result == 0) \
PG_RETURN_NULL(); \
else \
Datum PG_RETURN_TIMESTAMPTZ(result); \
pg_stat_get_tuples_updated(PG_FUNCTION_ARGS) } \
{
Oid relid = PG_GETARG_OID(0); /* pg_stat_get_last_analyze_time */
int64 result; PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_analyze_time);
PgStat_StatTabEntry *tabentry;
/* pg_stat_get_last_autoanalyze_time */
if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autoanalyze_time);
result = 0;
else /* pg_stat_get_last_autovacuum_time */
result = (int64) (tabentry->tuples_updated); PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_autovacuum_time);
PG_RETURN_INT64(result); /* pg_stat_get_last_vacuum_time */
} PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time);
/* pg_stat_get_lastscan */
Datum PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan);
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);
}
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 Datum
pg_stat_get_function_calls(PG_FUNCTION_ARGS) pg_stat_get_function_calls(PG_FUNCTION_ARGS)

View File

@ -364,22 +364,22 @@ typedef struct PgStat_StatTabEntry
PgStat_Counter tuples_deleted; PgStat_Counter tuples_deleted;
PgStat_Counter tuples_hot_updated; PgStat_Counter tuples_hot_updated;
PgStat_Counter n_live_tuples; PgStat_Counter live_tuples;
PgStat_Counter n_dead_tuples; PgStat_Counter dead_tuples;
PgStat_Counter changes_since_analyze; PgStat_Counter mod_since_analyze;
PgStat_Counter inserts_since_vacuum; PgStat_Counter ins_since_vacuum;
PgStat_Counter blocks_fetched; PgStat_Counter blocks_fetched;
PgStat_Counter blocks_hit; PgStat_Counter blocks_hit;
TimestampTz vacuum_timestamp; /* user initiated vacuum */ TimestampTz last_vacuum_time; /* user initiated vacuum */
PgStat_Counter vacuum_count; PgStat_Counter vacuum_count;
TimestampTz autovac_vacuum_timestamp; /* autovacuum initiated */ TimestampTz last_autovacuum_time; /* autovacuum initiated */
PgStat_Counter autovac_vacuum_count; PgStat_Counter autovacuum_count;
TimestampTz analyze_timestamp; /* user initiated */ TimestampTz last_analyze_time; /* user initiated */
PgStat_Counter analyze_count; PgStat_Counter analyze_count;
TimestampTz autovac_analyze_timestamp; /* autovacuum initiated */ TimestampTz last_autoanalyze_time; /* autovacuum initiated */
PgStat_Counter autovac_analyze_count; PgStat_Counter autoanalyze_count;
} PgStat_StatTabEntry; } PgStat_StatTabEntry;
typedef struct PgStat_WalStats typedef struct PgStat_WalStats