Skip to content

Commit 4f74fa3

Browse files
author
Commitfest Bot
committed
[CF 6639] v14 - Track skipped vacuum and analyze in pg_stat_all_tables
This branch was automatically generated by a robot using patches from an email thread registered at: https://commitfest.postgresql.org/patch/6639 The branch will be overwritten each time a new patch version is posted to the thread, and also periodically to check for bitrot caused by changes on the master branch. Patch(es): https://www.postgresql.org/message-id/20260728232710.a00f54d1136b788437b2eb7e@sraoss.co.jp Author(s): Yugo Nagata
2 parents 3c982c9 + b797e5b commit 4f74fa3

14 files changed

Lines changed: 766 additions & 35 deletions

File tree

doc/src/sgml/monitoring.sgml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4683,6 +4683,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
46834683
</para></entry>
46844684
</row>
46854685

4686+
<row>
4687+
<entry role="catalog_table_entry"><para role="column_definition">
4688+
<structfield>last_lock_skipped_vacuum</structfield> <type>timestamp with time zone</type>
4689+
</para>
4690+
<para>
4691+
Last time a manual vacuum on this table was attempted but skipped due to
4692+
lock unavailability (not counting <command>VACUUM FULL</command>)
4693+
</para></entry>
4694+
</row>
4695+
46864696
<row>
46874697
<entry role="catalog_table_entry"><para role="column_definition">
46884698
<structfield>last_autovacuum</structfield> <type>timestamp with time zone</type>
@@ -4693,6 +4703,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
46934703
</para></entry>
46944704
</row>
46954705

4706+
<row>
4707+
<entry role="catalog_table_entry"><para role="column_definition">
4708+
<structfield>last_lock_skipped_autovacuum</structfield> <type>timestamp with time zone</type>
4709+
</para>
4710+
<para>
4711+
Last time a vacuum on this table by the autovacuum daemon was attempted
4712+
but skipped due to lock unavailability
4713+
</para></entry>
4714+
</row>
4715+
46964716
<row>
46974717
<entry role="catalog_table_entry"><para role="column_definition">
46984718
<structfield>last_analyze</structfield> <type>timestamp with time zone</type>
@@ -4702,6 +4722,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47024722
</para></entry>
47034723
</row>
47044724

4725+
<row>
4726+
<entry role="catalog_table_entry"><para role="column_definition">
4727+
<structfield>last_lock_skipped_analyze</structfield> <type>timestamp with time zone</type>
4728+
</para>
4729+
<para>
4730+
Last time a manual analyze on this table was attempted but skipped due to
4731+
lock unavailability
4732+
</para></entry>
4733+
</row>
4734+
47054735
<row>
47064736
<entry role="catalog_table_entry"><para role="column_definition">
47074737
<structfield>last_autoanalyze</structfield> <type>timestamp with time zone</type>
@@ -4712,6 +4742,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47124742
</para></entry>
47134743
</row>
47144744

4745+
<row>
4746+
<entry role="catalog_table_entry"><para role="column_definition">
4747+
<structfield>last_lock_skipped_autoanalyze</structfield> <type>timestamp with time zone</type>
4748+
</para>
4749+
<para>
4750+
Last time at which an analyze on this table by the autovacuum was
4751+
attempted but skipped due to lock unavailability
4752+
</para></entry>
4753+
</row>
4754+
47154755
<row>
47164756
<entry role="catalog_table_entry"><para role="column_definition">
47174757
<structfield>vacuum_count</structfield> <type>bigint</type>
@@ -4722,6 +4762,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47224762
</para></entry>
47234763
</row>
47244764

4765+
<row>
4766+
<entry role="catalog_table_entry"><para role="column_definition">
4767+
<structfield>lock_skipped_vacuum_count</structfield> <type>bigint</type>
4768+
</para>
4769+
<para>
4770+
Number of times manual vacuums on this table have been attempted but skipped
4771+
due to lock unavailability (not counting <command>VACUUM FULL</command>)
4772+
</para></entry>
4773+
</row>
4774+
47254775
<row>
47264776
<entry role="catalog_table_entry"><para role="column_definition">
47274777
<structfield>autovacuum_count</structfield> <type>bigint</type>
@@ -4732,6 +4782,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47324782
</para></entry>
47334783
</row>
47344784

4785+
<row>
4786+
<entry role="catalog_table_entry"><para role="column_definition">
4787+
<structfield>lock_skipped_autovacuum_count</structfield> <type>bigint</type>
4788+
</para>
4789+
<para>
4790+
Number of times vacuums on this table by the autovacuum daemon have been
4791+
attempted but skipped due to lock unavailability
4792+
</para></entry>
4793+
</row>
4794+
47354795
<row>
47364796
<entry role="catalog_table_entry"><para role="column_definition">
47374797
<structfield>analyze_count</structfield> <type>bigint</type>
@@ -4741,6 +4801,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47414801
</para></entry>
47424802
</row>
47434803

4804+
<row>
4805+
<entry role="catalog_table_entry"><para role="column_definition">
4806+
<structfield>lock_skipped_analyze_count</structfield> <type>bigint</type>
4807+
</para>
4808+
<para>
4809+
Number of times manual analyzes on this table have been attempted but
4810+
skipped due to lock unavailability
4811+
</para></entry>
4812+
</row>
4813+
47444814
<row>
47454815
<entry role="catalog_table_entry"><para role="column_definition">
47464816
<structfield>autoanalyze_count</structfield> <type>bigint</type>
@@ -4751,6 +4821,16 @@ description | Waiting for a newly initialized WAL file to reach durable storage
47514821
</para></entry>
47524822
</row>
47534823

4824+
<row>
4825+
<entry role="catalog_table_entry"><para role="column_definition">
4826+
<structfield>lock_skipped_autoanalyze_count</structfield> <type>bigint</type>
4827+
</para>
4828+
<para>
4829+
Number of times analyzes on this table by the autovacuum daemon have
4830+
been attempted but skipped due to lock unavailability
4831+
</para></entry>
4832+
</row>
4833+
47544834
<row>
47554835
<entry role="catalog_table_entry"><para role="column_definition">
47564836
<structfield>total_vacuum_time</structfield> <type>double precision</type>
@@ -4806,6 +4886,14 @@ description | Waiting for a newly initialized WAL file to reach durable storage
48064886
</tgroup>
48074887
</table>
48084888

4889+
<note>
4890+
<para>
4891+
When a manual vacuum or analyze on a parent table in an inheritance or
4892+
partitioning hierarchy is skipped, the statistics are recorded only for
4893+
the parent table, not for its children.
4894+
</para>
4895+
</note>
4896+
48094897
</sect2>
48104898

48114899
<sect2 id="monitoring-pg-stat-autovacuum-scores-view">

src/backend/catalog/system_views.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -736,13 +736,21 @@ CREATE VIEW pg_stat_all_tables AS
736736
pg_stat_get_mod_since_analyze(C.oid) AS n_mod_since_analyze,
737737
pg_stat_get_ins_since_vacuum(C.oid) AS n_ins_since_vacuum,
738738
pg_stat_get_last_vacuum_time(C.oid) as last_vacuum,
739+
pg_stat_get_last_lock_skipped_vacuum_time(C.oid) as last_lock_skipped_vacuum,
739740
pg_stat_get_last_autovacuum_time(C.oid) as last_autovacuum,
741+
pg_stat_get_last_lock_skipped_autovacuum_time(C.oid) as last_lock_skipped_autovacuum,
740742
pg_stat_get_last_analyze_time(C.oid) as last_analyze,
743+
pg_stat_get_last_lock_skipped_analyze_time(C.oid) as last_lock_skipped_analyze,
741744
pg_stat_get_last_autoanalyze_time(C.oid) as last_autoanalyze,
745+
pg_stat_get_last_lock_skipped_autoanalyze_time(C.oid) as last_lock_skipped_autoanalyze,
742746
pg_stat_get_vacuum_count(C.oid) AS vacuum_count,
747+
pg_stat_get_lock_skipped_vacuum_count(C.oid) AS lock_skipped_vacuum_count,
743748
pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count,
749+
pg_stat_get_lock_skipped_autovacuum_count(C.oid) AS lock_skipped_autovacuum_count,
744750
pg_stat_get_analyze_count(C.oid) AS analyze_count,
751+
pg_stat_get_lock_skipped_analyze_count(C.oid) AS lock_skipped_analyze_count,
745752
pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count,
753+
pg_stat_get_lock_skipped_autoanalyze_count(C.oid) AS lock_skipped_autoanalyze_count,
746754
pg_stat_get_total_vacuum_time(C.oid) AS total_vacuum_time,
747755
pg_stat_get_total_autovacuum_time(C.oid) AS total_autovacuum_time,
748756
pg_stat_get_total_analyze_time(C.oid) AS total_analyze_time,

