Coalescing ManifestStore.get_many#1033
Draft
TomNicholas wants to merge 1 commit into
Draft
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1033 +/- ##
==========================================
- Coverage 90.07% 89.93% -0.14%
==========================================
Files 36 36
Lines 2206 2275 +69
==========================================
+ Hits 1987 2046 +59
- Misses 219 229 +10
🚀 New features to boost your workflow:
|
TomNicholas
force-pushed
the
manifeststore-coalescing-get-many
branch
from
July 1, 2026 21:30
834b1d0 to
e86e1f1
Compare
TomNicholas
force-pushed
the
manifeststore-coalescing-get-many
branch
from
July 1, 2026 22:02
e86e1f1 to
3f770c4
Compare
Implement Store.get_many on ManifestStore: resolve the requested chunk keys through the manifests to (source file, byte range), group the requests by source file, coalesce each group into runs, and serve each run with a single ranged read that is sliced back into per-chunk buffers. Keys that are not plain manifest-backed chunks (metadata, inlined, or missing chunks) are served individually via `get`. Coalescing uses two knobs (the object_store / async-tiff model): a run merges references whose gap is <= `coalesce_max_gap_bytes` as long as the resulting read stays <= `coalesce_max_bytes`. The gap defaults to 0 - merge only adjacent references, a pure win with no wasted bytes - because benchmarking a 2D map-tile query against a remote Met Office file showed that bridging larger gaps pulls in the chunks that sit between rows (a 2D box is contiguous along one axis but strided along the other), reading ~3x the needed bytes and running slower than no coalescing at all. Merging only adjacent references was ~2.8x faster than the per-chunk baseline with zero over-read. `max_bytes` (default 8 MiB) bounds the size of any single read. Depends on the cross-key `Store.get_many` API in zarr-python (zarr-developers/zarr-python#4112, #4113); until that is released the method is a dormant override. See zarr-developers#947.
TomNicholas
force-pushed
the
manifeststore-coalescing-get-many
branch
from
July 2, 2026 01:43
3f770c4 to
7761438
Compare
This was referenced Jul 8, 2026
Closed
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.
Implements the chunk-coalescing idea from #947: teach
ManifestStoreto satisfy a batch of chunk requests with fewer, larger reads by deriving an "effective shard index" from the manifests at read time.ManifestStore.get_many(overriding the new cross-keyStore.get_many) resolves the requested chunk keys to(source file, byte range), groups requests by source file, coalesces each group into runs, and serves each run with one ranged read that is sliced back into per-chunk buffers. No file-format assumptions, no spec changes. Keys that aren't plain manifest-backed chunks (metadata, inlined, missing) fall back to per-keyget.Coalescing uses the object_store / async-tiff two-knob model: references merge into one read when their gap is
<= coalesce_max_gap_bytesand the merged read stays<= coalesce_max_bytes.Why
coalesce_max_gap_bytesdefaults to 0Benchmarking a 2D map-tile query (5×5 chunks of
air_temperature) against a remote Met Office file on Azure, versus the status quo of onegetper chunk:A 2D spatial box is contiguous along one axis but strided along the other (row-major chunk layout), so a large gap bridges the row stride and pulls in the chunks between rows — reading ~3× the needed bytes and running slower than no coalescing. Merging only adjacent references is a pure win: zero over-read, ~2.8× faster (collapsing 25 requests into 5). Hence the default gap of 0;
coalesce_max_bytes(8 MiB) just bounds the size of any single read. A non-zero gap is available for callers who know their access is contiguous.Depends on the
Store.get_manyAPI and its use inBatchedCodecPipelinein zarr-python (zarr-developers/zarr-python#4112, zarr-developers/zarr-python#4113); until those are released this is a dormant override, tested in isolation.xref #947
Draft — feedback welcome on the approach and the config surface.