Documentation
¶
Overview ¶
Package zarr reads and writes Zarr arrays: chunked, compressed, N-dimensional arrays stored as key/value objects. It implements Zarr v3 (read and write) and reads Zarr v2.
An array lives in a store.Store: a directory (store/fs), memory (store/mem), an HTTP server (store/http), or an object store (store/s3, store/gcs, store/azblob, each its own module). OpenArray opens an existing array as an Array whose element type T matches its dtype; CreateArray makes a new one:
st, err := fs.New("/data/out.zarr")
a, err := zarr.CreateArray[float32](ctx, st, "", []int64{4096, 4096}, []int64{512, 512},
zarr.WithCodecs(zstd.Spec(3)))
err = a.Write(ctx, zarr.All(a.Shape()), data)
Array.Read and Array.Write move a Selection, a strided hyperrectangle, between the array and a flat row-major slice, fetching or storing the chunks it touches concurrently. Array.Stream yields chunks one at a time for data that does not fit in memory.
Compression and other codecs are configured by WithCodecs from the Spec constructor in each codec package (gzip.Spec, zstd.Spec, sharding.Spec, ...). Every codec in the v3 specification ships in a subpackage of codec and is registered by importing this package.
Example ¶
Create a compressed array, write it, and read a window back.
package main
import (
"context"
"fmt"
"log"
"math"
zarr "github.com/exergy-dev/zarr-go"
"github.com/exergy-dev/zarr-go/codec/zstd"
"github.com/exergy-dev/zarr-go/store/mem"
)
func main() {
ctx := context.Background()
st := mem.New() // or fs.New(dir) for a directory on disk
shape, chunks := []int64{4, 6}, []int64{2, 3}
a, err := zarr.CreateArray[float32](ctx, st, "temperature", shape, chunks,
zarr.WithCodecs(zstd.Spec(3)),
zarr.WithFillValue(float32(math.NaN())),
zarr.WithDimensionNames([]string{"y", "x"}),
)
if err != nil {
log.Fatal(err)
}
data := make([]float32, 4*6)
for i := range data {
data[i] = float32(i)
}
if err := a.Write(ctx, zarr.All(shape), data); err != nil {
log.Fatal(err)
}
b, err := zarr.OpenArray[float32](ctx, st, "temperature")
if err != nil {
log.Fatal(err)
}
// Rows 1-2, columns 2-4.
sel := zarr.Selection{{Start: 1, Stop: 3}, {Start: 2, Stop: 5}}
out := make([]float32, sel.NumElements())
if err := b.Read(ctx, sel, out); err != nil {
log.Fatal(err)
}
fmt.Println(b.Shape(), b.Chunks(), b.Dtype(), b.DimensionNames())
fmt.Println(out)
}
Output: [4 6] [2 3] float32 [y x] [8 9 10 14 15 16]
Index ¶
- Variables
- func ChunksIntersecting(arrayShape, chunkShape []int64, sel Selection) iter.Seq[ChunkCoord]
- func Float16ToFloat32(h Float16) float32
- func MaxDecodedBytes() int64
- func SetMaxDecodedBytes(n int64)
- type Array
- func (a *Array[T]) Attrs() map[string]any
- func (a *Array[T]) Chunks() []int64
- func (a *Array[T]) DimensionNames() []string
- func (a *Array[T]) Dtype() Dtype
- func (a *Array[T]) FillValue() T
- func (a *Array[T]) Path() string
- func (a *Array[T]) Read(ctx context.Context, sel Selection, dst []T) error
- func (a *Array[T]) Shape() []int64
- func (a *Array[T]) Stream(ctx context.Context, sel Selection) iter.Seq2[Chunk[T], error]
- func (a *Array[T]) Write(ctx context.Context, sel Selection, src []T) error
- type Chunk
- type ChunkCoord
- type CreateOption
- func WithAttributes(attrs map[string]any) CreateOption
- func WithChunkKeySeparator(sep string) CreateOption
- func WithCodecs(specs ...codec.Spec) CreateOption
- func WithDimensionNames(names []string) CreateOption
- func WithFillValue(v any) CreateOption
- func WithOverwrite() CreateOption
- func WithV2ChunkKeys() CreateOption
- type DecodeError
- type DimRange
- type Dtype
- type Float16
- type Group
- type Node
- type Numeric
- type OpenOption
- type Selection
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrCodecRequiresCGO is raised at array-open time when the metadata // references a codec the current build can't handle (e.g., Blosc on // the default no-cgo build). It aliases codec.ErrRequiresCGO so callers // can errors.Is against either form. ErrCodecRequiresCGO = codec.ErrRequiresCGO // ErrShapeMismatch is returned when the caller's destination slice is // the wrong size for the requested selection. ErrShapeMismatch = errors.New("shape mismatch") // ErrUnsupportedDtype is returned when metadata declares a dtype that // isn't in the Numeric constraint set. ErrUnsupportedDtype = errors.New("unsupported dtype") // ErrCorruptMetadata is returned when a zarr.json/.zarray/.zgroup // document parses as JSON but doesn't satisfy the spec (e.g., a chunk // shape with a zero dimension, a missing required field, an // unrecognized must_understand extension). Open/OpenArray wrap the // underlying internal/metadata error with this sentinel. ErrCorruptMetadata = errors.New("corrupt metadata") // ErrUnknownCodec is returned at pipeline construction when metadata // references a codec name that isn't in the registry. It aliases // codec.ErrUnknownCodec so callers can errors.Is against either form. ErrUnknownCodec = codec.ErrUnknownCodec // ErrReadOnly is returned by Array.Write, CreateArray, and CreateGroup // when the store is not a store.Writer. It aliases store.ErrReadOnly. ErrReadOnly = store.ErrReadOnly )
Sentinel errors. Wrap with fmt.Errorf("...: %w", ...) at boundaries.
Functions ¶
func ChunksIntersecting ¶
func ChunksIntersecting(arrayShape, chunkShape []int64, sel Selection) iter.Seq[ChunkCoord]
ChunksIntersecting yields each chunk coordinate whose chunk overlaps the selection. Coordinates are emitted in row-major (C) order.
The yielded slice is reused across iterations; clone it if retained.
func Float16ToFloat32 ¶
Float16ToFloat32 expands a half-precision float to single precision.
func MaxDecodedBytes ¶
func MaxDecodedBytes() int64
MaxDecodedBytes returns the cap currently set by SetMaxDecodedBytes.
func SetMaxDecodedBytes ¶
func SetMaxDecodedBytes(n int64)
SetMaxDecodedBytes sets the maximum number of bytes any single codec invocation (gzip, zlib, zstd, blosc, ...) may decompress a chunk or shard index trailer into. This guards against decompression bombs: a small compressed payload whose header declares a huge decoded size. Pass 0 to disable the cap. The default is 1 GiB. Safe to call concurrently; the new value applies to subsequent codec invocations, except that a zstd codec fixes its decoder memory limit when built, at array open (see zstd.New).
Types ¶
type Array ¶
type Array[T Numeric] struct { // contains filtered or unexported fields }
Array is the typed view of a Zarr array. Construct via OpenArray[T].
Concurrency: Array[T].Read is internally concurrent (it dispatches per-chunk fetch+decode goroutines bounded by WithConcurrency / WithIOConcurrency) and is safe to call from multiple goroutines on the same Array.
Array[T].Write performs read-modify-write on each touched chunk and does NOT take a chunk-level lock. Concurrent Writes that touch the same chunk can lose updates; concurrent Read+Write may observe a torn intermediate state. Callers that need either pattern must serialize at the application layer (one goroutine writing per array, or a per-chunk mutex).
func CreateArray ¶
func CreateArray[T Numeric]( ctx context.Context, s store.Store, path string, shape, chunks []int64, opts ...CreateOption, ) (*Array[T], error)
CreateArray creates a new v3 array under path with the given shape and chunk shape. shape/chunks may both be empty to create a rank-0 (scalar) array. The store must implement store.Writer.
func OpenArray ¶
func OpenArray[T Numeric](ctx context.Context, s store.Store, path string, opts ...OpenOption) (*Array[T], error)
OpenArray opens the array at path and asserts its dtype matches T. Detects v3 first; falls back to v2 if zarr.json is absent.
func (*Array[T]) Attrs ¶
Attrs returns a copy of the array's user attributes (v3 "attributes", or the v2 .zattrs sidecar), or nil if it has none.
func (*Array[T]) DimensionNames ¶
DimensionNames returns a copy of the array's v3 dimension_names, or nil if it has none (always nil for v2 arrays).
func (*Array[T]) FillValue ¶
func (a *Array[T]) FillValue() T
FillValue returns the value an unwritten chunk reads as.
func (*Array[T]) Read ¶
Read materializes the selection into dst. dst must hold sel.NumElements() elements; layout is row-major (C order).
func (*Array[T]) Stream ¶
Stream yields decoded chunks intersecting sel, one whole chunk at a time, without assembling the full output buffer. Chunks are fetched and decoded sequentially; a missing chunk is yielded filled with the fill value.
Each yielded Chunk has its own freshly allocated Data, which the iterator never touches again: callers may retain it without copying.
Example ¶
Stream an array chunk by chunk instead of materializing the selection.
package main
import (
"context"
"fmt"
"log"
zarr "github.com/exergy-dev/zarr-go"
"github.com/exergy-dev/zarr-go/store/mem"
)
func main() {
ctx := context.Background()
st := mem.New()
shape, chunks := []int64{5}, []int64{2}
a, err := zarr.CreateArray[int32](ctx, st, "", shape, chunks, zarr.WithFillValue(-1))
if err != nil {
log.Fatal(err)
}
// Only the first chunk is written; the others read as the fill value.
if err := a.Write(ctx, zarr.Selection{{Start: 0, Stop: 2}}, []int32{10, 11}); err != nil {
log.Fatal(err)
}
for c, err := range a.Stream(ctx, zarr.All(shape)) {
if err != nil {
log.Fatal(err)
}
fmt.Println(c.Coord, c.Shape, c.Data)
}
}
Output: [0] [2] [10 11] [1] [2] [-1 -1] [2] [1] [-1]
func (*Array[T]) Write ¶
Write encodes the elements in src and writes them to the chunks intersecting sel. src must hold sel.NumElements() elements; layout is row-major.
Chunks are written concurrently, bounded like Read by WithConcurrency (encode) and WithIOConcurrency (store traffic). Each touched chunk is read-modify-written: if the existing chunk exists it is fetched and merged with src in the intersecting region, otherwise a new chunk filled with the array's fill value is created. Chunks that the selection covers exactly (the whole chunk shape) skip the read.
type Chunk ¶
Chunk is one decoded chunk yielded from Stream. Shape is clipped to the array bounds and Data holds exactly product(Shape) elements in row-major order. Data is freshly allocated for each chunk and owned by the caller.
type ChunkCoord ¶
type ChunkCoord []int64
ChunkCoord identifies one chunk in the chunk grid.
func (ChunkCoord) Clone ¶
func (c ChunkCoord) Clone() ChunkCoord
Clone returns a copy of c so the caller can retain it across iterator steps.
type CreateOption ¶
type CreateOption interface {
// contains filtered or unexported methods
}
CreateOption customizes CreateArray and CreateGroup. WithAttributes and WithOverwrite apply to both; every other option only means something for an array, and CreateGroup returns an error naming it rather than silently ignoring it.
Every OpenOption is also a CreateOption: passed to CreateArray, it configures the returned Array exactly as it would for OpenArray.
func WithAttributes ¶
func WithAttributes(attrs map[string]any) CreateOption
WithAttributes attaches user attributes to the new node. The map is shallow-copied so later mutations by the caller don't alter the node's in-memory or already-persisted metadata.
func WithChunkKeySeparator ¶
func WithChunkKeySeparator(sep string) CreateOption
WithChunkKeySeparator sets the separator used between chunk-coordinate components. The default chunk_key_encoding's default separator is "/"; WithV2ChunkKeys defaults it to ".". Call this after WithV2ChunkKeys in the options list to override that default.
func WithCodecs ¶
func WithCodecs(specs ...codec.Spec) CreateOption
WithCodecs sets the array's codec pipeline, in the order the v3 metadata lists it: array→array codecs (transpose), then the array→bytes codec (bytes or sharding_indexed), then bytes→bytes codecs (compression, crc32c). Each codec package has a Spec constructor:
zarr.WithCodecs(zstd.Spec(3))
zarr.WithCodecs(sharding.Spec([]int64{64, 64}, zstd.Spec(3), crc32c.Spec()))
When the list has no array→bytes codec, a little-endian bytes codec is inserted in front of the first bytes→bytes codec, so a bare compressor is enough. The default pipeline is that bytes codec alone (no compression).
func WithDimensionNames ¶
func WithDimensionNames(names []string) CreateOption
WithDimensionNames labels the array's dimensions.
func WithFillValue ¶
func WithFillValue(v any) CreateOption
WithFillValue sets the value a chunk that was never written reads as. The default is zero (false for bool). v is a Go value of the array's element kind: a bool, any integer type, any float type (NaN and ±Inf included), Float16, or a complex type; or a json.RawMessage holding the fill value in its v3 metadata form, such as a hex bit pattern ("0x7fc00000") for a specific NaN payload. The value must be representable in the array's dtype: a fractional or out-of-range value is reported by CreateArray.
func WithOverwrite ¶
func WithOverwrite() CreateOption
WithOverwrite makes CreateArray / CreateGroup unconditionally overwrite any existing zarr.json at the target path. Without it, concurrent creates use SetIfNotExists and the loser receives store.ErrAlreadyExists.
For CreateArray, an overwrite also deletes every existing key under path (chunks included) before the new metadata is written, so re-creating an array with a different shape/dtype/chunking at the same path can't leave stale chunk bytes that the new metadata's codec pipeline would decode as garbage.
func WithV2ChunkKeys ¶
func WithV2ChunkKeys() CreateOption
WithV2ChunkKeys selects the v3 "v2"-compatible chunk_key_encoding (e.g. "arr/0.1" instead of the default "arr/c/0/1"), matching the key layout Zarr v2 stores use, and defaults the separator to "." (v2's convention). Call WithChunkKeySeparator after this option to use a different separator.
type DecodeError ¶
DecodeError is returned from chunk decode failures with enough context to debug a single bad chunk in a 10M-chunk array. Err names the codec that failed (e.g. `codec "gzip": ...`) when the failure came from one.
func (*DecodeError) Error ¶
func (e *DecodeError) Error() string
func (*DecodeError) Unwrap ¶
func (e *DecodeError) Unwrap() error
type DimRange ¶
DimRange is the half-open range [Start, Stop) along one dimension, with a non-negative Step. Step 0 is equivalent to Step 1 (every element).
type Dtype ¶
type Dtype uint8
Dtype identifies the on-wire element type of a Zarr array.
func ParseDtype ¶
ParseDtype maps a v3 spec dtype name to a Dtype.
type Float16 ¶
type Float16 uint16
Float16 is the IEEE 754 binary16 type, stored as its raw bit pattern. Use Float16ToFloat32 to convert.
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group is a group node (v3 zarr.json or v2 .zgroup).
func CreateGroup ¶
func CreateGroup(ctx context.Context, s store.Store, path string, opts ...CreateOption) (*Group, error)
CreateGroup creates a new v3 group under path. The store must implement store.Writer. By default this is an atomic create: if a zarr.json already exists at the target the call returns store.ErrAlreadyExists. Pass WithOverwrite() to clobber an existing entry, and WithAttributes to attach user attributes. Any other (array-only) option is an error.
Example ¶
Groups hold arrays and other groups; paths are slash-separated.
package main
import (
"context"
"fmt"
"log"
zarr "github.com/exergy-dev/zarr-go"
"github.com/exergy-dev/zarr-go/store/mem"
)
func main() {
ctx := context.Background()
st := mem.New()
g, err := zarr.CreateGroup(ctx, st, "experiment", zarr.WithAttributes(map[string]any{"run": 7}))
if err != nil {
log.Fatal(err)
}
a, err := zarr.CreateArray[uint8](ctx, st, g.Path()+"/mask", []int64{2, 2}, []int64{2, 2})
if err != nil {
log.Fatal(err)
}
fmt.Println(g.Path(), g.Attrs()["run"], a.Path())
}
Output: experiment 7 experiment/mask
func (*Group) CreateGroup ¶
CreateGroup adds a sub-group named name under g.
type Node ¶
type Node interface {
// contains filtered or unexported methods
}
Node is the union of Group and *Array[T] returned by Open.
Callers typically use OpenArray[T] when the dtype is known at compile time and avoid the type-switch entirely.
func Open ¶
Open returns the Node (Group or Array) at path. Detects v3 by reading zarr.json; falls back to v2 (.zarray / .zgroup) if zarr.json is absent.
Example ¶
Open an array whose dtype is not known at compile time.
package main
import (
"context"
"fmt"
"log"
zarr "github.com/exergy-dev/zarr-go"
"github.com/exergy-dev/zarr-go/store/mem"
)
func main() {
ctx := context.Background()
st := mem.New()
if _, err := zarr.CreateArray[int16](ctx, st, "counts", []int64{3}, []int64{3}); err != nil {
log.Fatal(err)
}
node, err := zarr.Open(ctx, st, "counts")
if err != nil {
log.Fatal(err)
}
switch n := node.(type) {
case *zarr.Array[int16]:
fmt.Println("int16 array of shape", n.Shape())
case *zarr.Array[float32]:
fmt.Println("float32 array of shape", n.Shape())
case *zarr.Group:
fmt.Println("group at", n.Path())
}
}
Output: int16 array of shape [3]
type Numeric ¶
type Numeric interface {
bool |
int8 | int16 | int32 | int64 |
uint8 | uint16 | uint32 | uint64 |
Float16 | float32 | float64 |
complex64 | complex128
}
Numeric is the type constraint for all dtypes the typed Array[T] supports.
bool is included to match the Zarr v3 spec; one byte per element.
Deliberately exact (no ~): DtypeOf switches on T's concrete type, so a defined type like `type MyF32 float32` would satisfy an approximate constraint but map to DtypeInvalid. The exact constraint makes that a compile error instead.
type OpenOption ¶
type OpenOption func(*arrayOptions)
OpenOption customizes Open / OpenArray. It is also a CreateOption, so the same options configure the Array that CreateArray returns.
func WithConcurrency ¶
func WithConcurrency(n int) OpenOption
WithConcurrency caps the number of chunks being decoded (Read) or encoded (Write) at once. The default is the number of CPUs.
func WithIOConcurrency ¶
func WithIOConcurrency(n int) OpenOption
WithIOConcurrency caps the number of in-flight store requests a Read or Write issues. The default is four times the number of CPUs.
func WithRangeGap ¶
func WithRangeGap(b int64) OpenOption
WithRangeGap sets the maximum gap (in bytes) between adjacent ranges that will be coalesced into a single GetRange call. Used by the sharded partial-decode path: inner chunks intersecting a read's region are usually NOT contiguous in the shard body (unneeded inner chunks lie between needed rows), so paying for a few KB of extra payload is usually cheaper than paying for the latency of another round trip on a high-RTT object store. 0 disables coalescing beyond exact adjacency.
type Selection ¶
type Selection []DimRange
Selection identifies a strided hyperrectangle of an array: one DimRange per dimension, so len(sel) must equal the array rank. A zero Step selects every element in [Start, Stop), as does Step 1:
sel := zarr.Selection{{Start: 0, Stop: 1024}, {Start: 0, Stop: 1024}}
All returns the selection covering a whole array.
func (Selection) NumElements ¶
NumElements returns the count of elements covered by the selection. A rank-0 selection (nil or empty — only valid for a rank-0 array; Validate enforces len(sel) == array rank) covers exactly the one scalar element.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package codec defines the codec interfaces and the global codec registry.
|
Package codec defines the codec interfaces and the global codec registry. |
|
blosc
Package blosc provides a stub for the Zarr v3 "blosc" bytes→bytes codec in the default (no-cgo) build.
|
Package blosc provides a stub for the Zarr v3 "blosc" bytes→bytes codec in the default (no-cgo) build. |
|
bytes
Package bytes implements the Zarr v3 "bytes" array→bytes codec.
|
Package bytes implements the Zarr v3 "bytes" array→bytes codec. |
|
crc32c
Package crc32c implements the Zarr v3 "crc32c" bytes→bytes codec.
|
Package crc32c implements the Zarr v3 "crc32c" bytes→bytes codec. |
|
gzip
Package gzip implements the Zarr v3 "gzip" bytes→bytes codec.
|
Package gzip implements the Zarr v3 "gzip" bytes→bytes codec. |
|
sharding
Package sharding implements the Zarr v3 "sharding_indexed" array→bytes codec.
|
Package sharding implements the Zarr v3 "sharding_indexed" array→bytes codec. |
|
transpose
Package transpose implements the Zarr v3 "transpose" array→array codec.
|
Package transpose implements the Zarr v3 "transpose" array→array codec. |
|
zlib
Package zlib implements the Zarr v2 "zlib" bytes→bytes codec using the pure-Go compress/zlib stdlib package.
|
Package zlib implements the Zarr v2 "zlib" bytes→bytes codec using the pure-Go compress/zlib stdlib package. |
|
zstd
Package zstd implements the Zarr v3 "zstd" bytes→bytes codec using the pure-Go github.com/klauspost/compress/zstd library.
|
Package zstd implements the Zarr v3 "zstd" bytes→bytes codec using the pure-Go github.com/klauspost/compress/zstd library. |
|
internal
|
|
|
bufpool
Package bufpool provides sync.Pools of []byte keyed by power-of-two size class.
|
Package bufpool provides sync.Pools of []byte keyed by power-of-two size class. |
|
declimit
Package declimit hosts the shared decompression-output size cap consulted by the gzip, zlib, zstd and blosc codecs and the sharding index decoder.
|
Package declimit hosts the shared decompression-output size cap consulted by the gzip, zlib, zstd and blosc codecs and the sharding index decoder. |
|
metadata
Package metadata parses and marshals Zarr v3 array and group JSON, and translates v2 .zarray/.zgroup documents into the same v3-shaped types.
|
Package metadata parses and marshals Zarr v3 array and group JSON, and translates v2 .zarray/.zgroup documents into the same v3-shaped types. |
|
ndcopy
Package ndcopy provides the strided N-dimensional byte-buffer copy kernel used wherever a rectangular sub-region moves between two row-major buffers: Array[T].Read/Write/Stream's chunk<->user-buffer copies, and the sharding codec's shard<->inner-chunk and partial-decode region copies.
|
Package ndcopy provides the strided N-dimensional byte-buffer copy kernel used wherever a rectangular sub-region moves between two row-major buffers: Array[T].Read/Write/Stream's chunk<->user-buffer copies, and the sharding codec's shard<->inner-chunk and partial-decode region copies. |
|
Package store defines the Store interface that backs all zarr arrays.
|
Package store defines the Store interface that backs all zarr arrays. |
|
cache
Package cache provides an in-memory LRU caching decorator for store.Store.
|
Package cache provides an in-memory LRU caching decorator for store.Store. |
|
fs
Package fs provides a local-filesystem backend for the zarr Store interface.
|
Package fs provides a local-filesystem backend for the zarr Store interface. |
|
http
Package http provides a read-only implementation of store.Store backed by HTTP GET/HEAD requests.
|
Package http provides a read-only implementation of store.Store backed by HTTP GET/HEAD requests. |
|
mem
Package mem provides an in-memory implementation of store.Store.
|
Package mem provides an in-memory implementation of store.Store. |
|
storetest
Package storetest is a shared conformance test suite for store.Store implementations.
|
Package storetest is a shared conformance test suite for store.Store implementations. |