Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
802517f
Remove PgStat_KindInfo.named_on_disk
michaelpq Jul 1, 2024
96046c5
Use pgstat_kind_infos to read fixed shared statistics
michaelpq Jul 1, 2024
cf5ef07
Replace hardcoded identifiers of pgstats file by #defines
michaelpq Jul 3, 2024
d1268d1
Use pgstat_kind_infos to write fixed shared statistics
michaelpq Jul 9, 2024
bc0f54f
Add PgStat_KindInfo.init_shmem_cb
michaelpq Jul 11, 2024
268cb15
Add a new 'F' entry type for fixed-numbered stats in pgstats file
michaelpq Jul 11, 2024
6a7f4fe
Switch PgStat_Kind from an enum to a uint32 type
michaelpq Aug 1, 2024
d35ad4d
Add more debugging information when failing to read pgstats files
michaelpq Jul 30, 2024
575d5f3
Fix incorrect format placeholders in pgstat.c
michaelpq Aug 3, 2024
717ecca
Introduce pluggable APIs for Cumulative Statistics
michaelpq Aug 4, 2024
61cacda
Add helper routines to retrieve data for custom fixed-numbered pgstats
michaelpq Aug 5, 2024
b899a87
Fix two NULL pointer dereferences when reading custom pgstats from file
michaelpq Sep 5, 2024
64d6b8f
Add write_to_file to PgStat_KindInfo for pgstats kinds
michaelpq Nov 22, 2024
a062ad8
Move information about pgstats kinds into its own header pgstat_kind.h
michaelpq Jan 14, 2025
4d43814
Lower bounds related to pgstats kinds
michaelpq Jul 25, 2025
83ee8ed
Preserve Cloudberry statistics persistence with pluggable kinds
Alena0704 Oct 1, 2026
c6187aa
Allow custom statistics resets to preserve entry metadata
Alena0704 Oct 7, 2026
b251aef
Track per-relation cumulative time spent in [auto]vacuum and [auto]an…
michaelpq Jan 28, 2025
463bf6e
Add is_analyze parameter to vacuum_delay_point().
nathan-bossart Feb 11, 2025
1439570
Measure cost-based vacuum delay for progress reporting.
nathan-bossart Feb 11, 2025
4919bf9
Measure cost-based vacuum delay
nathan-bossart Feb 11, 2025
7fd7baf
Measure append-optimized vacuum active-phase time
Alena0704 Sep 20, 2026
0737b53
Accumulate vacuum timing for indexes and databases
Alena0704 Oct 1, 2026
ced04c7
Count vacuums that enter wraparound failsafe mode
Alena0704 Oct 1, 2026
0a10241
Measure heap and index vacuum work per call
Alena0704 Sep 9, 2026
489a764
Count vacuums interrupted by errors
Alena0704 Oct 1, 2026
bb18bc2
Count vacuum pages with unremovable dead tuples
Alena0704 Sep 9, 2026
2d59d69
Track table VM stability.
Alena0704 Mar 30, 2026
4a259e1
Count heap pages where vacuum freezes tuples
Alena0704 Sep 9, 2026
1e86b04
Report core vacuum timing for append-optimized tables
Alena0704 Oct 1, 2026
fce9e8d
Count heap pages marked all-visible by vacuum
Alena0704 Sep 9, 2026
f7c350d
Document cost-based VACUUM delay timing
Alena0704 Oct 7, 2026
3bf458e
Count vacuum runs made aggressive by the freeze age
Alena0704 Sep 9, 2026
7d15c61
Measure VACUUM buffer usage in core
Alena0704 Oct 1, 2026
e6dd6a6
Add relallfrozen to pg_class
melanieplageman Mar 3, 2025
0ad087a
Measure append-optimized vacuum work and remaining dead tuples
Alena0704 Sep 20, 2026
38c8ffa
Measure VACUUM WAL usage in core
Alena0704 Oct 1, 2026
aa98a08
Report AO active-phase time to cumulative statistics
Alena0704 Oct 7, 2026
653679f
Expose maintenance timing and visibility-map statistics in catalogs
Alena0704 Oct 7, 2026
38284e3
Store vacuum work counters in native cumulative statistics
Alena0704 Oct 7, 2026
33647dd
Expose native VACUUM work counters in catalog functions and views
Alena0704 Oct 7, 2026
45e7a81
Merge independent native VACUUM statistics branches
Alena0704 Oct 8, 2026
3bcd97e
Merge independent VACUUM resource instrumentation
Alena0704 Oct 8, 2026
ddd9959
Merge independent prerequisites for ext_vacuum_statistics
Alena0704 Oct 8, 2026
5794836
Report local VACUUM resource statistics through ext_vacuum_statistics
Alena0704 Oct 7, 2026
36fb0ad
Keep segment OID-reuse statistics warnings in the server log
Alena0704 Oct 9, 2026
e208e86
Merge updated pluggable statistics prerequisites
Alena0704 Oct 9, 2026
d7b48d8
Merge segment statistics diagnostics fix into extension prerequisites
Alena0704 Oct 9, 2026
b540641
Clarify local vacuum statistics reset scope and memory estimates
Alena0704 Oct 9, 2026
46a3f04
Report core VACUUM resources under VERBOSE without an extension hook
Alena0704 Oct 9, 2026
fd89633
Merge standalone VACUUM VERBOSE resource reporting
Alena0704 Oct 9, 2026
6af4030
Introduce the VACUUM reporting hook with its extension consumer
Alena0704 Oct 9, 2026
dc4717d
Merge single-query visibility-map count collection
Alena0704 Oct 9, 2026
d8c19f5
Fetch both visibility-map counts in one segment query
Alena0704 Oct 9, 2026
4aeb85f
Merge single-query visibility-map count collection
Alena0704 Oct 9, 2026
ddbf2f3
Add a native reset for VACUUM work counters
Alena0704 Oct 9, 2026
26d909e
Merge native VACUUM work reset into extension prerequisites
Alena0704 Oct 9, 2026
169cd5b
Merge native VACUUM work reset
Alena0704 Oct 9, 2026
43b1a72
Read native VACUUM work counters from extension views
Alena0704 Oct 9, 2026
f9d6bbe
Include cluster VACUUM resource views and resets with the extension
Alena0704 Oct 9, 2026
3011f96
Test native VACUUM cluster timing without the extension
Alena0704 Oct 9, 2026
60a7cf4
Merge core VACUUM timing regression coverage
Alena0704 Oct 9, 2026
1c9b89b
Keep native VACUUM regressions in the core timing patch
Alena0704 Oct 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ SUBDIRS = \
tsm_system_rows \
tsm_system_time \
unaccent \
ext_vacuum_statistics \
vacuumlo

