AEDB
aedb is an embedded Rust storage engine for applications that need:
- transactional writes
- durable WAL + checkpoint recovery
- snapshot-consistent reads
- optional permission-aware APIs for multi-tenant workloads
Primary API entry point: AedbInstance.
Why AEDB
AEDB is designed for local-first and service-side state where you want predictable durability and recovery behavior without running an external database process.
Use AEDB when you want:
- in-process storage with explicit durability controls
- deterministic crash recovery from checkpoint + WAL replay
- table + KV data models in one engine
- operational APIs for checkpoint, backup, restore, and diagnostics
Installation
[]
= "0.2.3"
= { = "1", = ["macros", "rt-multi-thread"] }
Quick Start
use AedbInstance;
use DdlOperation;
use ColumnDef;
use ;
use Mutation;
use ;
use tempdir;
async
Core Concepts
Action envelopes and typed KV numerics
For single hot-path action commits (effects + metadata in one atomic envelope), use
AedbInstance::commit_action_envelope(...) with ActionEnvelopeRequest.
Result semantics are explicit:
ActionCommitOutcome::AppliedActionCommitOutcome::Duplicate(idempotent replay, no writes applied)
Native U256 KV mutation variants are available for strict/soft decrement and bounded updates:
Mutation::KvAddU256ExMutation::KvSubU256ExMutation::KvMaxU256Mutation::KvMinU256
CommitResult also exposes idempotency metadata:
idempotency: IdempotencyOutcomecanonical_commit_seq
Data model
- Namespace hierarchy:
project -> scope -> table - Typed relational tables for structured data
- KV APIs for point lookups, prefix/range scans, and counters
- Atomic KV/table integer updates with commit-time read assertions
Casino-style hot balance updates should use native atomic mutations plus assertions, not a separate accumulator subsystem. This keeps the safety check in the same commit envelope while allowing non-conflicting atomic updates to stay parallelizable.
Atomic update safety has four layers:
preflight/preflight_plancan reject obviously invalid updates before enqueueing, such as a decrement that would underflow the snapshot it inspected.ReadAssertions in aTransactionEnvelopeare authoritative pre-apply commit-time checks. They are evaluated against the working state for the commit epoch before the write intent applies.Mutation::PostflightCheckevaluatesReadAssertions after prior mutations in the same write intent have applied to the transaction-local trial state. Use this for hot-key atomic updates when the invariant is about the post-update value; it does not add a pre-apply read dependency that would serialize every writer on the same key.- Atomic mutation variants such as
KvSubU64Ex,KvSubU256Ex,KvAddI64Bounded, andTableDecU256apply the numeric update without requiring callers to perform a separate read-modify-write. If the mutation itself cannot be applied, it returns a structured error and the envelope rolls back.
Use commit_with_preflight for simple single-mutation UX checks. Use an explicit
TransactionEnvelope with Mutation::PostflightCheck when the business invariant
depends on the value after an atomic update, for example "balance must remain
above the reserve after this debit".
use ;
use ;
use ConsistencyMode;
let balance_key = b"house/balance".to_vec;
let base_seq = db.snapshot_probe.await?;
db.commit_envelope
.await?;
// Tier-2 event stream + processor checkpoint primitives
db.emit_event
.await?;
let page = db
.read_event_stream
.await?;
db.ack_reactive_processor_checkpoint
.await?;
let processor_lag = db
.reactive_processor_lag
.await?;
For event processors, prefer watermark-batched checkpoint ACKs to reduce write load:
db.ack_reactive_processor_checkpoint_batched
.await?;
ack_reactive_processor_checkpoint_batched_as(...) isolates watermark state per caller and
only updates cache state after successful commit.
Built-in processor scheduler (period + size limits):
use Arc;
let db = new;
db.start_reactive_processor
.await?;
let status = db
.reactive_processor_runtime_status
.await;
let health = db
.reactive_processor_health
.await?;
let processors = db
.list_reactive_processors
.await?;
db.stop_reactive_processor.await?;
caller_id defines the explicit auth context for that processor runtime:
- event stream reads run via
read_event_stream_as(...) - lag/checkpoint access runs via
reactive_processor_lag_as(...)andack_reactive_processor_checkpoint_batched_as(...) - dead-letter writes run via
commit_as(...)
In secure mode, caller_id is required for start_reactive_processor(...).
For periodic refresh jobs (e.g. weekly/all-time leaderboard snapshots), set
run_on_interval: true. AEDB will invoke the processor handler on each
run_interval_ms tick even when no new events are present.
Lifecycle controls:
pause_reactive_processor(name)disables in registry and stops runtime.resume_reactive_processor(name)re-enables and starts runtime using the registered handler.list_reactive_processors(consistency)returns durable config + running state.reactive_processor_health(name, consistency)returns lag + runtime counters/timestamps.reactive_processor_slo_status(name, consistency)returns threshold checks and breach reasons.list_reactive_processor_slo_statuses(consistency)returns all processor SLO states.enforce_reactive_processor_slos(consistency)returnsUnavailablewhen any enabled processor breaches SLO.
Processor configs are durably persisted in a system registry table when started. On process restart, register the handler again and AEDB auto-resumes enabled processors:
let resumed = db
.register_reactive_processor_handler
.await?;
assert!; // true when durable registry had enabled processor config
When handler retries are exhausted, AEDB writes failed events to the durable
_system.app.reactive_processor_dead_letters table and advances checkpoint so
poison batches do not stall ingestion.
Secure mode/authenticated flows can use commit_as, commit_envelope_as,
commit_as_with_preflight, and ack_reactive_processor_checkpoint_batched_as.
Arcana-oriented engine interface primitives (effect batches, keyed-state helpers,
processor pull/commit/context) are also exposed under aedb::engine_interface
and as AedbInstance methods:
commit_effect_batch(project_id, scope_id, EffectBatch)keyed_state_read/keyed_state_read_field/keyed_state_write/keyed_state_update/keyed_state_deletekeyed_state_query_index/keyed_state_index_rankprocessor_pull(event_name, processor_id, max_count)processor_commit(processor_id, checkpoint_seq, mutations)(atomic state + checkpoint commit)processor_context(project_id, scope_id, processor_id, source_event)with:pull(max_count)read/query_indexwrite/update/deleteaccumulate/value/expose/release_exposureemitcommit
Consistency modes
Reads are snapshot-based and configurable via ConsistencyMode:
AtLatestAtSeqAtCheckpoint
use ;
let result = db
.query_with_options
.await?;
println!;
Preflight and commits
preflightandpreflight_planare advisory; state may change before commitcommit_with_preflight/commit_as_with_preflightinclude the preflight read set in the commit envelope, which catches stale reads before writes applyReadAssertions are commit-time checks for invariants that must hold under concurrencyMutation::PostflightCheckis a commit-time post-apply check for atomic updates; failed checks abort and roll back the whole envelope before publish- atomic integer updates should encode their own underflow/overflow/missing-key policy and return structured errors rather than relying on fallbacks
- use
commit_with_finality(..., CommitFinality::Visible)for low-latency user ack - use
CommitFinality::Durablefor flows that must wait for WAL durability
Low-latency profile example:
use AedbConfig;
let config = low_latency;
let db = open?;
Security and Permissions
AEDB supports permission-aware APIs via CallerContext and Permission.
open_productionandopen_securerequire authenticated*_ascallsopen_secureenforces hardened durability/recovery settings (DurabilityMode::Full, strict recovery, hash chain, HMAC)- table/KV/query access can be scoped per project/scope/resource
authz_auditandassertion_auditsystem tables provide built-in audit trails
Security/operations docs:
docs/SECURITY_ACCEPTANCE_CRITERIA.mddocs/SECURITY_OPERATIONS_RUNBOOK.mddocs/AEDB_SDK_PROCESSOR_MACRO_SPEC.mddocs/AEDB_MIGRATION_SYSTEM.md
Operational APIs
checkpoint_now()to force a fuzzy checkpoint (does not block commit/query traffic)backup_full(...)/ restore helpers for backup workflowsoperational_metrics()for commit latency, queue depth, durable head lag, and more
CLI helper (src/bin/aedb.rs) includes offline dump/parity/invariant tooling:
Explorer CLI crate (crates/aedb-explorer) provides read-only inspection of projects/scopes/tables, schema, and sample rows:
API Areas
aedb::commit: mutations, envelopes, validationaedb::query: query planning and executionaedb::catalog: schema, types, and DDLaedb::repository: typed repository/pagination helpersaedb::declarative: declarative schema migration buildersaedb::backup,aedb::checkpoint,aedb::recovery: durability and restore path
Development
Focused suites:
Security acceptance gate (mandatory profile):
Production readiness gate:
Production rollout guidance:
License
Dual-licensed under:
- MIT (
LICENSE-MIT) - Apache-2.0 (
LICENSE-APACHE)