Skip to content

tarfs: compact Entry, reconstructing tar.Header on demand - #2433

Draft
markusthoemmes wants to merge 1 commit into
chainguard-dev:mainfrom
markusthoemmes:tarfs-compact
Draft

tarfs: compact Entry, reconstructing tar.Header on demand#2433
markusthoemmes wants to merge 1 commit into
chainguard-dev:mainfrom
markusthoemmes:tarfs-compact

Conversation

@markusthoemmes

@markusthoemmes markusthoemmes commented Aug 25, 2026

Copy link
Copy Markdown
Member

A tarfs index retains ~1KB per file: the stored tar.Header costs three time.Times and several always-zero fields, every entry carries a PAX map allocated to hold a single well-known checksum record, and hdr.FileInfo() boxes another allocation. Since the package cache keeps a tarfs index alive per cached package, this multiplies across every file of every package in long-running processes.

Store a compact form instead: packed scalar fields, the APK-TOOLS.checksum.SHA1 record hex-decoded into a fixed [20]byte with remaining PAX records (xattrs, mostly) spilled to a nil-by-default map, and *Entry implementing fs.FileInfo itself. Entry.Header becomes a method that reconstructs the header on demand, which is a breaking change for consumers of the Entry.Header field.

On a wolfi go-1.25 package (6339 files) this shrinks the index from 987 to 324 bytes per entry (6.0 to 2.0 MB), over half of which comes from replacing the per-entry PAX map with the decoded checksum field. An image built from this branch is byte-identical to one built from main in every blob (layers, manifests, configs), differing only in the vcs-revision annotations.

A tarfs index retains ~1KB per file: the stored tar.Header costs three time.Times and several always-zero fields, every entry carries a PAX map allocated to hold a single well-known checksum record, and hdr.FileInfo() boxes another allocation. Since the package cache keeps a tarfs index alive per cached package, this multiplies across every file of every package in long-running processes.

Store a compact form instead: packed scalar fields, the APK-TOOLS.checksum.SHA1 record hex-decoded into a fixed [20]byte with remaining PAX records (xattrs, mostly) spilled to a nil-by-default map, and *Entry implementing fs.FileInfo itself. Entry.Header becomes a method that reconstructs the header on demand, which is a breaking change for consumers of the Entry.Header field.

On a wolfi go-1.25 package (6339 files) this shrinks the index from 987 to 324 bytes per entry (6.0 to 2.0 MB), over half of which comes from replacing the per-entry PAX map with the decoded checksum field. An image built from this branch is byte-identical to one built from main in every blob (layers, manifests, configs), differing only in the vcs-revision annotations.
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