Add support for structured dtypes to zarr3 driver, open structs as void#271
Open
BrianMichell wants to merge 63 commits intogoogle:masterfrom
Open
Add support for structured dtypes to zarr3 driver, open structs as void#271BrianMichell wants to merge 63 commits intogoogle:masterfrom
zarr3 driver, open structs as void#271BrianMichell wants to merge 63 commits intogoogle:masterfrom
Conversation
…t for raw bits dtype
Implement shim for `open_as_void` driver level flag
* Begin removing void field shim * Fully removed void string shim * Cleanup debug prints * Remove shimmed validation * Remove unnecessary comment * Prefer false over zero for ternary clarity
* Implement a more general and portable example set * Fix driver cache bug * Update example for template * Cleanup example * Remove testing examples from source
* Use the appropriate fill value for open_as_void structured data * Cleanup
Collaborator
|
I'll try to get to this in about a week, before I look this one over, please double check that the prior PR works for you. Also look over this one and see if any of the suggestions from the other one applies. |
Matches the pattern from zarr v2 driver (PR google#272). When both "field" and "open_as_void" are specified in the spec, return an error since these options are mutually exclusive - field selects a specific field from a structured array, while open_as_void provides raw byte access to the entire structure.
The zarr3 URL syntax cannot represent field selection or void access mode. Following the pattern from zarr v2 driver (PR google#272), ToUrl() now returns an error when either of these options is specified instead of silently ignoring them.
…trip Following the pattern from zarr v2 driver (PR google#272), override GetBoundSpecData in ZarrDataCache to set spec.open_as_void from ChunkCacheImpl::open_as_void_. This ensures that when you open a store with open_as_void=true and then call spec(), the resulting spec correctly has open_as_void=true set. Without this fix, opening a store with open_as_void=true and then getting its spec would lose the open_as_void flag, causing incorrect behavior if the spec is used to re-open the store.
Apply changes based on feedback from google#272
Add assertions in EncodeChunk and DecodeChunk to verify that arrays are C-contiguous before performing direct memcpy operations: - In EncodeChunk: verify component arrays are C-contiguous - In DecodeChunk: verify decoded byte arrays are C-contiguous These assertions validate assumptions about array layouts that the chunk cache relies on for correct operation. The chunk cache write path (AsyncWriteArray) allocates C-order arrays, and the codec chain produces C-contiguous decoded arrays. Also adds the necessary includes and BUILD dependencies for IsContiguousLayout and c_order.
Replace raw memcpy loops with CopyArray using strided ArrayViews for structured type encoding and decoding. This follows the standard TensorStore pattern (as used in zarr v2 with internal::EncodeArray) where array copies are done via IterateOverArrays which safely handles any source/destination strides. The key insight is creating an ArrayView with strides that represent the interleaved field positions within the struct layout: - For a field at byte_offset B within a struct of size S - The strides are [..., S] instead of [..., field_size] - This allows CopyArray to correctly interleave/deinterleave fields This approach: 1. Removes the need for contiguity assertions (CopyArray handles any layout) 2. Is consistent with zarr v2's use of internal::EncodeArray 3. Uses the standard IterateOverArrays iteration pattern The void access decode path retains its memcpy with assertion because it's a simple byte reinterpretation where both arrays are known to be C-contiguous (destination freshly allocated, source from codec chain).
Replace manual stride computation loops with ComputeStrides() from
contiguous_layout.h. This is the standard TensorStore utility for
computing C-order (or Fortran-order) byte strides given a shape
and innermost element stride.
The manual loop:
Index stride = bytes_per_outer_element;
for (DimensionIndex i = rank; i-- > 0;) {
strides[i] = stride;
stride *= shape[i];
}
Is exactly equivalent to:
ComputeStrides(c_order, bytes_per_outer_element, shape, strides);
Replace manual loops with standard library and TensorStore utilities:
1. DimensionSet::UpTo(rank) - Creates a DimensionSet with bits [0, rank)
set to true. Replaces:
DimensionSet s(false);
for (i = 0; i < rank; ++i) s[i] = true;
2. std::fill_n for origins (all zeros) and std::copy_n for shape copy.
This is more idiomatic and clearer than explicit index loops.
These are standard patterns used throughout TensorStore for similar
operations on dimension sets and shape vectors.
The sub-chunk cache in sharding mode uses a grid from the sharding codec state, which doesn't know about void access. This caused issues: 1. Shape mismatch: The grid's component shape was [4, 4] but decoded arrays had shape [4, 4, 4] (with bytes dimension) 2. Invalid key generation: The grid's chunk_shape affected cell indexing Fix by: - Add `grid_has_void_dimension_` flag to track whether the grid includes the bytes dimension (false for sub-chunk caches) - For sub-chunk caches with void access on non-structured types, create a modified grid with: - Component chunk_shape including bytes dimension [4, 4, 4] - Grid chunk_shape unchanged [4, 4] (for cell indexing) - Proper chunked_to_cell_dimensions mapping This enables void access to work correctly with sharding codecs.
The ZarrShardSubChunkCache template had duplicate member variables (open_as_void_, original_is_structured_, bytes_per_element_) that were already present in the base class ChunkCacheImpl (ZarrLeafChunkCache). Access these through ChunkCacheImpl:: prefix instead to follow DRY principle and maintain consistency with other TensorStore patterns.
Reviewed the code for potential inconsistencies and fixed some bugs
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
Collaborator
|
FWIW I see a new assert failure in this PR: It's best to run all the tests as you're developing. I typically do So far this is mostly build-based issues. I'll look at more of the structure later. |
…ubspan does not exceed the grid size. This prevents potential out-of-bounds access when generating keys. Resolves: google#271 (comment)
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
laramiel
reviewed
Feb 3, 2026
| return base_dtype; | ||
| } | ||
| return absl::InvalidArgumentError( | ||
| tensorstore::StrCat("Data type not supported: ", dtype)); |
Collaborator
There was a problem hiding this comment.
Still quite a few tensorstore::StrCat in error messages. Please check all the files for these.
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.
Supersedes #264
Resolves comments 1 and 2