# Cloudberry-specific additions (to ease merge pain).
Expand Down
4 changes: 2 additions & 2 deletions contrib/bloom/blvacuum.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
*itupPtr,
*itupEnd;

vacuum_delay_point();
vacuum_delay_point(false);

buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
Expand Down Expand Up @@ -191,7 +191,7 @@ blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
Buffer buffer;
Page page;

vacuum_delay_point();
vacuum_delay_point(false);

buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
RBM_NORMAL, info->strategy);
Expand Down
5 changes: 5 additions & 0 deletions contrib/ext_vacuum_statistics/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Generated subdirectories
/log/
/results/
/tmp_check/
/output_iso/
31 changes: 31 additions & 0 deletions contrib/ext_vacuum_statistics/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# contrib/ext_vacuum_statistics/Makefile

EXTENSION = ext_vacuum_statistics
MODULE_big = ext_vacuum_statistics
OBJS = vacuum_statistics.o
DATA = ext_vacuum_statistics--1.0.sql
PGFILEDESC = "ext_vacuum_statistics - convenience views for extended vacuum statistics"

TAP_TESTS = 1

NO_INSTALLCHECK = 1

ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/ext_vacuum_statistics
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif

# Cloudberry: the test of the cluster-wide views needs a running cluster
# with the module in shared_preload_libraries of every instance, which the
# temporary instances of "make check" are not, so it has a target of its
# own, run against such a cluster.
.PHONY: installcheck-cluster

installcheck-cluster:
$(pg_regress_installcheck) --dbname=contrib_regression_vacstat gp_vacuum_statistics
256 changes: 256 additions & 0 deletions contrib/ext_vacuum_statistics/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
# ext_vacuum_statistics

Extended vacuum statistics extension for PostgreSQL. It collects and exposes detailed per-table, per-index, and per-database vacuum statistics (buffer I/O, WAL, general, timing) via convenient views in the `ext_vacuum_statistics` schema.

## Installation

```
./configure tmp_install="$(pwd)/my/inst"
make clean && make && make install
cd contrib/ext_vacuum_statistics
make && make install
```

It is essential that the extension is listed in `shared_preload_libraries` because it registers a vacuum hook at server startup.

In your `postgresql.conf`:

```
shared_preload_libraries = 'ext_vacuum_statistics'
```

Restart PostgreSQL.

In your database:

```sql
CREATE EXTENSION ext_vacuum_statistics;
```

## Usage

From a Cloudberry coordinator, query statistics across the cluster:

```sql
-- Per-table heap vacuum statistics, with gp_segment_id
SELECT * FROM ext_vacuum_statistics.gp_stats_vacuum_tables;

-- Per-index vacuum statistics
SELECT * FROM ext_vacuum_statistics.gp_stats_vacuum_indexes;

-- Per-database aggregate vacuum statistics
SELECT * FROM ext_vacuum_statistics.gp_stats_vacuum_database;
```

