fix(sync): materialize git-backed blobs so large pull/fetch stops re-inflating (promptctl-sync-pull-l07p)#276
Merged
Conversation
…inflating (promptctl-sync-pull-l07p) A large `lit sync pull`/`fetch` over a git-backed remote was O(reads x blobsize): dolt's GitBlobstore served each NBS ranged read (footer/index/chunk) by streaming and re-inflating the whole ~18.5MB archive blob from byte 0. The footer read uses a negative offset, so it re-inflated almost the entire blob just for the trailer. This is the same git-blob pathology PR #274 fixed for init adopt, here fixed at the source so every sync path (fetch/pull/receive/clone) benefits. The fix lives in dolt's blobstore: materialize each immutable, content-addressed blob to a local file once and serve every range by seek. Pin a transient one-commit fork via `replace` until the upstream PR (dolthub/dolt#11264) merges; then drop the replace and bump the dolthub/dolt/go pin. The full ./internal/... suite passes against the patched dolt (behavior-preserving: same bytes, served from a file instead of a re-inflated stream). The authoritative regression test — BlobReader invoked once per blob, not once per range — ships in the upstream PR with the code it guards. Claude-Session: https://claude.ai/code/session_01TMiknvhzuS1tM8frgeDwmH
There was a problem hiding this comment.
Coding Agent Review
Reviewed 1 scope(s): go-deps.
go-deps — Reviewed go.mod replace directive and go.sum entries swapping github.com/dolthub/dolt/go for the brandon-fryslie fork. The change is clean: correct syntax, proper go.sum entries, informative WHY comment with upstream PR reference and removal plan. No LAW violations introduced. Dependency direction remains one-way.
✅ Approved
Reviewed by config auto→deepseek / claude-code / deepseek-v4-pro.
Cost: $0.0182 · 198,295 in / 5,064 out tokens · claude-code/deepseek-v4-pro · est.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the
lit sync pull/fetchlarge-pull slowness over a git-backed remote (ticketpromptctl-sync-pull-l07p) — the same git-blob ranged-read pathology PR #274 fixed forlit initadopt, now fixed at the source so every sync path benefits.Root cause
On a git-backed remote, Dolt's NBS table files live inside git blob objects, which have no random access.
dolt'sGitBlobstoreserved a ranged read by streaming the whole blob throughgit cat-fileand discarding the prefix (store/blobstore/git_blobstore.go: sliceInlineBlob). NBS reads a table file with many small ranged reads — footer (a negative-offset tail read), index, then chunk-by-chunk — so each read re-inflated nearly the entire ~18.5 MB archive blob from byte 0. A largeDOLT_FETCH/DOLT_PULLwas O(reads × blobsize): tens of GB of redundant zlib and thousands of subprocess spawns. (Incremental syncs pull a small delta and were already fine; #274 already routed the cold init-adopt through clone.)Decision (the ticket asked for one)
Three options were on the table:
Seek.Chosen: option 1. It's the single seam (
[LAW:single-enforcer]) where "git blob, no random access" meets "NBS table file, expects random access," so one change fixes fetch and pull and receive and clone/adopt at once. Option 2 requires a "large vs small pull" branch ([LAW:no-mode-explosion]/[LAW:dataflow-not-control-flow]), duplicates transfer logic, and leaves fetch/receive slow. Option 1 is also literally what dolt's ownTODO(gitblobstore)recommends.How it ships
The fix lives entirely inside the pinned upstream
dolthub/dolt. This PR adds a transientreplacedirective pointinggithub.com/dolthub/dolt/goat a one-commit fork that carries the patch:The upstream PR is open at dolthub/dolt#11264. Once it merges, drop the
replaceand bump thedolthub/dolt/gopin — the fork is temporary.Regression guard
The authoritative regression test lives with the code it guards, in the fork / upstream PR:
TestGitBlobstore_RangedReads_MaterializeBlobOnceasserts that N scattered ranged reads of one blob invokeBlobReaderexactly once (pre-fix: N; post-fix: 1). On the lit side, the full./internal/...suite — including the real-remoteTestAdoptRemoteByCloneBootstrapsAndReAdoptsandTestSyncReconcile*integration tests — passes green against the patched dolt, confirming the change is behavior-preserving (same bytes, served from a file instead of a re-inflated stream).https://claude.ai/code/session_01TMiknvhzuS1tM8frgeDwmH