COOLJAPAN
← All posts

AmateRS 0.2.2 Released — Horizontal Sharding Goes Live, with OpenTelemetry Tracing and an io_uring WAL

This AmateRS patch activates horizontal sharding (QueryRouter, ShardRegistry, a placement scheduler that drives shard splits over Raft), adds end-to-end OpenTelemetry tracing, an io_uring WAL, an FHE circuit cache, constant-time API-key auth, and an async Python SDK.

release amaters fhe homomorphic-encryption database sharding observability rust distributed-systems

The “patch” that quietly turned AmateRS into a horizontally-sharded, fully-observable distributed database.

Today we released AmateRS 0.2.2 — a patch on paper, but the largest real changelog of the 0.2.x line: horizontal sharding is now live in the public API, distributed traces flow across nodes via OpenTelemetry, and the write path can ride a kernel-bypass io_uring WAL on Linux.

No C. No Fortran. No plaintext leaving your control. While the FHE incumbents lean on TFHE-rs, Microsoft SEAL, and OpenFHE — and the database incumbents still assume a server that can read your data — AmateRS keeps computing in the dark, inside a single static binary, 100% Pure Rust, Apache-2.0. Like Amaterasu retreating into the heavenly rock cave while her light still shines, your data stays inside its cryptographic shell while the queries keep running. Serialization rides oxicode (no bincode), and the new typed cluster log uses postcard for compact, no_std-friendly ClusterCommand encoding on the Raft path.

Why AmateRS 0.2.2 is a game changer

This release crosses the line from “single-node FHE database with a consensus foundation” to “distributed FHE database you can actually shard.”

All of this lands green: 2,224 tests run, 2,224 passed, 29 skipped, 0 failed across the workspace — including 10 chaos scenarios in the cluster crate and 116 pytest cases in the Python SDK.

Technical Deep Dive

(a) Sharding & placement (Ukehi)

The sharding machinery was already written — it just wasn’t switched on. In 0.2.2, shard.rs and partitioner.rs become part of the public surface, exposing consistent-hashing / range / hash partitioning, the QueryRouter, and a k-way ResultMerger. A ShardRegistry tracks the topology, and the shard lifecycle is modeled explicitly as ShardSplit, ShardMerge, and ShardTransfer.

Driving that lifecycle is placement.rs: a stateless PlacementCoordinator that consumes a ShardRegistry snapshot and emits a deterministic PlacementPlan — split detection for hot shards (is_hot), merge detection for cold adjacent shards on the same node, and imbalance detection that proposes rebalance transfers. It is a pure function: no I/O, fully testable, fully reproducible.

The active half lives in placement_scheduler.rs. The background async PlacementScheduler runs on the Raft leader, takes the plan’s PlacementActions, and proposes them as ClusterCommand entries through Raft. Its PlacementSchedulerHandle stops the loop on drop, and you wire it in with attach_placement_scheduler().

That cluster log is now properly typed. cluster_command.rs defines ClusterCommand with 7 variantsDataPut, DataDelete, PlaceSplit, PlaceMerge, PlaceTransfer, MembershipAdd, MembershipRemove — serialized with postcard (compact, no_std-compatible), replacing the previous raw byte encoding. And because shard transfers can move a lot of state, large snapshots now stream in configurable chunks (snapshot_chunk_threshold_bytes, snapshot_chunk_size_bytes) via SnapshotStreamer / SnapshotReceiver, with per-follower streamers tracked and auto-cleaned; small snapshots still ship single-shot.

(b) Observability: OpenTelemetry

Tracing is now first-class. Behind the telemetry feature in amaters-core, telemetry.rs gives you TelemetryConfig and a TelemetryGuard: an OTLP gRPC exporter (opentelemetry-otlp), a batch SdkTracerProvider, and tracing-subscriber integration. The guard calls shutdown() on drop so in-flight spans are flushed cleanly.

To make traces span more than one node, amaters-net adds W3C TraceContext propagation for gRPC (otel_propagator.rs, also behind telemetry). TraceparentExtractor reads traceparent / tracestate from incoming gRPC metadata, inject_trace_context writes them onto outgoing calls, and TraceContextPropagatorLayer — a Tower Layer — wires it into the stack so you get end-to-end distributed traces across the cluster.

(c) Storage & compute perf

On Linux, the WAL can now bypass the kernel buffer cache. wal_uring.rs (feature io-uring in amaters-core) introduces UringWalWriter, which runs tokio_uring I/O on a dedicated OS thread with its own tokio_uring::start runtime and bridges to the async caller over an mpsc channel. UringWalConfig exposes ring_size, batch_size, direct_io, and channel_capacity, and the handle is Send + Sync + Clone so it can be shared without a mutex. Crucially, tokio-uring is now a cfg(target_os = "linux") conditional dependency, so macOS and Windows builds compile fine.

