Current release · 11 August 2026
0.1.0-beta.3
A consolidation release: garbage collection now scales with pending work rather than total key count, the connection layer accounts for its resources exactly, and RESP client compatibility is tighter.
Garbage collection
- Every applied mutation that creates a committed version enqueues a durable GC candidate in the same atomic write batch. Routine GC drains bounded candidate prefixes below the read-pin safe point and asks
nexir-mvccfor per-key plans instead of scanning the full logical keyspace, so GC cost tracks pending debt rather than total key count. - Draining uses a bounded cursor with local catch-up guardrails instead of restarting discovery at the head of the candidate column family for every batch.
- New operator-triggered bounded deep scrub: resumable, read-pin-free deep row validation with low-priority I/O. Ordinary startup performs structural validation only and no longer deep-scans user rows, so cold start does not pay for a full scan.
- Prometheus coverage for candidate enqueue and drain, queue estimates, decode failures, oldest candidate age, eligible backlog, GC batches and bytes, incomplete plans, safe-point lag, and scrub progress.
Connection layer
- Response-permit head-of-line deadlock fixed. Response-buffer permits were released only after the ordered write, so a completed later reply could hold budget that the head of the queue still needed. Permits are now scoped to the writer.
- Exact client-buffer accounting. Input permits are derived from the buffer length instead of accumulated per read, so a client that trickles bytes can no longer consume a disproportionate share of the global buffer budget.
max_buffered_client_bytes_globalbounds buffered client input for the first time, and shrinking a buffer can never close a connection. - No uncharged frames. A parsed frame stays charged to an admission budget from the moment it leaves the client buffer until a request permit bundle owns it.
- Per-slice write deadlines. Responses are written in fixed 1 MiB slices, each with its own deadline, so a slow-but-progressing client can read a large value while a stalled reader is still bounded. Oversized-request,
QUIT/READMODE, and protocol-error frames now share that deadline. client_write_timeout_secsdefaults to 30 seconds. Because the deadline covers one slice rather than a whole burst, the implied minimum client throughput drops to 34 KiB/s while worst-case response-permit occupancy drops to 30 seconds.
Protocol and client compatibility
COMMAND,COMMAND COUNT,COMMAND INFO,COMMAND LIST, and an empty-mapCOMMAND DOCSare generated from the authoritative command registry, so client libraries that probe the command table during initialization work as expected.HELLOparses itsprotover.HELLO 3returns-NOPROTO unsupported protocol versionrather than silently continuing in RESP2, andHELLO ... AUTHreturns-ERR AUTH is not supportedrather than reporting an authentication that never happened.- Empty (
*0) and null or negative multibulk frames are consumed without a reply and leave the connection open, matching Redis. - Malformed inline, header, and bulk-length input is rejected deterministically instead of being partially consumed.
- Request arguments are zero-copy
Bytesslices of the read buffer, removing one full copy of every key and value on the request path, and a ready burst of ordered replies is written with a single syscall.
Storage and consensus
- Fail-closed corruption handling. Runtime corruption, malformed scalar rows, oversized values, and malformed GC candidate tokens fail closed; snapshot build and admission deeply validate scalar and candidate rows.
- Client writes enter Raft as independent command entries. Physical OpenRaft append batching and Raft-log group commit remain enabled and independently tunable, and the default
max_inflight_proposalsis now 512. - Response-buffer over-subscription is measurable:
nexir_client_buffered_response_bytes_max(peak since start),nexir_client_buffered_response_bytes_worst_case(configuration-derived ceiling), andnexir_client_response_permit_wait_seconds. - The repository is a Cargo workspace with compiler-enforced layer boundaries —
nexir-core,nexir-protocol,nexir-storage,nexir-consensus, and the rootnexirbinary crate. No behavior, format, or encoding change. nexir-mvccupdated to 0.3.0.
Command surface
Nexir exposes a deliberately small scalar surface over RESP2: GET, SET (with EX/PX/EXAT/PXAT), single-key DEL, EXPIRE/PEXPIRE/EXPIREAT/PEXPIREAT, PERSIST, and TTL/PTTL, plus the operational commands HELLO, PING, ECHO, QUIT, SELECT 0, COMMAND, CONFIG GET, CLIENT READMODE, INIT, and CLUSTER. See Redis compatibility for the full table.
Notes for operators
- Beta storage formats are not carried forward between releases. Start each node on a fresh data directory.
- Within one connection's pipeline, execution order is guaranteed for write-then-write and write-then-read, but not for read-then-write or read-then-read. Read the reply before issuing a write across that boundary; sequential request/response clients are unaffected.
Artifacts
| Target | Archive |
|---|---|
| Linux x86_64 | nexir-v0.1.0-beta.3-linux-x86_64.tar.gz |
| Linux ARM64 | nexir-v0.1.0-beta.3-linux-aarch64.tar.gz |
| macOS Intel | nexir-v0.1.0-beta.3-darwin-x86_64.tar.gz |
| macOS Apple Silicon | nexir-v0.1.0-beta.3-darwin-aarch64.tar.gz |
| Container | ghcr.io/nexirdb/nexir:v0.1.0-beta.3 (linux/amd64, linux/arm64) |
Each archive has an immutable same-name .sha256 sidecar under https://releases.nexir.com/v0.1.0-beta.3/. See the release file layout and the download page.