Skip to content

Update packfile design doc to match merged writer and reader implementations - #737

Merged
tamirms merged 2 commits into
feature/full-historyfrom
update-packfile-design-doc-reader
May 28, 2026
Merged

Update packfile design doc to match merged writer and reader implementations#737
tamirms merged 2 commits into
feature/full-historyfrom
update-packfile-design-doc-reader

Conversation

@tamirms

@tamirms tamirms commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

The packfile design doc has been out of sync with the implementation. Most of the divergence came in with the writer (#702) and was never reflected in the doc; the reader (#712) added a few more deltas on top. This PR brings the doc end-to-end into alignment with the merged code.

No code changes — doc-only.

Major changes

From #702 (writer) — doc was never updated

  • Format model. WriterOptions.Format is now a caller-assigned Format uint32 identifier, not the old RecordFormat enum (Compressed / Uncompressed / Raw). The built-in formats are gone — codec is plug-in via NewRecordEncoder.
  • New WriterOptions fields. NewRecordEncoder func() RecordEncoder (per-worker factory), ContentHashExtract for per-item transformation before hashing.
  • Trailer is 76 bytes (was 64). New format uint32 field at offset 8; only flagContentHash remains (flagNoCompression / flagNoCRC are gone). Magic constant corrected to 0x48434C53. Worked-example file-size math updated.
  • Records. Caller-encoded payload + library-managed item-size-index CRC. Per-record payload integrity is encoder-supplied (zstd's xxHash64, or caller's choice, or none with passthrough).
  • Writer single-goroutine constraint documented (parallel to the Reader's concurrency disclosure).
  • AppendItem semantics: no-args is a no-op, []byte{} records an empty item, parts are copied, oversized items error.
  • Sync nit: doc said fdatasync; the code calls os.File.Sync() which is fsync.
  • Concurrency sizing advice: values above runtime.NumCPU() tend to hurt throughput.
  • ErrWriterClosed added to the Errors section.

From #712 (reader)

  • ReaderOptions is a struct (was variadic WithConcurrency). Default Concurrency is 1 (serial), not 8.
  • RecordDecoder is a single concurrent-safe instance, caller-owned, not closed by Reader.Close.
  • Error semantics. ReadItems / ReadRange return errors instead of panicking. New ErrPositionsUnsorted sentinel.
  • ReadRange lifetimes. Yielded slice is invalidated after the for-range loop exits (break or natural completion); iterator itself is not safe for concurrent iteration; count == 0 is valid.
  • ReadItems cancellation / atomicity. Context is checked at batch boundaries, not between items inside a batch; ReadItems is not atomic on error (fn may have run for some positions and not others). Empty positions slice is valid. fn's error is returned verbatim.
  • Close blocks on the background open if it is still in flight.
  • Implementation notes. ReadItems uses errgroup.WithContext (no more atomic-flag cancellation); single concurrent-safe decoder + package-level workspace pool replaces the old per-Reader decoder pool.

New section

  • Codec Contract. Documents Format uint32, the RecordEncoder / RecordDecoder interfaces, and the in-tree zstd codec (*zstd.Compressor / *zstd.Decompressor).

Polish

  • Disambiguated "format version" (the on-disk version byte vs the caller-assigned Format field) at the index-encoding section.
  • Used KiB/MiB binary prefixes where referring to specific code constants (1 MiB pooled buffer, 256 KiB speculative read).
  • Parallel-pipeline gate description corrected (triggered by encoder/hash, not by Concurrency).

Verification

Doc was fact-checked end-to-end against the current implementation in cmd/stellar-rpc/internal/packfile/ via five review passes: three parallel agents on API surface, on-disk format, and behavior/implementation; followed by deep audits dedicated to the writer side and the reader side. All trailer offsets, struct fields, method signatures, error names, default values, lifetime contracts, and implementation claims verified against code.

Test plan

  • No code changes; no tests to run
  • Doc renders cleanly in GitHub preview
  • All anchors / cross-references resolve

🤖 Generated with Claude Code

@tamirms tamirms changed the title Update packfile design doc to match merged reader implementation Update packfile design doc to match merged writer and reader implementations May 13, 2026
…tations

The packfile design doc has been out of sync with the implementation.
Most of the drift came in with the writer (#702) and was never reflected
in the doc; the reader (#712) added a few more deltas. This brings the
doc end-to-end into alignment with the merged code.

From #702 (writer):
- Format is a caller-assigned uint32, not the old RecordFormat enum
  (Compressed/Uncompressed/Raw). Codec is plug-in via NewRecordEncoder.
- New WriterOptions fields: NewRecordEncoder factory, ContentHashExtract.
- Trailer is 76 bytes (was 64): new format field at offset 8, only
  flagContentHash remains, magic corrected to 0x48434C53.
- Records: caller-encoded payload + library-managed item-size-index CRC;
  per-record payload integrity is encoder-supplied.
- Writer single-goroutine constraint; AppendItem semantics (no-args
  no-op, empty-bytes item, copy, MaxUint32 error); fsync (not
  fdatasync); Concurrency <= NumCPU sizing advice.
- ErrWriterClosed added to the errors list.

From #712 (reader):
- ReaderOptions is a struct (was variadic WithConcurrency); default
  Concurrency is 1, not 8; RecordDecoder is a single concurrent-safe
  instance, caller-owned, not closed by Reader.Close.
- ReadItems / ReadRange return errors instead of panicking; new
  ErrPositionsUnsorted sentinel.
- ReadRange break-early invalidates the last yielded slice; iterator
  not safe for concurrent iteration; count == 0 is valid.
- ReadItems ctx checked at batch boundaries (not per-item); non-atomic
  on error; empty positions is valid; fn errors returned verbatim.
- Close blocks waiting for the background open if it is still in flight.
- Implementation notes: errgroup.WithContext, single concurrent-safe
  decoder + package-level workspace pool, corrected parallel-pipeline
  gate.

New section: Codec Contract (Format, RecordEncoder, RecordDecoder
interfaces, zstd subpackage).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Comment thread design-docs/packfile-library.md
…y I/O is backgrounded

Open validates options synchronously before starting the background
goroutine; only file I/O runs in the background. Both error kinds are
still deferred to the first read. Matches the Go doc comment on Open in
reader.go, which the design doc had drifted from.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@tamirms
tamirms merged commit a78c79b into feature/full-history May 28, 2026
14 of 15 checks passed
@tamirms
tamirms deleted the update-packfile-design-doc-reader branch May 28, 2026 09:07
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