The corresponding `pg_stats_vacuum_*` views read only the connected instance.
Use them for a standalone server or a utility connection to a single segment.
Use the `gp_stats_vacuum_*_summary` views for cluster totals.

Example projection of table statistics:

```
relname | total_blks_read | total_blks_hit | wal_records | tuples_deleted | pages_removed
-----------+-----------------+----------------+-------------+----------------+---------------
mytable | 120 | 340 | 15 | 500 | 10
```

Reset statistics across the cluster from the coordinator:

```sql
SELECT ext_vacuum_statistics.gp_vacuum_statistics_reset();
```

These functions reset only extension-owned metrics; native work is unchanged.
Use the `gp_` wrappers from a normal coordinator connection to reset them
on the coordinator and all primary segments.

**Local functions reset only the current node.** Calling
`ext_vacuum_statistics.vacuum_statistics_reset()` on the coordinator (QD)
resets only the coordinator's counters; segment counters remain unchanged.
The same applies to `extvac_reset_entry()` and `extvac_reset_db_entry()`.
Use the local functions for a utility connection to an individual segment.

All functions below belong to the `ext_vacuum_statistics` schema:

| Reset scope | Cluster wrapper (call on the coordinator) | Local function (current node only) |
|-------------|------------------------------------------|-----------------------------------|
| One table or index | `gp_extvac_reset_entry(dboid, relid)` | `extvac_reset_entry(dboid, relid)` |
| One database and all its relations | `gp_extvac_reset_db_entry(dboid)` | `extvac_reset_db_entry(dboid)` |
| All databases | `gp_vacuum_statistics_reset()` | `vacuum_statistics_reset()` |

For example, reset only the current database across the cluster:

```sql
SELECT ext_vacuum_statistics.gp_extvac_reset_db_entry(oid)
FROM pg_database WHERE datname = current_database();
```

## Configuration (GUCs)

| GUC | Default | Description |
|-----|---------|-------------|
| `vacuum_statistics.enabled` | on | Collect extension resource metrics; native work obeys `track_counts` |

## Memory usage

Each tracked object (table or index) uses a fixed-size shared memory entry; the exact size depends on the platform.

Per-database aggregates add one entry per tracked database. Entry size includes
pgstat bookkeeping; memory estimates must use the structures of the actual
build rather than a fixed byte count from an earlier version.

The entry of a table or an index is dropped when the relation is dropped (at
commit, so a rolled back `DROP` keeps it), and a new relation that gets the OID
of an old one starts from zero. The module does that with an
`object_access_hook`.

## Recipes

**Disable extension resource collection temporarily (native work continues):**

```sql
SET vacuum_statistics.enabled = off;
```

## Views

| View | Description |
|------|-------------|
| `ext_vacuum_statistics.pg_stats_vacuum_tables` | Per-table heap vacuum stats (pages scanned, tuples deleted and resource usage) |
| `ext_vacuum_statistics.pg_stats_vacuum_indexes` | Per-index vacuum stats |
| `ext_vacuum_statistics.pg_stats_vacuum_database` | Per-database aggregate vacuum stats |

## Limitations

- Must be loaded via `shared_preload_libraries`; it cannot be loaded on demand.
- Starting a server without the module, even once, makes it treat the whole
statistics file as corrupted and reset all cumulative statistics, the
built-in ones included. Use `vacuum_statistics.enabled = off` rather than
removing the module.

## Native work counters

Heap, index and AO work counters are accumulated once, by native pgstat.
The extension's table and index views read those same counters through
`pg_stat_get_vacuum_stats()`, alongside separately stored buffer, WAL and I/O
measurements. They have the same work-counter history as `pg_stat_vacuum_tables`,
`pg_stat_vacuum_indexes` and their `gp_stat_*` counterparts; enabling the
extension does not start a second history.

Work counters obey `track_counts`. `vacuum_statistics.enabled` controls only
extension resource metrics.
With extension collection disabled, native work remains visible in these views.
Relations without a resource entry show zero resource counters.

Extension reset functions clear only the extension's own metrics, without
touching native work or any other core statistics. To reset native work, use
`pg_stat_reset_vacuum_stats(relid)` for one table or index, or
`pg_stat_reset_vacuum_stats()` for the current database and its non-shared
relations. These functions preserve native timing, vacuum/analyze invocation
counts, and other statistics. On Cloudberry, call the corresponding
`gp_stat_reset_vacuum_stats(relid)` or `gp_stat_reset_vacuum_stats()` on the
coordinator to reach all primary segments. The broader native reset
`pg_stat_reset_single_table_counters()`
clears native work but leaves extension resources intact; `pg_stat_reset()`
clears both for the current database. The two sets of metrics can therefore
cover different periods after a reset or a change in collection settings.

