Skip to content

ZMap

ZMap is a RESP protocol proxy over FoundationDB’s ordered key-value API, with convenience commands for typed numeric operations, atomic mutations, and range queries. All operations are scoped to the session’s active namespace.

Keys are stored in lexicographic order, enabling efficient range reads, range deletes, and key selector navigation. All operations inherit FoundationDB’s ACID transaction guarantees.

Keys and values are raw bytes. At the storage level there is no schema and no type system. Interpretation is left to the client. Keys are maintained in lexicographic order by FoundationDB, which enables ordered scans and range operations without secondary indexes.

Each ZMap entry is scoped to the session’s current namespace. The same key in different namespaces refers to different entries, providing full data isolation between namespaces.

On top of the raw byte layer, ZMap provides typed set, increment, and read commands for three numeric encodings:

EncodingSetIncrementReadSizeConflict behavior
int64ZSET.I64ZINC.I64ZGET.I648 bytesConflict-free (atomic ADD)
float64ZSET.F64ZINC.F64ZGET.F648 bytesRead-modify-write
decimal128ZSET.D128ZINC.D128ZGET.D12816 bytesRead-modify-write

ZINC.I64 is conflict-free because it maps directly to FoundationDB’s atomic ADD mutation, so concurrent increments on the same key never cause transaction conflicts. ZINC.F64 and ZINC.D128 perform a read-modify-write cycle because FoundationDB has no native atomic mutation for floating-point or decimal addition; concurrent calls on the same key can conflict.

If a key does not exist, all increment commands create it with an implicit starting value of zero.

> ZINC.I64 counter 10
OK
> ZINC.I64 counter 20
OK
> ZGET.I64 counter
(integer) 30

ZMUTATE exposes FoundationDB’s conflict-free atomic mutation primitives through a single command. Because mutations do not read the current value before writing, concurrent mutations on the same key do not cause transaction conflicts.

Available mutation types:

TypeDescription
ADDLittle-endian integer addition
BIT_AND / BIT_OR / BIT_XORBitwise operations
MIN / MAXUnsigned lexicographic minimum / maximum
BYTE_MIN / BYTE_MAXByte-level minimum / maximum
COMPARE_AND_CLEARClears the key if its current value equals the operand
APPEND_IF_FITSAppends the operand if the result fits within the value size limit
SET_VERSIONSTAMPED_VALUESets a value with a versionstamp embedded in the value

The operand is the raw byte representation of the value. For ADD, it is a little-endian signed 64-bit integer. The example below atomically adds 5 to counter. \x05\x00\x00\x00\x00\x00\x00\x00 is the 8-byte little-endian encoding of 5:

> ZMUTATE counter "\x05\x00\x00\x00\x00\x00\x00\x00" ADD
OK

In client SDKs, the operand is a byte array:

Java

ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(5).array();

Python

struct.pack('<q', 5)

JavaScript

const buf = Buffer.alloc(8);
buf.writeBigInt64LE(5n);

The ordered key space enables efficient range operations:

  • ZGETRANGE: Read an ordered range of key-value pairs with optional LIMIT (default 100), REVERSE, and key selector parameters. Both endpoints are inclusive by default.
  • ZDELRANGE: Delete all keys in a half-open interval [begin, end).
  • ZGETKEY: Resolve the key name that matches a key selector (first_greater_or_equal, first_greater_than, last_less_than, last_less_or_equal) relative to a reference key. Useful for cursor-like navigation.
  • ZGETRANGESIZE: Return the estimated byte size of a key range, backed by FoundationDB’s getEstimatedRangeSizeBytes API.

The wildcard * represents an unbounded boundary. Both ZGETRANGE and ZDELRANGE support *. For example, ZGETRANGE * * scans the entire subspace and ZDELRANGE * * clears it.

> ZGETRANGE key-0 key-5 LIMIT 3 REVERSE
1) 1) "key-5"
2) "f"
2) 1) "key-4"
2) "e"
3) 1) "key-3"
2) "d"

By default, each ZMap command auto-commits: Kronotop creates a FoundationDB transaction, executes the command, and commits immediately. To group multiple commands into a single atomic unit, wrap them in BEGIN / COMMIT:

> BEGIN
OK
> ZSET key1 100
OK
> ZSET key2 200
OK
> COMMIT
OK

ROLLBACK discards all uncommitted changes. Read commands (ZGET, ZGETRANGE, ZGETKEY, ZGETRANGESIZE) support snapshot reads via SNAPSHOTREAD ON, which avoids read conflict ranges for higher throughput on read-heavy workloads.

See Transactions for details on explicit transactions, snapshot reads, and FoundationDB constraints.

CommandDescription
ZSETSet a key-value pair
ZGETGet the value for a key
ZDELDelete a key
ZDELRANGEDelete a range of keys
ZGETRANGEGet an ordered range of key-value pairs
ZGETKEYResolve a key name by key selector
ZGETRANGESIZEGet the estimated byte size of a key range
ZMUTATEPerform an atomic mutation on a key
ZSET.I64Set a value as a signed 64-bit integer
ZINC.I64Atomically increment a 64-bit integer
ZGET.I64Get a value as a signed 64-bit integer
ZSET.F64Set a value as a double-precision float
ZINC.F64Increment a 64-bit floating-point value
ZGET.F64Get a value as a double-precision float
ZSET.D128Set a value as a decimal128 number
ZINC.D128Increment a 128-bit decimal value
ZGET.D128Get a value as a decimal128 number