| From: | Bertrand Drouvot <bertranddrouvot(dot)pg(at)gmail(dot)com> |
|---|---|
| To: | Sami Imseih <samimseih(at)gmail(dot)com> |
| Cc: | pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>, Kyotaro Horiguchi <horikyota(dot)ntt(at)gmail(dot)com>, Michael Paquier <michael(at)paquier(dot)xyz>, Lukas Fittl <lukas(at)fittl(dot)com> |
| Subject: | Re: pgstat: Flush some statistics within running transactions, take 2 |
| Date: | 2026-07-31 14:16:25 |
| Message-ID: | amyuOVEGvwOs5J0Y@bdtpg |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
On Thu, Jul 30, 2026 at 02:41:58PM -0500, Sami Imseih wrote:
> Hi,
>
> The discussion for mid-transaction flushes ended up taking place in
> the pg_stat_statements scalability thread [1], but I rather not have
> that thread become the place to review prerequisite patches. To keep
> things easier to follow, I am moving this patch back to its dedicated
> thread. The pg_stat_statements
> scalability work will follow as a patch set on top of this once this
> settles.
>
> Attaching v2 of this patch.
Thanks for the new version!
A few comments:
=== 1
void
pgstat_force_next_flush(void)
{
+ if (IsTransactionOrTransactionBlock())
+ pgstat_report_stat(true);
+
That causes issues for function stats. pgstat_function_flush_cb() returns
PGSTAT_FLUSH_DONE, then pgstat_delete_pending_entry() is called, freeing storage
still referenced by PgStat_FunctionCallUsage.fs. When the function returns,
pgstat_end_function_usage() writes through that stale pointer.
Example:
postgres=# SET track_functions = 'all';
postgres=# CREATE FUNCTION force_flush_wrapper()
RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
PERFORM pg_stat_force_next_flush();
END
$$;
postgres=# SELECT force_flush_wrapper();
postgres=# SELECT force_flush_wrapper();
postgres=# SELECT funcname, calls
FROM pg_stat_user_functions
WHERE funcid = 'force_flush_wrapper()'::regprocedure;
funcname | calls
---------------------+-------
force_flush_wrapper | 0
(1 row)
We got 0 instead of 2 but that could be worst and corrupt memory if the freed
storage is reused.
Function is a special case, see:
"
typedef struct PgStat_FunctionCallUsage
{
/* Link to function's hashtable entry (must still be there at exit!) */
/* NULL means we are not tracking the current function call */
PgStat_FunctionCounts *fs;
"
but custom statistics can have the same problem if they keep a pointer to pending
data across pgstat_force_next_flush().
I think that entry_ref->pending should not be freed by an in-transaction flush.
=== 2
- bool (*flush_pending_cb) (PgStat_EntryRef *sr, bool nowait);
+ PgStat_FlushResult(*flush_pending_cb) (PgStat_EntryRef *sr, bool nowait,
+ bool xact_boundary);
should we do the same for flush_static_cb() or exclude static callbacks from
mid-transaction flushes? (for the same reason that xact_boundary has been added
to flush_pending_cb())
=== 3
+typedef enum PgStat_FlushResult
+{
+ /* Fully flushed; the entry can be removed from the pending list. */
+ PGSTAT_FLUSH_DONE,
+
+ /*
+ * The lock could not be acquired without waiting (nowait was true). The
+ * entry must stay pending and be retried later.
+ */
+ PGSTAT_FLUSH_LOCK_CONFLICT,
+
+ /*
+ * Only part of the entry was flushed; some state was intentionally
+ * retained because it cannot be flushed in the current context (e.g.
+ * transactional counters flushed mid-transaction). The entry must stay
+ * pending and be flushed again at a suitable boundary.
+ */
+ PGSTAT_FLUSH_PARTIAL,
+} PgStat_FlushResult;
Previously, flush_pending_cb returned a bool with that meaning: false for lock
conflict and true for done.
Now 0 is PGSTAT_FLUSH_DONE and 1 is PGSTAT_FLUSH_LOCK_CONFLICT.
I think that would be better to change the enum ordering to preserve the previous
meaning. The concern is silent misbehavior in custom callbacks.
Regards,
--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Hannu Krosing | 2026-07-31 14:16:35 | Re: Support for 8-byte TOAST values, round two |
| Previous Message | Karina Litskevich | 2026-07-31 14:14:57 | Re: Implicit conversion from int64 to int32 when calling hash_get_num_entries |