Skip to content

storage: filesystem, pool FSObject reads via PackHandle#2154

Merged
pjbgf merged 1 commit into
go-git:mainfrom
hiddeco:fix-fsobject-shared-packhandle
Jun 2, 2026
Merged

storage: filesystem, pool FSObject reads via PackHandle#2154
pjbgf merged 1 commit into
go-git:mainfrom
hiddeco:fix-fsobject-shared-packhandle

Conversation

@hiddeco

@hiddeco hiddeco commented May 25, 2026

Copy link
Copy Markdown
Member

Materialising an FSObject returned by EncodedObject previously fell back to a direct o.fs.Open(packPath) on every Reader() call, bypassing the per-pack file-descriptor pool introduced in billy.Filesystem that pays an mmap/munmap on each Open, the regression amplified to ~400x more pack opens over 500 reads on the basic fixture1.

The cure threads the dotgit-cached *packhandle.PackHandle into the *packfile.Packfile via a new WithPackHandle option taking a PackHandleResolver. objectFromHeader captures the resolver in the FSObject.acquireRandom closure, so every read acquires a fresh cursor against the pool-owned SharedFile. The resolver re-runs on every Reader call, which lets cached FSObjects survive cleanPackList invalidations such as the one NewObjectPack triggers before a repack.

The internal *packhandle.PackHandle stays internal — the public packfile.PackHandle interface returns io.ReadSeekCloser and RandomReader, and DotGit.PackHandle returns the interface through an unexported adapter so callers can't accidentally call Close() on a catalog-owned handle. Packfile.Close joins the scanner-close and owned-handle close errors via errors.Join.

@hiddeco hiddeco force-pushed the fix-fsobject-shared-packhandle branch 2 times, most recently from 226f97c to d69e5a5 Compare May 25, 2026 12:18
Comment thread plumbing/format/packfile/internal_test.go Outdated
Comment thread storage/filesystem/object_bench_test.go Outdated
@hiddeco hiddeco force-pushed the fix-fsobject-shared-packhandle branch 2 times, most recently from 50a8b1f to d1cecf0 Compare May 26, 2026 17:33
@hiddeco hiddeco marked this pull request as ready for review May 27, 2026 07:21
Materialising an `FSObject` returned by `EncodedObject` previously
fell back to a direct `o.fs.Open(packPath)` on every `Reader()`
call, bypassing the per-pack file-descriptor pool introduced in
`billy.Filesystem` that pays an mmap/munmap on each Open, the
regression amplified to ~400x more pack opens over 500 reads on
the basic fixture[1].

The cure threads the dotgit-cached `*packhandle.PackHandle` into
the `*packfile.Packfile` via a new `WithPackHandle` option taking
a `PackHandleResolver`. `objectFromHeader` captures the resolver
in the `FSObject.acquireRandom` closure, so every read acquires
a fresh cursor against the pool-owned `SharedFile`. The resolver
re-runs on every `Reader` call, which lets cached FSObjects
survive resets of dotgit's pack-handle store such as the one
`NewObjectPack` triggers before a repack.

The internal `*packhandle.PackHandle` stays internal — the
public `packfile.PackHandle` interface returns `io.ReadSeekCloser`
and `RandomReader`, and `DotGit.PackHandle` returns the interface
through an unexported adapter so callers can't accidentally call
`Close()` on a dotgit-owned handle. `Packfile.Close` releases
only the scanner cursor; the resolver-owned handle outlives the
Packfile.

[1]: go-git#2153 (comment)

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <[email protected]>
@hiddeco hiddeco force-pushed the fix-fsobject-shared-packhandle branch from d1cecf0 to 2a435ca Compare May 29, 2026 13:52

@pjbgf pjbgf left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hiddeco thanks for working on this. 🙇

@pjbgf pjbgf merged commit 053c039 into go-git:main Jun 2, 2026
17 checks passed
@hiddeco hiddeco deleted the fix-fsobject-shared-packhandle branch June 3, 2026 07:19
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