The resource getter signatures and shared payload changed in this development
series. Rebuild the server and extension together and recreate the extension's
SQL objects when updating an earlier 1.0 installation. The new statistics-file
format discards previously saved counters; the new core function also requires
the matching catalog version.

## Cloudberry

Each instance (the coordinator and every segment) keeps the statistics of the
vacuums it runs itself. The local `pg_stats_vacuum_*` views show only that
instance; use `gp_stats_vacuum_*` to read the coordinator and primary segments.

Install the matching extension library, control and SQL files in the Cloudberry
installation on every host, including mirror and standby coordinator hosts.
`gpconfig` changes configuration files; it does not distribute extension files.
Load the module on every instance so it is also available after promotion.

Inspect both the active setting and the configuration files first:

```sh
gpconfig -s shared_preload_libraries
gpconfig -s shared_preload_libraries --file
```

When the existing list is empty, configure it with:

```sh
gpconfig -c shared_preload_libraries -v 'ext_vacuum_statistics'
```

Otherwise pass the complete existing list with `ext_vacuum_statistics` appended.
Preserve any intentional differences between coordinator, primary and mirror
settings; do not replace their other preloaded libraries. With `-v` and no
role restriction, `gpconfig` updates the coordinator, standby, primaries and
mirrors. Resolve any reported unreachable hosts before relying on their setup.
Check the resulting files, then restart the cluster to load the library:

```sh
gpconfig -s shared_preload_libraries --file
gpstop -ar
gpconfig -s shared_preload_libraries --file-compare
```

A configuration reload (`gpstop -u`) alone cannot load a new preload library.
Check that mirror and standby instances also restarted successfully. After the
restart, run the following on the coordinator in each database where the views
are needed; `CREATE EXTENSION` is dispatched to the segments:

```sql
CREATE EXTENSION IF NOT EXISTS ext_vacuum_statistics;
```

Cluster-wide views, like the `gp_stat_*` views of the core:

| View | Description |
|------|-------------|
| `ext_vacuum_statistics.gp_stats_vacuum_tables` | `pg_stats_vacuum_tables` of every instance, with `gp_segment_id` (-1 for the coordinator) |
| `ext_vacuum_statistics.gp_stats_vacuum_indexes` | the same for indexes |
| `ext_vacuum_statistics.gp_stats_vacuum_database` | the same for databases |
| `ext_vacuum_statistics.gp_stats_vacuum_tables_summary` | one row per table: summed over the segments (divided by their number for replicated tables); catalogs as on the coordinator |
| `ext_vacuum_statistics.gp_stats_vacuum_indexes_summary` | the same for indexes |
| `ext_vacuum_statistics.gp_stats_vacuum_database_summary` | one row per database, summed over all instances |

The reset functions without the `gp_` prefix act only on the connected instance;
`gp_vacuum_statistics_reset()`, `gp_extvac_reset_entry(dboid, relid)` and
`gp_extvac_reset_db_entry(dboid)` dispatch the resets from the coordinator to
all primary segments and also reset the coordinator. A `SET` of
`vacuum_statistics.enabled` on the coordinator is passed on to the segments.

The counters are local pgstat state and are not replicated through WAL.
Preloading on a mirror enables collection after promotion; it does not copy
its primary's accumulated counters. A promoted instance reports its own local
statistics, so it cannot continue the former primary's counter history. This
also applies when the standby coordinator is promoted. A compatible clean
restart can preserve an instance's own counters; crash recovery resets them.

Treat promotion as a new measurement interval for the affected instance, even
if its `gp_segment_id` is unchanged. Other instances keep their own counters,
but cluster summaries can decrease when a primary is replaced. Monitoring
should retain previous samples externally and begin a new baseline after
failover, without interpreting the change as negative vacuum work.

The test of the cluster-wide views runs against such a cluster:

```
make -C contrib/ext_vacuum_statistics installcheck-cluster
```

Reset functions return `void` and require superuser privileges by default.
An administrator can delegate access with `GRANT EXECUTE`; cluster wrappers
also require permission to execute the corresponding local reset function.
An extension relation reset clears only that relation's resource counters, leaving its indexes and
the database aggregate unchanged. A database reset clears its aggregate and
all its relation entries. The global reset affects all databases on the current
instance; the `gp_` wrappers apply these operations on the coordinator and all
primary segments.
Existing rows remain visible with zero extension counters after a reset.
Native work counters remain unchanged. `pg_stat_reset()` also resets the
extension's entries for the current database. Resetting does not remove the type of a table, index, or database entry.
Loading
Loading