Secondary indexes also got smarter. An IndexExtractor trait plus an IndexedField type derive secondary-index entries straight from (Key, CipherBlob)without parsing the ciphertext — and IndexManager::apply_extracted applies batched, diff-based updates. Both LsmTreeStorage and MemoryStorage auto-maintain those indexes via builder methods with_index_manager / with_index_extractor / register_index, so put, delete, and atomic_update now keep indexes consistent transparently under the update_lock — with zero overhead when no manager is attached.

For compute, the new FHE CircuitCache (circuit_cache.rs in amaters-net) is a thread-safe LRU (HashMap + VecDeque + parking_lot::Mutex, clonable Arc) for compiled FHE circuits, keyed by the blake3 hash of the predicate, defaulting to 256 entries. The FILTER and UPDATE predicate sites in server.rs call circuit_cache.get_or_compile(), so repeated same-predicate requests skip PredicateCompiler::compile entirely.

(d) Operability & safety

API-key validation no longer leaks timing. In auth.rs and middleware.rs, the old HashMap lookup on raw key strings is replaced with a constant-time linear scan via the constant_time_eq crate, killing the timing side-channel oracle on stored key characters. (The hashed path, hash_keys=true, was never affected.)

Operations get an alerting brain: alert_rules.rs adds a RuleEngine that evaluates AlertRules against AlertEvents, classifies them as AlertSeverity::Info / Warning / Critical, dedups within a window (rule name + dedup key), and fans FiredAlerts out to AlertSinks. An AlertSink trait plus a LogSink (emitting via tracing) ship in the box; each FiredAlert carries its rule_name, severity, event, and dedup_key.

Schema evolution gets a framework, too. In amaters-server, migration.rs adds a MigrationRegistry where you register version→version Migration steps; plan(from, to) runs a BFS shortest-path search to produce a MigrationPlan of zero-copy step references. The Migration trait exposes from_version / to_version / description / migrate(&mut MigrationContext), and MigrationContext wraps a serde_json::Value document (get / set / remove / into_doc) threaded through the steps so they compose without copying.

And for day-to-day debugging, the CLI gains an explain command in the REPL: it prints the QueryPlanner logical and physical plans locally, with no server round-trip, for get / set / delete / range, using amaters_core::compute::QueryPlanner to render a tree-formatted LogicalPlan + PhysicalPlan with cost estimates.

Getting Started

Add the crate (or pin the SDK explicitly) and start a server:

# Library / facade meta-crate
cargo add amaters
# or pin the Rust SDK directly:
#   amaters-sdk-rust = "0.2.2"

# Start a node
cargo run --bin amaters-server -- start --data-dir ./data

Then poke at the new local query debugger inside the REPL:

cargo run --bin amaters-cli -- repl
# inside the REPL:
explain get my_key      # prints the logical + physical query plan locally (no server round-trip)

To turn on distributed tracing, build with the telemetry feature and point the OTLP exporter at your collector; on Linux, enable the io-uring feature for the kernel-bypass WAL path:

cargo run --bin amaters-server --features "telemetry,io-uring" -- start --data-dir ./data

The Python SDK is fully async now, including pool stats. amaters.PoolStats (a #[pyclass], PyPoolStats under the hood) exposes .total_connections / .active_connections / .idle_connections / .max_connections, and both pool_stats() and close() are awaitable.

What’s New in 0.2.2

Sharding & Placement

Observability — OpenTelemetry

Storage — io_uring WAL + index automation

Network — FHE CircuitCache

Security

Cluster — alert RuleEngine

Server — migration framework

Python SDK — async

CLI — explain

Testing

Dep bumps

Fixed

Tips

This is the foundation

AmateRS sits inside the COOLJAPAN ecosystem (June 2026, full ecosystem), and 0.2.2 leans on it concretely: oxicode still handles serialization (no bincode in the default path), OxiARC provides LZ4 + DEFLATE compression, and postcard gives the new typed cluster log its compact, no_std-friendly encoding on the Raft replication path. The four mythic layers — Iwato (storage), Yata (FHE compute), Ukehi (consensus), Musubi (network) — now carry a sharding plane and an observability plane on top, all in Pure Rust.

Repository: https://github.com/cool-japan/amaters

Star the repo if you believe a database should be able to compute on your data without ever reading it. Sharding is live, traces are flowing, and the dark just got a lot more scalable.

KitaSan at COOLJAPAN OÜ June 19, 2026

↑ Back to all posts