Re: Redesign per-backend statistics

From: Michael Paquier <michael(at)paquier(dot)xyz>
To: Bertrand Drouvot <bertranddrouvot(dot)pg(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org, Andres Freund <andres(at)anarazel(dot)de>, Sami Imseih <samimseih(at)gmail(dot)com>
Subject: Re: Redesign per-backend statistics
Date: 2026-08-10 04:38:31
Message-ID: anlVx_TD_Q8He5uf@paquier.xyz
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Fri, Aug 07, 2026 at 12:31:47PM +0000, Bertrand Drouvot wrote:
> On Fri, Aug 07, 2026 at 10:39:04AM +0900, Michael Paquier wrote:
> an earlier POC version used arrays indexed by ProcNumber. The main concern was
> reserving storage for every possible process slot and every kind, even with
> few active processes. With that, max_connections=10000 would reserve about 33.5MB
> for the three kinds. Queries would also need to scan unused slots or use another
> structure to track active ones.

Hmm, okay, that feels like a waste. I doubt that anybody would use
that many max_connections, but if these are idle most of the time..

> I don't think that the fixed allocation would be the right design, particularly
> because it grows with MaxBackends even when most slots are unused. Since v1
> already avoids hash lookups on the flush path, I don't think the simpler access
> justifies that memory cost.

Accessing an array indexed by procnumber should be slightly cheaper
than a hash lookup when grabbing the stats of an individual backend,
as this is just a BackendPidGetProc() -> GetNumberFromPGProc() to get
a location.

>> Using one LWLock for each backend sounds costly just for more
>> correctness with the stats, and we don't have that many writes anyway?
>
> I think that an array would not remove the need for content
> synchronization.

We would need some level of concurrent protection even with an array.

> The dshash partition lock protects the entry lifetime, but the owner updates its
> cached entry without holding that lock. Queries read the entry, while shared
> and per-backend resets can modify it from another process. In particular, a
> concurrent reset with a flush could lose counters.
>
> v1 uses one LWLock per kind and live process for that.

I can see that:

+pgstat_per_backend_snapshot(PgStat_Kind kind, dshash_table *hash, void *snap)
[...]
+ while ((entry = dshash_seq_next(&hstat)) != NULL)
+ {
+ LWLockAcquire(&entry->lock, LW_SHARED);

That's a sequential scan combined with potentially hundreds of LWLocks
acquired and released successivelly. That looks expensive here for a
single IO/lock/WAL data scan. That's the level of locking required
because a mutex cannot be hold while doing external calls, and here we
have one per_backend_acc_cb callback and one
pgstat_cache_per_backend_entry(). Not sure I like much this costly
locking level. I'm concerned by this cost.
--
Michael

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Bertrand Drouvot 2026-08-10 04:40:54 Re: Split index and table statistics into different types of stats
Previous Message Ian Lawrence Barwick 2026-08-10 04:14:15 pg_control_checkpoint(): add "data_checksum_version" (Pg19)?