Skip to content

Report actual wire bytes in COPY (cumulative) Transfer column#46

Merged
teknogeek0 merged 1 commit into
mainfrom
fix/copy-transfer-bytes
Jul 23, 2026
Merged

Report actual wire bytes in COPY (cumulative) Transfer column#46
teknogeek0 merged 1 commit into
mainfrom
fix/copy-transfer-bytes

Conversation

@teknogeek0

Copy link
Copy Markdown
Collaborator

Problem

pgcopydb list progress reported only table/index counts (no byte volume), and list progress --summary showed a blank Transfer column for the COPY (cumulative) row — it was populated from sourceTable->bytes (catalog pg_table_size()) rather than actual wire bytes.

Fix (ports upstream dimitri/pgcopydb dimitri#1002)

  1. table-data.c: pass summary.bytesTransmitted (actual wire bytes) to summary_increment_timing(TIMING_SECTION_COPY_DATA, …) instead of sourceTable->bytes.
  2. Surface per-table byte counts (already written to summary.bytes) in list progress.
  3. Add jitter to the periodic stats flush so N copy workers don't contend on the SQLite write lock at the same instant.

Observability/progress-accuracy fix; no change to what data gets copied.

Tests

Full PGVERSION=18 make tests green (all suites, exit 0). Clean cherry-pick.

…imitri#258) (dimitri#1002)

* fix: report actual wire bytes in COPY (cumulative) Transfer column (dimitri#258)

The top-level summary has always had a Transfer column in the COPY
(cumulative) row but it was populated with sourceTable->bytes — the
on-disk size from pg_table_size() on the source — rather than the
actual bytes sent over the wire during COPY.

The real wire byte count is already tracked buffer-by-buffer in
CopyTableSummary.bytesTransmitted (pgsql.c) and stored in the summary
table after each table copy (table-data.c:1467/1502).  The only gap
was that summary_increment_timing for TIMING_SECTION_COPY_DATA was
reading the catalog size instead of the transmitted count.

Changing that one argument makes the COPY (cumulative) row display the
true amount of data moved across the wire, e.g.:

  COPY (cumulative)   both   12h01m   47 GB   4

Source catalog size, target relation size, and wire bytes legitimately
differ due to bloat, TOAST, protocol framing, and storage version
differences, so the catalog value was never a useful proxy.

Closes dimitri#258

* feat: show bytes transferred in list progress (dimitri#258)

pgcopydb list progress now prints a Bytes row alongside Tables and
Indexes:

      Tables |           42 |            3 |           39
     Indexes |          150 |           12 |          138
       Bytes |       100 GB |              |        95 GB

The 'Done' column accumulates bytes from:
  - completed tables: their final bytesTransmitted from summary_finish_table
  - in-progress tables: the last periodic flush from summary_update_table_copy_stats

That hook already wrote bytesTransmitted to summary.bytes every 5 s;
what was missing was reading it back in copydb_update_progress.

Jitter is added to the periodic flush so N table workers do not all
wake at the same second.  Each worker's first write fires between 1 and
WRITE_INTERVAL_SECS seconds after startup, offset by getpid() %
WRITE_INTERVAL_SECS.  Subsequent writes remain every WRITE_INTERVAL_SECS
seconds, but staggered.  rand() is not used (it is banned); getpid() is
a deterministic, non-repeating source adequate for this purpose.

The JSON output gains a 'bytes' object with 'total', 'transferred',
'total-pretty', and 'transferred-pretty' fields.

(cherry picked from commit fe9efbc)
@teknogeek0
teknogeek0 merged commit fa93a4a into main Jul 23, 2026
185 of 186 checks passed
@teknogeek0
teknogeek0 deleted the fix/copy-transfer-bytes branch July 23, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants