Guides

Atomic batches

Commit several mutations together with one version and one visibility boundary.

Write a batch

err := db.WriteBatch(ctx, []zeedb.Mutation{
    {Collection: "users", Key: []byte("a"), Value: []byte("one")},
    {Collection: "users", Key: []byte("b"), Value: []byte("two")},
    {Collection: "users", Key: []byte("old"), Delete: true},
})
if err != nil {
    return err
}

Each nonempty batch receives one monotonically increasing commit sequence. All records written by the batch share that version. An empty batch is a no-op and does not advance the sequence.

Visibility

All mutation validation happens before appending the WAL. The batch is encoded as one checksummed frame, synced in durable mode, and published under the database’s exclusive lock.

Concurrent readers observe either the committed state before the batch or the committed state after it. They never see half a batch.

This guarantee applies across collections in the current single-shard engine. It is not a multi-shard transaction protocol or a general read/write transaction API.

Repeated keys

Within one batch, the last mutation for a collection/key pair wins:

err := db.WriteBatch(ctx, []zeedb.Mutation{
    {Collection: "c", Key: []byte("key"), Value: []byte("first")},
    {Collection: "c", Key: []byte("key"), Delete: true},
    {Collection: "c", Key: []byte("key"), Value: []byte("last")},
})

The resulting value is last. Every mutation still contributes to encoded batch size and operation-count limits.

Limits and failures

The defaults are 4096 operations and a 1 MiB encoded payload. Final record sizes must fit data and memtable budgets. See configuration.

A validation failure rejects the entire batch before it changes storage. An I/O failure after WAL append begins can have an indeterminate result: a complete unacknowledged batch may appear after recovery. There are no operation IDs or retry deduplication in the current embedded engine.

On an indeterminate write/checkpoint failure, close and reopen the database and reconcile state before retrying non-idempotent application work. Sync-specific operation IDs belong to the planned SyncPath protocol.

Something to improve?Edit this page on GitHub