diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 2d0ebd6f27d..d60b6710bfd 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -3050,7 +3050,9 @@ description | Waiting for a newly initialized WAL file to reach durable storage object is not wal, or if is enabled and object is wal, - otherwise zero) + otherwise zero). This may include time spent waiting for a + read started by another backend. In that case + reads may still be zero. diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 3908529872a..169829eb020 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1829,8 +1829,9 @@ WaitReadBuffers(ReadBuffersOperation *operation) needed_wait = true; /* - * The IO operation itself was already counted earlier, in - * AsyncReadBuffers(), this just accounts for the wait time. + * This just accounts for the wait time. The IO operation + * itself was already counted earlier in AsyncReadBuffers() -- + * either by us or by another backend if this is a foreign IO. */ pgstat_count_io_op_time(io_object, io_context, IOOP_READ, io_start, 0, 0); @@ -2018,8 +2019,7 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress) * A secondary benefit is that this would allow us to measure the time in * pgaio_io_acquire() without causing undue timer overhead in the common, * non-blocking, case. However, currently the pgstats infrastructure - * doesn't really allow that, as it a) asserts that an operation can't - * have time without operations b) doesn't have an API to report + * doesn't really allow that because it doesn't have an API to report * "accumulated" time. */ ioh = pgaio_io_acquire_nb(CurrentResourceOwner, &operation->io_return); diff --git a/src/backend/utils/activity/pgstat_io.c b/src/backend/utils/activity/pgstat_io.c index 4f7a39aaa0e..8ec1aad5078 100644 --- a/src/backend/utils/activity/pgstat_io.c +++ b/src/backend/utils/activity/pgstat_io.c @@ -25,9 +25,10 @@ static bool have_iostats = false; /* * Check that stats have not been counted for any combination of IOObject, - * IOContext, and IOOp which are not tracked for the passed-in BackendType. If - * stats are tracked for this combination and IO times are non-zero, counts - * should be non-zero. + * IOContext, and IOOp which are not tracked for the passed-in BackendType. + * Non-zero time with a zero operation count is allowed as there are cases + * where this may be appropriate -- like when a backend is waiting on IO + * initiated by another backend. * * The passed-in PgStat_BktypeIO must contain stats from the BackendType * specified by the second parameter. Caller is responsible for locking the @@ -43,19 +44,10 @@ pgstat_bktype_io_stats_valid(PgStat_BktypeIO *backend_io, { for (int io_op = 0; io_op < IOOP_NUM_TYPES; io_op++) { - /* we do track it */ - if (pgstat_tracks_io_op(bktype, io_object, io_context, io_op)) - { - /* ensure that if IO times are non-zero, counts are > 0 */ - if (backend_io->times[io_object][io_context][io_op] != 0 && - backend_io->counts[io_object][io_context][io_op] <= 0) - return false; - - continue; - } - /* we don't track it, and it is not 0 */ - if (backend_io->counts[io_object][io_context][io_op] != 0) + if (!pgstat_tracks_io_op(bktype, io_object, io_context, io_op) && + (backend_io->counts[io_object][io_context][io_op] != 0 || + backend_io->times[io_object][io_context][io_op] != 0)) return false; } }