| From: | Sami Imseih <samimseih(at)gmail(dot)com> |
|---|---|
| To: | Bertrand Drouvot <bertranddrouvot(dot)pg(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-08-06 23:23:53 |
| Message-ID: | CAA5RZ0tAh6w+Tsia2=qGhcfp2wawHXd34AxiH59i+7hnnihX_A@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
Thanks for the review!
> At minimum that should be documented but I think a cleaner fix would be to
> separate pending lifetime from queue membership, so that PGSTAT_FLUSH_DONE
> removes an entry from the work queue while retaining its storage.
After discussing offline, I don't think I like the idea of an
extension having to set a flag to force a re-scan. It's not
a very clear API, so your idea of re-queueing and for this
to happen transparently is important. Initially, I was hesitant
to manipulate the pending list, but after playing around with this,
I think it's doable and the best way to proceed. We can
have a flag on entry_ref called flushed_this_pass which is
set to true whenever we flush it, even partially, but not on a
lock conflict, where nothing was flushed. Then, whenever
pgstat_prep_pending_from_entry_ref() is called again and the
entry is seen as having been flushed, we move it to the tail
so the ongoing scan can find it again.
```
@@ -1388,8 +1396,18 @@
pgstat_prep_pending_from_entry_ref(PgStat_EntryRef *entry_ref)
}
entry_ref->pending =
MemoryContextAllocZero(pgStatPendingContext, entrysize);
+ entry_ref->flushed_this_pass = false;
dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
}
+ else if (entry_ref->flushed_this_pass)
+ {
+ /*
+ * The entry is already pending and was already
visited in the current
+ * flush pass. Move it to the tail so the data just
accumulated into
+ * it is flushed again before the pass ends.
+ */
+ dlist_move_tail(&pgStatPending, &entry_ref->pending_node);
+ }
}
```
That is the crux of the fix. The flush loop clears the flag on the
current entry before invoking its callback, so a callback that
accumulates into its own entry does not re-queue itself, and the next
pointer is determined after the callback returns, so a re-queued entry
is always picked up by the ongoing scan.
With regards to the still relevant points you raised:
==
> I think that pgstat_report_analyze() should subtract only the unflushed
> delta, means:
>
> deadtuples -= rel->pgstat_info->counts.delta_dead_tuples - rel->pgstat_info->flushed.delta_dead_tuples;
done
==
> However, changed_tuples is cumulative and truncate does not reset the shared
> mod_since_analyze counter. Resetting flushed.changed_tuples to zero can
> therefore publish changes that were already published.
>
> I don't think flushed.changed_tuples should be reset here.
done.
===
> Both truncdropped values are then true. A subsequent truncate leaves
> counts.truncdropped true, so the condition does not become true again and
> the statistics reset is skipped.
done.
===
> I think that would need a bump catalog version, add a XXX in the commit
> message to not forget about it?
>
> also "descr => 'statistics: force stats to be flushed after the next
> commit'," should be updated?
done. The catalog version is bumped and the descr now reads
"statistics: force stats to be flushed, immediately if within a
transaction".
===
> Should we also add test to verify that the function double counting bug
> is solved?
done. stats.sql now has a test where a plpgsql function calls
pg_stat_force_next_flush() from within itself, then verifies that
pg_stat_user_functions and pg_stat_get_xact_function_calls() both
report the correct call counts mid-transaction and after commit, with
no calls lost or double counted.
Also, I am keeping the test_custom_stats changes out of the main patch for
now, but have them attached as a nocfbot as they may help in the patch review.
The incorporate your ideas for the same kind with different objects, etc.
Lastly, Since the mid-transaction behavior is now user visible, v5 also brings
back the documentation updates for last_seq_scan/last_idx_scan from an
earlier version, and adds pg_stat_force_next_flush() to the statistics
functions table in monitoring.sgml. It was previously undocumented as a
test only helper, but that no longer seems appropriate given it now has
a public facing behavior worth describing.
Horighuchi-san raised a point here [1] about throttling mid-transaction flushes,
but I am not sure if we should. These are manually executed, and I
think the caller
should be the one responsible for throttling, not the pgstat infrastructure.
WDYT?
Attached is v5.
[1] https://www.postgresql.org/message-id/20260601.135858.1116584574478485492.horikyota.ntt%40gmail.com
--
Sami Imseih
Amazon Web Services (AWS)
| Attachment | Content-Type | Size |
|---|---|---|
| nocfbot.test_custom_stats.patch | application/octet-stream | 12.9 KB |
| v5-0001-pgstat-Allow-pg_stat_force_next_flush-to-work-in-.patch | application/octet-stream | 73.5 KB |
| From | Date | Subject | |
|---|---|---|---|
| Previous Message | Zsolt Parragi | 2026-08-06 22:59:49 | Re: MERGE/SPLIT PARTITIONS issues/questions |