Skip to content

[snapshot] Record the measured payload size instead of the nominal PVC size - #466

Open
kkozoriz wants to merge 7 commits into
mainfrom
fix/snapshot-payload-size
Open

[snapshot] Record the measured payload size instead of the nominal PVC size#466
kkozoriz wants to merge 7 commits into
mainfrom
fix/snapshot-payload-size

Conversation

@kkozoriz

@kkozoriz kkozoriz commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Problem

Every size a snapshot reported for a volume's payload came from the nominal PVC quantity (VolumeSnapshotContent.status.restoreSize), not from the payload itself. A thin-provisioning backend (LINSTOR/DRBD) rounds the underlying device up from that quantity and a filesystem volume is usually far emptier than its PVC, so the two genuinely differ. Consequences: download progress totals were wrong, and d8 snapshot upload rejected valid archives as size-mismatched when the real decoded payload exceeded the nominal size.

Fix

  • Measure the real payload footprint once, at finalization, and record it in snapshot.yaml as VolumeInfo.rawSizeBytes / storedSizeBytes. Size keeps its old meaning: the nominal quantity used to provision the scratch volume on re-import.
  • Measuring is cheap: zstd frame headers only, no full decode; a header-only PAX pass for filesystem data.tar.
  • Upload trusts the recorded size when present and falls back to measuring for older archives, plus an X-Device-Size preflight so a provably too-small target device fails before the first PUT rather than mid-transfer.
  • Filesystem upload reports its progress total up front from the preflight tar scan instead of growing a running total that only became complete at the last entry.
  • Manifest format version 3. Version 2 archives are still read; they simply carry no recorded sizes and the reader measures instead.
  • Resumed staging with no source MD5 is now verified by decoded size instead of being trusted on sight.

Before / After

Real 4-volume snapshot (sds-replicated-thin-r3, 2 block + 2 filesystem), all four PVCs nominally 1Gi:

Volume Nominal Size (PVC) Recorded rawSizeBytes / storedSizeBytes
block-pvc-1 1,073,741,824 1,077,665,792
block-pvc-2 1,073,741,824 1,077,665,792
fs-pvc-1 1,073,741,824 524,291,072
fs-pvc-2 1,073,741,824 996,150,272
image image

storedSizeBytes matched the actual on-disk file size (stat) exactly for all four volumes.

Download progress total for that snapshot: 3.4 GiB (real measured) instead of 4.0 GiB (4 x 1Gi nominal).

Validation

Numbers above come from a full d8 snapshot download / upload cycle against a live test cluster on a build containing this branch; recorded sizes were cross-checked against stat on the produced archive files.

Tests

  • internal/snapshot/archive/snapshot_yaml_test.go - format version 3, round-trip, version 2 read compatibility
  • internal/snapshot/archive/fsmetadata_test.go - tar raw-size sum
  • internal/snapshot/compress/decode_test.go - decoded-size measurement per codec
  • internal/snapshot/volume/payload_size_test.go, manifest_worker_test.go, progress_test.go - measurement at finalization and progress accounting
  • internal/snapshot/volume/fs_test.go - resumed staging verified by size without a source MD5
  • internal/snapshot/snapimport/{volume,fs,plan}_test.go - upload trusts the recorded size, device-size preflight, up-front filesystem total

Header-only pass over data.tar's PAX metadata, no decode required.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
For zstd, reads only frame headers. Other codecs still need a
streaming pass, but no output is buffered.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
VolumeInfo gains RawSizeBytes/StoredSizeBytes alongside the existing
nominal Size, under a new format version. Size stays what it always
was: the PVC quantity used to provision the scratch volume on
re-import, not the payload's actual byte size — a thin-provisioning
backend rounds the device up from it, so the two can differ.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
MeasurePayload reads the actual data.bin[.<ext>]/data.tar on disk and
is called once per node at finalize time, since a resumed or
re-published node may not have downloaded anything in this run.

Test fixtures in pipeline/manifest_worker switch from placeholder
bytes to real zstd/tar payloads, since finalize now parses them.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
An already-staged file with no source MD5 to compare against was
trusted on sight. Decode it and compare the real plaintext size
against the declared one instead; a mismatch re-fetches, same as an
MD5 mismatch already did.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
Upload's declared block-transfer size used to come from the nominal
PVC quantity for every codec, block included. A thin-provisioning
backend rounds the underlying device up from that quantity, so a
compressed payload's real decoded size can exceed it — upload then
rejected valid archives as size-mismatched.

Now resolveBlockPayloadSize trusts the size recorded in the archive
(from the previous commits) when present, falling back to measuring
the payload itself for older archives. Also adds an X-Device-Size
preflight so a target device provably too small fails before the
first PUT instead of mid-transfer.

Filesystem upload's progress total is now reported once, up front,
from the preflight tar scan's exact sum — instead of growing as a
running total that only reaches completeness at the last entry.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
@kkozoriz kkozoriz changed the title [snapshot] snapshot payload size [snapshot] Record the measured payload size instead of the nominal PVC size Aug 30, 2026
Shortens overly long doc/inline comments this branch added across
production and test files, keeping the same meaning, to reduce diff
size and ease review. No behavior or test-logic changes.

Signed-off-by: Konstantin Kozoriz <konstantin.kozoriz@flant.com>
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.

1 participant