src/backend/commands/vacuum.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,8 +813,26 @@ vacuum_open_relation(Oid relid, RangeVar *relation, uint32 options,
813813
rel = try_relation_open(relid, NoLock);
814814
else
815815
{
816+
int flags = 0;
817+
816818
rel = NULL;
817819
rel_lock = false;
820+
821+
if ((options & VACOPT_VACUUM) != 0 && (options & VACOPT_FULL) == 0)
822+
{
823+
if (AmAutoVacuumWorkerProcess())
824+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_AUTOVACUUM;
825+
else
826+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_VACUUM;
827+
}
828+
if ((options & VACOPT_ANALYZE) != 0)
829+
{
830+
if (AmAutoVacuumWorkerProcess())
831+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_AUTOANALYZE;
832+
else
833+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_ANALYZE;
834+
}
835+
pgstat_report_skipped_vacuum_analyze(relid, flags);
818836
}
819837

820838
/* if relation is opened, leave */
@@ -950,6 +968,8 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
950968
*/
951969
if (!OidIsValid(relid))
952970
{
971+
int flags = 0;
972+
953973
if (options & VACOPT_VACUUM)
954974
ereport(WARNING,
955975
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
@@ -960,6 +980,24 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
960980
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
961981
errmsg("skipping analyze of \"%s\" --- lock not available",
962982
vrel->relation->relname)));
983+
984+
/*
985+
* Get relid for statistics reporting.
986+
*
987+
* Since we failed to acquire the lock, use NoLock here. Although
988+
* a concurrent DDL may have dropped or renamed the relation,
989+
* RangeVarGetRelid() with NoLock does not check for invalidation
990+
* messages.
991+
*/
992+
relid = RangeVarGetRelid(vrel->relation, NoLock, true);
993+
994+
if ((options & VACOPT_VACUUM) != 0 && (options & VACOPT_FULL) == 0)
995+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_VACUUM;
996+
if ((options & VACOPT_ANALYZE) != 0)
997+
flags |= PGSTAT_REPORT_LOCK_SKIPPED_ANALYZE;
998+
999+
pgstat_report_skipped_vacuum_analyze(relid, flags);
1000+
9631001
return vacrels;
9641002
}
9651003

src/backend/utils/activity/pgstat_relation.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@
1717

1818
#include "postgres.h"
1919

20+
#include "access/htup_details.h"
2021
#include "access/twophase_rmgr.h"
2122
#include "access/xact.h"
2223
#include "catalog/catalog.h"
24+
#include "utils/injection_point.h"
25+
#include "utils/inval.h"
2326
#include "utils/memutils.h"
2427
#include "utils/pgstat_internal.h"
2528
#include "utils/rel.h"
29+
#include "utils/syscache.h"
2630
#include "utils/timestamp.h"
2731

2832

@@ -420,6 +424,89 @@ pgstat_report_analyze(Relation rel,
420424
(void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO);
421425
}
422426

427+
/*
428+
* Report that the table was skipped during vacuum or/and analyze.
429+
*/
430+
void
431+
pgstat_report_skipped_vacuum_analyze(Oid relid, int flags)
432+
{
433+
PgStat_EntryRef *entry_ref;
434+
PgStatShared_Relation *shtabentry;
435+
PgStat_StatTabEntry *tabentry;
436+
TimestampTz ts;
437+
HeapTuple classTup;
438+
bool isshared;
439+
440+
if (!pgstat_track_counts || !flags)
441+
return;
442+
443+
classTup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
444+
if (!HeapTupleIsValid(classTup))
445+
return; /* somebody deleted the rel, forget it */
446+
isshared = ((Form_pg_class) GETSTRUCT(classTup))->relisshared;
447+
ReleaseSysCache(classTup);
448+
INJECTION_POINT("skipped-vacuum-analyze-before-entry-lock", NULL);
449+
450+
/* Store the data in the table's hash table entry. */
451+
ts = GetCurrentTimestamp();
452+
453+
entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_RELATION,
454+
isshared ? InvalidOid : MyDatabaseId,
455+
relid, false);
456+
457+
/*
458+
* Re-check whether the relation still exists. Unlike the normal stats
459+
* reporting path, we don't hold a relation lock here (the whole point of
460+
* SKIP_LOCKED is that we failed to acquire one). Without a lock, a
461+
* concurrent DROP TABLE could commit between our earlier syscache lookup
462+
* and the stats entry creation above, leaving an orphaned stats entry.
463+
*
464+
* Accept cache invalidation messages first, so that a DROP that committed
465+
* after our earlier check is visible to the syscache lookup below.
466+
*/
467+
AcceptInvalidationMessages();
468+
classTup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
469+
if (!HeapTupleIsValid(classTup))
470+
{
471+
pgstat_unlock_entry(entry_ref);
472+
pgstat_drop_entry(PGSTAT_KIND_RELATION,
473+
isshared ? InvalidOid : MyDatabaseId, relid, true);
474+
return;
475+
}
476+
ReleaseSysCache(classTup);
477+
478+
shtabentry = (PgStatShared_Relation *) entry_ref->shared_stats;
479+
tabentry = &shtabentry->stats;
480+
481+
if (flags & PGSTAT_REPORT_LOCK_SKIPPED_VACUUM)
482+
{
483+
tabentry->last_lock_skipped_vacuum_time = ts;
484+
tabentry->lock_skipped_vacuum_count++;
485+
}
486+
else if (flags & PGSTAT_REPORT_LOCK_SKIPPED_AUTOVACUUM)
487+
{
488+
tabentry->last_lock_skipped_autovacuum_time = ts;
489+
tabentry->lock_skipped_autovacuum_count++;
490+
}
491+
492+
if (flags & PGSTAT_REPORT_LOCK_SKIPPED_ANALYZE)
493+
{
494+
tabentry->last_lock_skipped_analyze_time = ts;
495+
tabentry->lock_skipped_analyze_count++;
496+
}
497+
else if (flags & PGSTAT_REPORT_LOCK_SKIPPED_AUTOANALYZE)
498+
{
499+
tabentry->last_lock_skipped_autoanalyze_time = ts;
500+
tabentry->lock_skipped_autoanalyze_count++;
501+
}
502+
503+
pgstat_unlock_entry(entry_ref);
504+
505+
/* see pgstat_report_vacuum() */
506+
pgstat_flush_io(false);
507+
(void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO);
508+
}
509+
423510
/*
424511
* count a tuple insertion of n tuples
425512
*/

src/backend/utils/adt/pgstatfuncs.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ PG_STAT_GET_RELENTRY_INT64(mod_since_analyze)
8484
/* pg_stat_get_numscans */
8585
PG_STAT_GET_RELENTRY_INT64(numscans)
8686

87+
/* pg_stat_get_lock_skipped_analyze_count */
88+
PG_STAT_GET_RELENTRY_INT64(lock_skipped_analyze_count)
89+
90+
/* pg_stat_get_lock_skipped_autoanalyze_count */
91+
PG_STAT_GET_RELENTRY_INT64(lock_skipped_autoanalyze_count)
92+
93+
/* pg_stat_get_lock_skipped_autovacuum_count */
94+
PG_STAT_GET_RELENTRY_INT64(lock_skipped_autovacuum_count)
95+
96+
/* pg_stat_get_lock_skipped_vacuum_count */
97+
PG_STAT_GET_RELENTRY_INT64(lock_skipped_vacuum_count)
98+
8799
/* pg_stat_get_tuples_deleted */
88100
PG_STAT_GET_RELENTRY_INT64(tuples_deleted)
89101

@@ -204,6 +216,18 @@ PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_vacuum_time)
204216
/* pg_stat_get_lastscan */
205217
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(lastscan)
206218

219+
/* pg_stat_get_last_lock_skipped_analyze_time */
220+
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_lock_skipped_analyze_time)
221+
222+
/* pg_stat_get_last_lock_skipped_autoanalyze_time */
223+
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_lock_skipped_autoanalyze_time)
224+
225+
/* pg_stat_get_last_lock_skipped_autovacuum_time */
226+
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_lock_skipped_autovacuum_time)
227+
228+
/* pg_stat_get_last_lock_skipped_vacuum_time */
229+
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(last_lock_skipped_vacuum_time)
230+
207231
/* pg_stat_get_stat_reset_time */
208232
PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat_reset_time)
209233

0 commit comments

Comments
 (0)