<#2108 [Ideas] pluggable cumulative statistics in ...
# general
g
#2108 [Ideas] pluggable cumulative statistics in Cloudberry New discussion created by Alena0704 Description Proposal: pluggable cumulative statistics in Cloudberry The idea and intended result Pluggable cumulative statistics let extensions define their own statistics and store them through the same infrastructure as built-in statistics. An extension registers a statistics kind describing its data, and the common system provides shared-memory storage, reads, resets, and persistence across clean restarts. We want new statistics and their SQL interfaces to evolve in extensions. Adding an extension-owned metric should not require adding a built-in catalog function or system-view column and bumping the core catalog version for that change. Extensions should also be able to reuse the common statistics store instead of implementing storage, synchronization, resets, and persistence independently. Pluggable statistics provide the storage mechanism. The extension author decides what to count, where to update the counters, and how to expose them through SQL. New measurement points may still require core hooks. How extensions and users would use it An extension developer defines counters, registers their kind at server startup, and connects measurement code or reporting hooks to updates of those counters. The extension supplies SQL functions and views for reading the values, plus any collection controls and reset functions it needs. An operator loads the module through
shared_preload_libraries
, restarts the server, and installs the extension's SQL objects in the relevant databases. Monitoring then queries the extension's views and compares observations over time, accounting for resets. In Cloudberry, the extension also defines how local observations are exposed and aggregated across the coordinator and segments. This gives each consumer control over its metrics and SQL interface while keeping storage and lifecycle operations in the common cumulative-statistics system. The VACUUM example below follows this path from measurement to SQL. What Cloudberry has today and why it is insufficient Before the proposed port, Cloudberry already has a cumulative-statistics infrastructure for built-in kinds, including Cloudberry-specific resource-queue statistics. What is missing is the supported registration API that lets extensions define their own kinds and participate in that infrastructure. There are two existing approaches to adding statistics, each with a limitation: | Approach | Limitation | | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ | | Add a built-in statistics kind or extend existing core statistics and SQL interfaces | Metric-specific changes become core changes; adding catalog functions or system-view columns also requires catalog maintenance | | Keep statistics in an extension-owned store | The extension must maintain its own storage, synchronization, reset, and persistence behavior | For example,
pg_stat_statements
maintains its own shared hash table with a limit set by
pg_stat_statements.max
and removes entries when it fills up. This illustrates the separate storage machinery an extension maintains today. pg_stat_statements implementation The common cumulative-statistics system also uses a hash table, backed by dynamic shared memory. It allocates memory as entries are added, without a configured entry-count limit like
pg_stat_statements.max
. Making this store available to custom kinds would let extensions reuse it. Statistics memory allocation Proposed implementation and how it works This mechanism has already been added to PostgreSQL and is documented in PostgreSQL 19. PR #2102 proposes bringing it to Cloudberry by cherry-picking the upstream commits and adapting them, including preservation of Cloudberry-specific resource-queue statistics. The implementation extends the existing cumulative-statistics infrastructure with registration and access APIs. Its operation and division of responsibilities are described first, followed by the commits that introduce them. Registration and storage An extension describes a statistics kind with
PgStat_KindInfo
and registers it through
pgstat_register_kind()
while loading through
shared_preload_libraries
. Two object models are supported: | Model | Example use | | ---------------------------- | -------------------------------------------------- | | Fixed-numbered statistics | A fixed set of counters for a subsystem | | Variable-numbered statistics | Separate entries for tables, indexes, or databases | The kind descriptor defines the data layout, storage properties, and applicable callbacks. Extensions can use pending local updates with callbacks to flush them into shared memory. The
write_to_file
property controls whether statistics participate in persistence. The PR also adds an optional
reset_data_cb
for variable-numbered kinds. It lets a reset clear counters while preserving identifying metadata in the entry payload. Without the callback, the existing zero-fill behavior remains. PR #2102 Limitations Dynamic allocation does not guarantee that a statistics update will succeed when memory is exhausted. Variable-numbered kinds share the cumulative-statistics memory infrastructure. Their memory use grows with the number of tracked objects and the size of each entry, with additional overhead for the shared hash table, backend-local references, pending updates, and snapshots. There is no per-kind entry-count limit or automatic eviction policy comparable to
pg_stat_statements.max
. When a new entry is needed, the current implementation inserts it into the shared hash table and allocates its payload with
dsa_allocate0()
. This allocation does not use `DSA_ALLOC_NO_OOM`: if memory cannot be allocated, the allocator raises
ERROR
. The infrastructure therefore does not guarantee that it will simply skip a statistics sample under memory pressure. The error can propagate to the operation collecting the statistics, including a VACUUM reporting through an extension hook. See the local implementation in <../src/backend/utils/activity/pgstat_shmem.c|pgstat_shmem.c>, <../src/include/utils/dsa.h|dsa.h>, and <../src/backend/utils/mmgr/dsa.c|dsa.c>. This makes memory budgeting and cleanup part of extension design. Extensions should keep payloads compact, avoid unnecessarily high-cardinality keys, and connect object deletion to entry cleanup. A per-kind quota, eviction policy, or a safe way to drop a sample on allocation failure would require additional design; the proposed API does not provide these guarantees. Memory-pressure tests should establish both the error seen by the caller and whether subsequent collection remains usable. Other limitations also affect consumers: • Custom kind IDs are limited to 24–32 and must be unique across loaded extensions. Registration happens during preload, so enabling a new module requires a restart. • Shared-entry locking, pending-update flushing, and snapshot creation have a cost. The API does not guarantee negligible overhead under frequent updates or concurrent access. • Re… apache/cloudberry