v31-0002-Aggregate-IO-operation-stats-per-BackendType.patch
text/x-patch
Filename: v31-0002-Aggregate-IO-operation-stats-per-BackendType.patch
Type: text/x-patch
Part: 0
Patch
Format: format-patch
Series: patch v31-0002
Subject: Aggregate IO operation stats per BackendType
| File | + | − |
|---|---|---|
| doc/src/sgml/monitoring.sgml | 2 | 0 |
| src/backend/utils/activity/pgstat_bgwriter.c | 6 | 1 |
| src/backend/utils/activity/pgstat.c | 35 | 0 |
| src/backend/utils/activity/pgstat_checkpointer.c | 6 | 1 |
| src/backend/utils/activity/pgstat_io_ops.c | 157 | 0 |
| src/backend/utils/activity/pgstat_relation.c | 13 | 2 |
| src/backend/utils/activity/pgstat_shmem.c | 4 | 0 |
| src/backend/utils/activity/pgstat_wal.c | 3 | 1 |
| src/backend/utils/adt/pgstatfuncs.c | 3 | 1 |
| src/include/miscadmin.h | 2 | 0 |
| src/include/pgstat.h | 82 | 1 |
| src/include/utils/pgstat_internal.h | 37 | 0 |
| src/tools/pgindent/typedefs.list | 3 | 0 |
From 0ee5cda16066edbbe0b992cae7272c9e2671d1a7 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Thu, 6 Oct 2022 12:23:38 -0400
Subject: [PATCH v31 2/3] Aggregate IO operation stats per BackendType
Stats on IOOps for all IOContexts for a backend are tracked locally. Add
functionality for backends to flush these stats to shared memory and
accumulate them with those from all other backends, exited and live.
Also add reset and snapshot functions used by cumulative stats system
for management of these statistics.
The aggregated stats in shared memory could be extended in the future
with per-backend stats -- useful for per connection IO statistics and
monitoring.
Some BackendTypes will not flush their pending statistics at regular
intervals and explicitly call pgstat_flush_io_ops() during the course of
normal operations to flush their backend-local IO operation statistics
to shared memory in a timely manner.
Because not all BackendType, IOOp, IOContext combinations are valid, the
validity of the stats is checked before flushing pending stats and
before reading in the existing stats file to shared memory.
Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Justin Pryzby <pryzby@telsasoft.com>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Reviewed-by: Maciek Sakrejda <m.sakrejda@gmail.com>
Reviewed-by: Lukas Fittl <lukas@fittl.com>
Discussion: https://www.postgresql.org/message-id/flat/20200124195226.lth52iydq2n2uilq%40alap3.anarazel.de
---
doc/src/sgml/monitoring.sgml | 2 +
src/backend/utils/activity/pgstat.c | 35 ++++
src/backend/utils/activity/pgstat_bgwriter.c | 7 +-
.../utils/activity/pgstat_checkpointer.c | 7 +-
src/backend/utils/activity/pgstat_io_ops.c | 157 ++++++++++++++++++
src/backend/utils/activity/pgstat_relation.c | 15 +-
src/backend/utils/activity/pgstat_shmem.c | 4 +
src/backend/utils/activity/pgstat_wal.c | 4 +-
src/backend/utils/adt/pgstatfuncs.c | 4 +-
src/include/miscadmin.h | 2 +
src/include/pgstat.h | 83 ++++++++-
src/include/utils/pgstat_internal.h | 37 +++++
src/tools/pgindent/typedefs.list | 3 +
13 files changed, 353 insertions(+), 7 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 342b20ebeb..14dfd650f8 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -5360,6 +5360,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
the <structname>pg_stat_bgwriter</structname>
view, <literal>archiver</literal> to reset all the counters shown in
the <structname>pg_stat_archiver</structname> view,
+ <literal>io</literal> to reset all the counters shown in the
+ <structname>pg_stat_io</structname> view,
<literal>wal</literal> to reset all the counters shown in the
<structname>pg_stat_wal</structname> view or
<literal>recovery_prefetch</literal> to reset all the counters shown
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index 609f0b1ad8..e66dde0ea5 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -359,6 +359,15 @@ static const PgStat_KindInfo pgstat_kind_infos[PGSTAT_NUM_KINDS] = {
.snapshot_cb = pgstat_checkpointer_snapshot_cb,
},
+ [PGSTAT_KIND_IOOPS] = {
+ .name = "io_ops",
+
+ .fixed_amount = true,
+
+ .reset_all_cb = pgstat_io_ops_reset_all_cb,
+ .snapshot_cb = pgstat_io_ops_snapshot_cb,
+ },
+
[PGSTAT_KIND_SLRU] = {
.name = "slru",
@@ -582,6 +591,7 @@ pgstat_report_stat(bool force)
/* Don't expend a clock check if nothing to do */
if (dlist_is_empty(&pgStatPending) &&
+ !have_ioopstats &&
!have_slrustats &&
!pgstat_have_pending_wal())
{
@@ -628,6 +638,9 @@ pgstat_report_stat(bool force)
/* flush database / relation / function / ... stats */
partial_flush |= pgstat_flush_pending_entries(nowait);
+ /* flush IO Operations stats */
+ partial_flush |= pgstat_flush_io_ops(nowait);
+
/* flush wal stats */
partial_flush |= pgstat_flush_wal(nowait);
@@ -1321,6 +1334,14 @@ pgstat_write_statsfile(void)
pgstat_build_snapshot_fixed(PGSTAT_KIND_CHECKPOINTER);
write_chunk_s(fpout, &pgStatLocal.snapshot.checkpointer);
+ /*
+ * Write IO Operations stats struct
+ */
+ pgstat_build_snapshot_fixed(PGSTAT_KIND_IOOPS);
+ write_chunk_s(fpout, &pgStatLocal.snapshot.io_ops.stat_reset_timestamp);
+ for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+ write_chunk_s(fpout, &pgStatLocal.snapshot.io_ops.stats[i]);
+
/*
* Write SLRU stats struct
*/
@@ -1495,6 +1516,20 @@ pgstat_read_statsfile(void)
if (!read_chunk_s(fpin, &shmem->checkpointer.stats))
goto error;
+ /*
+ * Read IO Operations stats struct
+ */
+ if (!read_chunk_s(fpin, &shmem->io_ops.stat_reset_timestamp))
+ goto error;
+
+ for (int bktype = 0; bktype < BACKEND_NUM_TYPES; bktype++)
+ {
+ pgstat_backend_io_stats_assert_well_formed(shmem->io_ops.stats[bktype].data,
+ bktype);
+ if (!read_chunk_s(fpin, &shmem->io_ops.stats[bktype].data))
+ goto error;
+ }
+
/*
* Read SLRU stats struct
*/
diff --git a/src/backend/utils/activity/pgstat_bgwriter.c b/src/backend/utils/activity/pgstat_bgwriter.c
index fbb1edc527..3d7f90a1b7 100644
--- a/src/backend/utils/activity/pgstat_bgwriter.c
+++ b/src/backend/utils/activity/pgstat_bgwriter.c
@@ -24,7 +24,7 @@ PgStat_BgWriterStats PendingBgWriterStats = {0};
/*
- * Report bgwriter statistics
+ * Report bgwriter and IO Operation statistics
*/
void
pgstat_report_bgwriter(void)
@@ -56,6 +56,11 @@ pgstat_report_bgwriter(void)
* Clear out the statistics buffer, so it can be re-used.
*/
MemSet(&PendingBgWriterStats, 0, sizeof(PendingBgWriterStats));
+
+ /*
+ * Report IO Operations statistics
+ */
+ pgstat_flush_io_ops(false);
}
/*
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..cfcf127210 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -24,7 +24,7 @@ PgStat_CheckpointerStats PendingCheckpointerStats = {0};
/*
- * Report checkpointer statistics
+ * Report checkpointer and IO Operation statistics
*/
void
pgstat_report_checkpointer(void)
@@ -62,6 +62,11 @@ pgstat_report_checkpointer(void)
* Clear out the statistics buffer, so it can be re-used.
*/
MemSet(&PendingCheckpointerStats, 0, sizeof(PendingCheckpointerStats));
+
+ /*
+ * Report IO Operation statistics
+ */
+ pgstat_flush_io_ops(false);
}
/*
diff --git a/src/backend/utils/activity/pgstat_io_ops.c b/src/backend/utils/activity/pgstat_io_ops.c
index cea46322a7..86d403fe55 100644
--- a/src/backend/utils/activity/pgstat_io_ops.c
+++ b/src/backend/utils/activity/pgstat_io_ops.c
@@ -20,6 +20,42 @@
#include "utils/pgstat_internal.h"
static PgStat_IOContextOps pending_IOOpStats;
+bool have_ioopstats = false;
+
+
+/*
+ * Helper function to accumulate source PgStat_IOOpCounters into target
+ * PgStat_IOOpCounters. If either of the passed-in PgStat_IOOpCounters are
+ * members of PgStatShared_IOContextOps, the caller is responsible for ensuring
+ * that the appropriate lock is held.
+ */
+static void
+pgstat_accum_io_op(PgStat_IOOpCounters *target, PgStat_IOOpCounters *source, IOOp io_op)
+{
+ switch (io_op)
+ {
+ case IOOP_ACQUIRE:
+ target->acquires += source->acquires;
+ return;
+ case IOOP_EXTEND:
+ target->extends += source->extends;
+ return;
+ case IOOP_FSYNC:
+ target->fsyncs += source->fsyncs;
+ return;
+ case IOOP_HIT:
+ target->hits += source->hits;
+ return;
+ case IOOP_READ:
+ target->reads += source->reads;
+ return;
+ case IOOP_WRITE:
+ target->writes += source->writes;
+ return;
+ }
+
+ elog(ERROR, "unrecognized IOOp value: %d", io_op);
+}
void
pgstat_count_io_op(IOOp io_op, IOContext io_context)
@@ -54,6 +90,77 @@ pgstat_count_io_op(IOOp io_op, IOContext io_context)
break;
}
+ have_ioopstats = true;
+}
+
+PgStat_BackendIOContextOps *
+pgstat_fetch_backend_io_context_ops(void)
+{
+ pgstat_snapshot_fixed(PGSTAT_KIND_IOOPS);
+
+ return &pgStatLocal.snapshot.io_ops;
+}
+
+/*
+ * Flush out locally pending IO Operation statistics entries
+ *
+ * If no stats have been recorded, this function returns false.
+ *
+ * If nowait is true, this function returns true if the lock could not be
+ * acquired. Otherwise, return false.
+ */
+bool
+pgstat_flush_io_ops(bool nowait)
+{
+ PgStatShared_IOContextOps *type_shstats;
+ bool expect_backend_stats = true;
+
+ if (!have_ioopstats)
+ return false;
+
+ type_shstats =
+ &pgStatLocal.shmem->io_ops.stats[MyBackendType];
+
+ if (!nowait)
+ LWLockAcquire(&type_shstats->lock, LW_EXCLUSIVE);
+ else if (!LWLockConditionalAcquire(&type_shstats->lock, LW_EXCLUSIVE))
+ return true;
+
+ expect_backend_stats = pgstat_io_op_stats_collected(MyBackendType);
+
+ for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
+ {
+ PgStat_IOOpCounters *sharedent = &type_shstats->data[io_context];
+ PgStat_IOOpCounters *pendingent = &pending_IOOpStats.data[io_context];
+
+ if (!expect_backend_stats ||
+ !pgstat_bktype_io_context_valid(MyBackendType, io_context))
+ {
+ pgstat_io_context_ops_assert_zero(sharedent);
+ pgstat_io_context_ops_assert_zero(pendingent);
+ continue;
+ }
+
+ for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
+ {
+ if (!(pgstat_io_op_valid(MyBackendType, io_context, io_op)))
+ {
+ pgstat_io_op_assert_zero(sharedent, io_op);
+ pgstat_io_op_assert_zero(pendingent, io_op);
+ continue;
+ }
+
+ pgstat_accum_io_op(sharedent, pendingent, io_op);
+ }
+ }
+
+ LWLockRelease(&type_shstats->lock);
+
+ memset(&pending_IOOpStats, 0, sizeof(pending_IOOpStats));
+
+ have_ioopstats = false;
+
+ return false;
}
const char *
@@ -98,6 +205,56 @@ pgstat_io_op_desc(IOOp io_op)
elog(ERROR, "unrecognized IOOp value: %d", io_op);
}
+void
+pgstat_io_ops_reset_all_cb(TimestampTz ts)
+{
+ PgStatShared_BackendIOContextOps *backends_stats_shmem = &pgStatLocal.shmem->io_ops;
+
+ for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+ {
+ PgStatShared_IOContextOps *stats_shmem = &backends_stats_shmem->stats[i];
+
+ LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
+
+ /*
+ * Use the lock in the first BackendType's PgStat_IOContextOps to
+ * protect the reset timestamp as well.
+ */
+ if (i == 0)
+ backends_stats_shmem->stat_reset_timestamp = ts;
+
+ memset(stats_shmem->data, 0, sizeof(stats_shmem->data));
+ LWLockRelease(&stats_shmem->lock);
+ }
+}
+
+void
+pgstat_io_ops_snapshot_cb(void)
+{
+ PgStatShared_BackendIOContextOps *backends_stats_shmem = &pgStatLocal.shmem->io_ops;
+ PgStat_BackendIOContextOps *backends_stats_snap = &pgStatLocal.snapshot.io_ops;
+
+ for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+ {
+ PgStatShared_IOContextOps *stats_shmem = &backends_stats_shmem->stats[i];
+ PgStat_IOContextOps *stats_snap = &backends_stats_snap->stats[i];
+
+ LWLockAcquire(&stats_shmem->lock, LW_SHARED);
+
+ /*
+ * Use the lock in the first BackendType's PgStat_IOContextOps to
+ * protect the reset timestamp as well.
+ */
+ if (i == 0)
+ backends_stats_snap->stat_reset_timestamp =
+ backends_stats_shmem->stat_reset_timestamp;
+
+ memcpy(stats_snap->data, stats_shmem->data, sizeof(stats_shmem->data));
+ LWLockRelease(&stats_shmem->lock);
+ }
+
+}
+
/*
* IO Operation statistics are not collected for all BackendTypes.
*
diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c
index a846d9ffb6..7a2fd1ccf9 100644
--- a/src/backend/utils/activity/pgstat_relation.c
+++ b/src/backend/utils/activity/pgstat_relation.c
@@ -205,7 +205,7 @@ pgstat_drop_relation(Relation rel)
}
/*
- * Report that the table was just vacuumed.
+ * Report that the table was just vacuumed and flush IO Operation statistics.
*/
void
pgstat_report_vacuum(Oid tableoid, bool shared,
@@ -257,10 +257,18 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
}
pgstat_unlock_entry(entry_ref);
+
+ /*
+ * Flush IO Operations statistics now. pgstat_report_stat() will flush IO
+ * Operation stats, however this will not be called after an entire
+ * autovacuum cycle is done -- which will likely vacuum many relations --
+ * or until the VACUUM command has processed all tables and committed.
+ */
+ pgstat_flush_io_ops(false);
}
/*
- * Report that the table was just analyzed.
+ * Report that the table was just analyzed and flush IO Operation statistics.
*
* Caller must provide new live- and dead-tuples estimates, as well as a
* flag indicating whether to reset the changes_since_analyze counter.
@@ -340,6 +348,9 @@ pgstat_report_analyze(Relation rel,
}
pgstat_unlock_entry(entry_ref);
+
+ /* see pgstat_report_vacuum() */
+ pgstat_flush_io_ops(false);
}
/*
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 9a4f037959..275a7be166 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -202,6 +202,10 @@ StatsShmemInit(void)
LWLockInitialize(&ctl->checkpointer.lock, LWTRANCHE_PGSTATS_DATA);
LWLockInitialize(&ctl->slru.lock, LWTRANCHE_PGSTATS_DATA);
LWLockInitialize(&ctl->wal.lock, LWTRANCHE_PGSTATS_DATA);
+
+ for (int i = 0; i < BACKEND_NUM_TYPES; i++)
+ LWLockInitialize(&ctl->io_ops.stats[i].lock,
+ LWTRANCHE_PGSTATS_DATA);
}
else
{
diff --git a/src/backend/utils/activity/pgstat_wal.c b/src/backend/utils/activity/pgstat_wal.c
index 5a878bd115..9cac407b42 100644
--- a/src/backend/utils/activity/pgstat_wal.c
+++ b/src/backend/utils/activity/pgstat_wal.c
@@ -34,7 +34,7 @@ static WalUsage prevWalUsage;
/*
* Calculate how much WAL usage counters have increased and update
- * shared statistics.
+ * shared WAL and IO Operation statistics.
*
* Must be called by processes that generate WAL, that do not call
* pgstat_report_stat(), like walwriter.
@@ -43,6 +43,8 @@ void
pgstat_report_wal(bool force)
{
pgstat_flush_wal(force);
+
+ pgstat_flush_io_ops(force);
}
/*
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index eadd8464ff..edd73e5c25 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -2071,6 +2071,8 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
}
+ else if (strcmp(target, "io") == 0)
+ pgstat_reset_of_kind(PGSTAT_KIND_IOOPS);
else if (strcmp(target, "recovery_prefetch") == 0)
XLogPrefetchResetStats();
else if (strcmp(target, "wal") == 0)
@@ -2079,7 +2081,7 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized reset target: \"%s\"", target),
- errhint("Target must be \"archiver\", \"bgwriter\", \"recovery_prefetch\", or \"wal\".")));
+ errhint("Target must be \"archiver\", \"io\", \"bgwriter\", \"recovery_prefetch\", or \"wal\".")));
PG_RETURN_VOID();
}
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index e7ebea4ff4..bf97162e83 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -331,6 +331,8 @@ typedef enum BackendType
B_WAL_WRITER,
} BackendType;
+#define BACKEND_NUM_TYPES B_WAL_WRITER + 1
+
extern PGDLLIMPORT BackendType MyBackendType;
extern const char *GetBackendTypeDesc(BackendType backendType);
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 472e0def97..0d3d5e28a1 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -49,6 +49,7 @@ typedef enum PgStat_Kind
PGSTAT_KIND_ARCHIVER,
PGSTAT_KIND_BGWRITER,
PGSTAT_KIND_CHECKPOINTER,
+ PGSTAT_KIND_IOOPS,
PGSTAT_KIND_SLRU,
PGSTAT_KIND_WAL,
} PgStat_Kind;
@@ -243,7 +244,7 @@ typedef struct PgStat_TableXactStatus
* ------------------------------------------------------------
*/
-#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA7
+#define PGSTAT_FILE_FORMAT_ID 0x01A5BCA8
typedef struct PgStat_ArchiverStats
{
@@ -319,6 +320,12 @@ typedef struct PgStat_IOContextOps
PgStat_IOOpCounters data[IOCONTEXT_NUM_TYPES];
} PgStat_IOContextOps;
+typedef struct PgStat_BackendIOContextOps
+{
+ TimestampTz stat_reset_timestamp;
+ PgStat_IOContextOps stats[BACKEND_NUM_TYPES];
+} PgStat_BackendIOContextOps;
+
typedef struct PgStat_StatDBEntry
{
PgStat_Counter n_xact_commit;
@@ -501,6 +508,7 @@ extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void);
*/
extern void pgstat_count_io_op(IOOp io_op, IOContext io_context);
+extern PgStat_BackendIOContextOps *pgstat_fetch_backend_io_context_ops(void);
extern const char *pgstat_io_context_desc(IOContext io_context);
extern const char *pgstat_io_op_desc(IOOp io_op);
@@ -512,6 +520,79 @@ extern bool pgstat_expect_io_op(BackendType bktype, IOContext io_context, IOOp i
/* IO stats translation function in freelist.c */
extern IOContext IOContextForStrategy(BufferAccessStrategy bas);
+/*
+ * Functions to assert that invalid IO Operation counters are zero.
+ */
+static inline void
+pgstat_io_context_ops_assert_zero(PgStat_IOOpCounters *counters)
+{
+ Assert(counters->acquires == 0 && counters->extends == 0 &&
+ counters->fsyncs == 0 && counters->reads == 0 &&
+ counters->writes == 0);
+}
+
+static inline void
+pgstat_io_op_assert_zero(PgStat_IOOpCounters *counters, IOOp io_op)
+{
+ switch (io_op)
+ {
+ case IOOP_ACQUIRE:
+ Assert(counters->acquires == 0);
+ return;
+ case IOOP_EXTEND:
+ Assert(counters->extends == 0);
+ return;
+ case IOOP_FSYNC:
+ Assert(counters->fsyncs == 0);
+ return;
+ case IOOP_HIT:
+ Assert(counters->hits == 0);
+ return;
+ case IOOP_READ:
+ Assert(counters->reads == 0);
+ return;
+ case IOOP_WRITE:
+ Assert(counters->writes == 0);
+ return;
+ }
+
+ /* Should not reach here */
+ Assert(false);
+}
+
+/*
+ * Assert that stats have not been counted for any combination of IOContext and
+ * IOOp which are not valid for the passed-in BackendType. The passed-in array
+ * of PgStat_IOOpCounters must contain stats from the BackendType specified by
+ * the second parameter. Caller is responsible for any locking if the passed-in
+ * array of PgStat_IOOpCounters is a member of PgStatShared_IOContextOps.
+ */
+static inline void
+pgstat_backend_io_stats_assert_well_formed(PgStat_IOOpCounters
+ backend_io_context_ops[IOCONTEXT_NUM_TYPES], BackendType bktype)
+{
+ bool expect_backend_stats = true;
+
+ if (!pgstat_io_op_stats_collected(bktype))
+ expect_backend_stats = false;
+
+ for (int io_context = 0; io_context < IOCONTEXT_NUM_TYPES; io_context++)
+ {
+ if (!expect_backend_stats ||
+ !pgstat_bktype_io_context_valid(bktype, io_context))
+ {
+ pgstat_io_context_ops_assert_zero(&backend_io_context_ops[io_context]);
+ continue;
+ }
+
+ for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++)
+ {
+ if (!pgstat_io_op_valid(bktype, io_context, io_op))
+ pgstat_io_op_assert_zero(&backend_io_context_ops[io_context],
+ io_op);
+ }
+ }
+}
/*
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 40a3602855..95f19cae99 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -329,6 +329,26 @@ typedef struct PgStatShared_Checkpointer
PgStat_CheckpointerStats reset_offset;
} PgStatShared_Checkpointer;
+typedef struct PgStatShared_IOContextOps
+{
+ /*
+ * lock protects ->data
+ * If this PgStatShared_IOContextOps is
+ * PgStatShared_BackendIOContextOps->stats[0], lock also protects
+ * PgStatShared_BackendIOContextOps->stat_reset_timestamp.
+ */
+ LWLock lock;
+ PgStat_IOOpCounters data[IOCONTEXT_NUM_TYPES];
+} PgStatShared_IOContextOps;
+
+typedef struct PgStatShared_BackendIOContextOps
+{
+ /* ->stats_reset_timestamp is protected by ->stats[0].lock */
+ TimestampTz stat_reset_timestamp;
+ PgStatShared_IOContextOps stats[BACKEND_NUM_TYPES];
+} PgStatShared_BackendIOContextOps;
+
+
typedef struct PgStatShared_SLRU
{
/* lock protects ->stats */
@@ -419,6 +439,7 @@ typedef struct PgStat_ShmemControl
PgStatShared_Archiver archiver;
PgStatShared_BgWriter bgwriter;
PgStatShared_Checkpointer checkpointer;
+ PgStatShared_BackendIOContextOps io_ops;
PgStatShared_SLRU slru;
PgStatShared_Wal wal;
} PgStat_ShmemControl;
@@ -442,6 +463,8 @@ typedef struct PgStat_Snapshot
PgStat_CheckpointerStats checkpointer;
+ PgStat_BackendIOContextOps io_ops;
+
PgStat_SLRUStats slru[SLRU_NUM_ELEMENTS];
PgStat_WalStats wal;
@@ -549,6 +572,15 @@ extern void pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, Time
extern bool pgstat_function_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
+/*
+ * Functions in pgstat_io_ops.c
+ */
+
+extern void pgstat_io_ops_reset_all_cb(TimestampTz ts);
+extern void pgstat_io_ops_snapshot_cb(void);
+extern bool pgstat_flush_io_ops(bool nowait);
+
+
/*
* Functions in pgstat_relation.c
*/
@@ -641,6 +673,11 @@ extern void pgstat_create_transactional(PgStat_Kind kind, Oid dboid, Oid objoid)
extern PGDLLIMPORT PgStat_LocalState pgStatLocal;
+/*
+ * Variables in pgstat_io_ops.c
+ */
+
+extern PGDLLIMPORT bool have_ioopstats;
/*
* Variables in pgstat_slru.c
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 67218ec6f2..33c9362257 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2005,12 +2005,14 @@ PgFdwRelationInfo
PgFdwScanState
PgIfAddrCallback
PgStatShared_Archiver
+PgStatShared_BackendIOContextOps
PgStatShared_BgWriter
PgStatShared_Checkpointer
PgStatShared_Common
PgStatShared_Database
PgStatShared_Function
PgStatShared_HashEntry
+PgStatShared_IOContextOps
PgStatShared_Relation
PgStatShared_ReplSlot
PgStatShared_SLRU
@@ -2018,6 +2020,7 @@ PgStatShared_Subscription
PgStatShared_Wal
PgStat_ArchiverStats
PgStat_BackendFunctionEntry
+PgStat_BackendIOContextOps
PgStat_BackendSubEntry
PgStat_BgWriterStats
PgStat_CheckpointerStats
--
2.34.1