v3-0002-count-client-xacts-only.patch
application/octet-stream
Filename: v3-0002-count-client-xacts-only.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v3-0002
Subject: Count xact_commit/xact_rollback only for client backends
| File | + | − |
|---|---|---|
| doc/src/sgml/monitoring.sgml | 8 | 4 |
| src/backend/access/transam/twophase.c | 1 | 1 |
| src/backend/access/transam/xact.c | 2 | 2 |
| src/backend/utils/activity/pgstat_database.c | 11 | 3 |
| src/backend/utils/activity/pgstat_xact.c | 2 | 2 |
| src/include/pgstat.h | 1 | 1 |
| src/include/utils/pgstat_internal.h | 1 | 1 |
From df6f10bd9ddf2b5659bf19d928763530a9af685c Mon Sep 17 00:00:00 2001
From: Nikolay Samokhvalov <nik@postgres.ai>
Date: Wed, 8 Jul 2026 08:04:58 -0700
Subject: [PATCH v3 2/2] Count xact_commit/xact_rollback only for client
backends
pg_stat_database.xact_commit and xact_rollback have historically counted
every top-level transaction end in a database, including the internal
transactions run by other server processes such as autovacuum workers and
walsenders. Those transactions are not user-visible transaction outcomes,
and counting them makes the ratio of commits to rollbacks harder to
interpret for monitoring.
Adopt the narrower definition discussed on the list: count a transaction in
xact_commit/xact_rollback only when it is executed by a regular client
backend (AmRegularBackendProcess()). The "parallel" argument, previously
used to keep parallel workers out of these counters, is now redundant --
parallel workers are background workers and are excluded by the backend-type
test -- so it is removed from both AtEOXact_PgStat() and
AtEOXact_PgStat_Database().
This is a monitoring-visible behavior change beyond the server processes
themselves: logical replication apply workers are background workers, so the
transactions they replay on a subscriber are no longer counted in the
subscriber's xact_commit. That is intended, and is called out here so the
change in subscriber statistics is not mistaken for a regression.
Because it changes long-standing counter semantics, this is master-only.
The back-patchable fix for the specific logical-decoding case that prompted
this is handled separately; this commit implements the general definition on
top of it.
Discussion: https://postgr.es/m/CAM527d_EbU5Li4a5FdKQjYsdF-4Lqr_i3jXmZOm7Wbb%3DQ2KzTw%40mail.gmail.com
---
doc/src/sgml/monitoring.sgml | 12 ++++++++----
src/backend/access/transam/twophase.c | 2 +-
src/backend/access/transam/xact.c | 4 ++--
src/backend/utils/activity/pgstat_database.c | 14 +++++++++++---
src/backend/utils/activity/pgstat_xact.c | 4 ++--
src/include/pgstat.h | 2 +-
src/include/utils/pgstat_internal.h | 2 +-
7 files changed, 26 insertions(+), 14 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 12b9ee20d4a..7e0a7550fa6 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3895,8 +3895,10 @@ description | Waiting for a newly initialized WAL file to reach durable storage
<structfield>xact_commit</structfield> <type>bigint</type>
</para>
<para>
- Number of transactions in this database that have been
- committed
+ Number of transactions in this database that have been committed by
+ regular client backends. Transactions performed by other server
+ processes, such as autovacuum workers, walsenders, and logical
+ replication apply workers, are not counted.
</para></entry>
</row>
@@ -3905,8 +3907,10 @@ description | Waiting for a newly initialized WAL file to reach durable storage
<structfield>xact_rollback</structfield> <type>bigint</type>
</para>
<para>
- Number of transactions in this database that have been
- rolled back
+ Number of transactions in this database that have been rolled back by
+ regular client backends. Transactions performed by other server
+ processes, such as autovacuum workers, walsenders, and logical
+ replication apply workers, are not counted.
</para></entry>
</row>
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 1035e8b3fc7..0408f8794b4 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1676,7 +1676,7 @@ FinishPreparedTransaction(const char *gid, bool isCommit)
LWLockRelease(TwoPhaseStateLock);
/* Count the prepared xact as committed or aborted */
- AtEOXact_PgStat(isCommit, false);
+ AtEOXact_PgStat(isCommit);
/*
* And now we can clean up any files we may have left.
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d74b231caf3..4e627e3306b 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -2515,7 +2515,7 @@ CommitTransaction(void)
AtEOXact_ComboCid();
AtEOXact_HashTables(true);
AtEOXact_RI(true);
- AtEOXact_PgStat(true, is_parallel_worker);
+ AtEOXact_PgStat(true);
AtEOXact_Snapshot(true, false);
AtEOXact_ApplyLauncher(true);
AtEOXact_LogicalRepWorkers(true);
@@ -3042,7 +3042,7 @@ AbortTransaction(void)
AtEOXact_ComboCid();
AtEOXact_HashTables(false);
AtEOXact_RI(false);
- AtEOXact_PgStat(false, is_parallel_worker);
+ AtEOXact_PgStat(false);
AtEOXact_ApplyLauncher(false);
AtEOXact_LogicalRepWorkers(false);
AtEOXact_LogicalCtl();
diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c
index 7f3bc016593..efe546931e3 100644
--- a/src/backend/utils/activity/pgstat_database.c
+++ b/src/backend/utils/activity/pgstat_database.c
@@ -17,6 +17,7 @@
#include "postgres.h"
+#include "miscadmin.h"
#include "storage/standby.h"
#include "utils/pgstat_internal.h"
#include "utils/timestamp.h"
@@ -292,10 +293,17 @@ pgstat_fetch_stat_dbentry(Oid dboid)
}
void
-AtEOXact_PgStat_Database(bool isCommit, bool parallel)
+AtEOXact_PgStat_Database(bool isCommit)
{
- /* Don't count parallel worker transaction stats */
- if (!parallel)
+ /*
+ * Only count transactions of regular client backends in
+ * xact_commit/xact_rollback. Transactions performed by other server
+ * processes -- autovacuum workers, walsenders, and, less obviously, logical
+ * replication apply workers -- are not user-visible transaction outcomes and
+ * would otherwise inflate these counters. (This subsumes the previous
+ * !parallel check, since parallel workers are bgworkers.)
+ */
+ if (AmRegularBackendProcess())
{
/*
* Count transaction commit or abort. (We use counters, not just
diff --git a/src/backend/utils/activity/pgstat_xact.c b/src/backend/utils/activity/pgstat_xact.c
index d1be3733e4d..6c3944b5f22 100644
--- a/src/backend/utils/activity/pgstat_xact.c
+++ b/src/backend/utils/activity/pgstat_xact.c
@@ -38,7 +38,7 @@ static bool pgStatSkipXactCounters = false;
* Called from access/transam/xact.c at top-level transaction commit/abort.
*/
void
-AtEOXact_PgStat(bool isCommit, bool parallel)
+AtEOXact_PgStat(bool isCommit)
{
PgStat_SubXactStatus *xact_state;
bool skip_xact_counters = pgStatSkipXactCounters;
@@ -49,7 +49,7 @@ AtEOXact_PgStat(bool isCommit, bool parallel)
*/
pgStatSkipXactCounters = false;
if (!skip_xact_counters)
- AtEOXact_PgStat_Database(isCommit, parallel);
+ AtEOXact_PgStat_Database(isCommit);
/* handle transactional stats information */
xact_state = pgStatXactStack;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index ff0a2e16467..4fa84061057 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -827,7 +827,7 @@ extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid);
* Functions in pgstat_xact.c
*/
-extern void AtEOXact_PgStat(bool isCommit, bool parallel);
+extern void AtEOXact_PgStat(bool isCommit);
extern void pgstat_suppress_xact_counters(void);
extern void pgstat_clear_xact_counter_suppression(void);
extern void AtEOSubXact_PgStat(bool isCommit, int nestDepth);
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index b3dc3ff7d8b..ad9bb649e34 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -737,7 +737,7 @@ extern void pgstat_checkpointer_snapshot_cb(void);
extern void pgstat_report_disconnect(Oid dboid);
extern void pgstat_update_dbstats(TimestampTz ts);
-extern void AtEOXact_PgStat_Database(bool isCommit, bool parallel);
+extern void AtEOXact_PgStat_Database(bool isCommit);
extern PgStat_StatDBEntry *pgstat_prep_database_pending(Oid dboid);
extern void pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts);
--
2.50.1 (Apple Git-155)