On Sun, Jan 11, 2026 at 02:22 Michael Paquier <[email protected]> wrote:

> On Thu, Jan 08, 2026 at 09:22:26PM -0600, Sami Imseih wrote:
> > I don't see any issue with this approach for fwrite().
>
> Please feel free to discard my comment, then :)
>
> > Another comment. Wouldn't be better to use "COPY FROM" and "COPY TO" in
> the
> > names to make it more obvious they are related to the COPY command?
>
> Yeah, we had better do that.  That's slightly cleaner for the user if
> they mix both COPY types at the same time, not requiring a mental
> mapping that FROM is a read and TO is a write.



v2 attached with the rename per feedback: COPY_DATA_READ/WRITE →
COPY_FROM_READ/COPY_TO_WRITE.

Given how small this patch is, any chance it could still make PG19?

>
From 54a3b83f47e29181a061dea9d92f82c602bbdd2e Mon Sep 17 00:00:00 2001
From: Nik Samokhvalov <[email protected]>
Date: Thu, 8 Jan 2026 13:50:53 -0800
Subject: [PATCH v2] Add IO wait events for COPY file/program operations

Add two new IO wait events:
- COPY_FROM_READ: COPY FROM blocking on file or program read
- COPY_TO_WRITE: COPY TO blocking on file or program write

This enables diagnosing:
- Storage I/O bottlenecks during bulk loads (COPY FROM '/path/to/file')
- Slow exports to files (COPY TO '/path/to/file')
- Pipe buffer congestion in ETL pipelines (COPY FROM/TO PROGRAM)

COPY FROM/TO STDIN/STDOUT already have coverage via Client/ClientRead
and Client/ClientWrite at the protocol layer.

These events are distinct from the existing COPY_FILE_READ/WRITE events,
which instrument file-to-file copy operations in basebackup code.

v2: Renamed COPY_DATA_READ/WRITE to COPY_FROM_READ/COPY_TO_WRITE per
    feedback from Sami Imseih, Dilip Kumar, and Michael Paquier.

Example usage:

  -- Session 1:
  COPY large_table TO '/slow/nfs/mount/out.csv';

  -- Session 2:
  SELECT wait_event, wait_event_type
  FROM pg_stat_activity
  WHERE pid = <session1_pid>;
  -- Shows: COPY_TO_WRITE / IO
---
 src/backend/commands/copyfromparse.c            | 2 ++
 src/backend/commands/copyto.c                   | 2 ++
 src/backend/utils/activity/wait_event_names.txt | 2 ++
 3 files changed, 6 insertions(+)

diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 5868a7fa11f..af1df0c1f14 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -249,7 +249,9 @@ CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 	switch (cstate->copy_src)
 	{
 		case COPY_FILE:
+			pgstat_report_wait_start(WAIT_EVENT_COPY_FROM_READ);
 			bytesread = fread(databuf, 1, maxread, cstate->copy_file);
+			pgstat_report_wait_end();
 			if (ferror(cstate->copy_file))
 				ereport(ERROR,
 						(errcode_for_file_access(),
diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c
index 4ab4a3893d5..7d146e95b2d 100644
--- a/src/backend/commands/copyto.c
+++ b/src/backend/commands/copyto.c
@@ -454,6 +454,7 @@ CopySendEndOfRow(CopyToState cstate)
 	switch (cstate->copy_dest)
 	{
 		case COPY_FILE:
+			pgstat_report_wait_start(WAIT_EVENT_COPY_TO_WRITE);
 			if (fwrite(fe_msgbuf->data, fe_msgbuf->len, 1,
 					   cstate->copy_file) != 1 ||
 				ferror(cstate->copy_file))
@@ -486,6 +487,7 @@ CopySendEndOfRow(CopyToState cstate)
 							(errcode_for_file_access(),
 							 errmsg("could not write to COPY file: %m")));
 			}
+			pgstat_report_wait_end();
 			break;
 		case COPY_FRONTEND:
 			/* Dump the accumulated row as one CopyData message */
diff --git a/src/backend/utils/activity/wait_event_names.txt b/src/backend/utils/activity/wait_event_names.txt
index 3299de23bb3..a7e4d5182a9 100644
--- a/src/backend/utils/activity/wait_event_names.txt
+++ b/src/backend/utils/activity/wait_event_names.txt
@@ -210,6 +210,8 @@ CONTROL_FILE_SYNC	"Waiting for the <filename>pg_control</filename> file to reach
 CONTROL_FILE_SYNC_UPDATE	"Waiting for an update to the <filename>pg_control</filename> file to reach durable storage."
 CONTROL_FILE_WRITE	"Waiting for a write to the <filename>pg_control</filename> file."
 CONTROL_FILE_WRITE_UPDATE	"Waiting for a write to update the <filename>pg_control</filename> file."
+COPY_FROM_READ	"Waiting to read data from a file or program during COPY FROM."
+COPY_TO_WRITE	"Waiting to write data to a file or program during COPY TO."
 COPY_FILE_COPY	"Waiting for a file copy operation."
 COPY_FILE_READ	"Waiting for a read during a file copy operation."
 COPY_FILE_WRITE	"Waiting for a write during a file copy operation."
-- 
2.50.1 (Apple Git-155)

Reply via email to