A modular data kernel written in Rust.
Janus explores protocols, storage engines, and cache building blocks behind a small execution core — not as a drop-in replacement for existing databases.
- Layered design: transport, protocol, serializer, kernel, storage
- First milestone targets TCP + RESP + in-memory key/value (
SET/GET/DELETE/EXPIRE/TTL/SAVE/MULTI/EXEC/DISCARD/INFO/TRACES/AUTH) - Modular storage:
StorageEnginetrait +Box<dyn StorageEngine>in the Kernel (dependency inversion) - Default plugin:
MemoryStorageEngine(HashMap); pedagogical second plugin:BTreeStorageEngine(BTreeMap) - Optional snapshot persistence via
--dbfile/JANUS_DBFILE - Optional append-only WAL via
--wal/JANUS_WAL(mutually exclusive with--dbfile) - Concurrent TCP clients share one in-memory store (
Arc<Mutex<Kernel>>) over Tokio async TCP - Phase 10 experiment: in-process primary → replica via
ReplicationSink+apply_replication_record(no Raft / cluster) - Pedagogical transactions: Redis-style
MULTI/EXEC/DISCARD(command queue + commit/abort; no WATCH / ACID claims) - Pedagogical metrics: Kernel counters inspected via
INFO(not Prometheus / OpenTelemetry) - Pedagogical tracing: Kernel span ring buffer inspected via
TRACES(not OTLP / W3C Trace Context) - Pedagogical authentication: optional
requirepass+AUTH <password>with a per-connectionNOAUTHgate (no ACL / users / TLS)
This project does not:
- Replace Redis or PostgreSQL
- Aim to be production-ready in early versions
- Bundle every Redis command or clustered topology on day one
- Run a multi-node cluster or consensus protocol in the default server binary
- Provide WATCH, Lua scripting, or full ACID transactions
- Export Prometheus / OpenTelemetry metrics or distributed tracing
- Provide ACL / authorization, multiple users, or TLS
TCP listen with RESP SET / GET / DEL / EXPIRE / TTL / SAVE / MULTI / EXEC / DISCARD / INFO / TRACES / AUTH over a pluggable in-memory store (lazy key expiry, optional snapshot file or WAL). Networking uses Tokio (#[tokio::main], task per connection); all connections share one Kernel under a Mutex. The composition root injects storage via build_storage() — Memory by default; BTreeStorageEngine proves the plugin seam in tests. Default bind 0.0.0.0:6380.
Replication (Phase 10, pedagogical): cargo run remains a single-node Memory primary. An optional ReplicationSink on the Kernel notifies after successful Set / Delete / Expire; a second in-process Kernel can apply those records (apply_replication_record). Covered by the harness under src/replication/harness.rs — not a production cluster, Raft, failover, or sharding.
Transactions (pedagogical): MULTI queues subsequent commands; EXEC applies them in order and returns a RESP array of results; DISCARD aborts without applying. Covered by the Tokio TCP e2e harness — not WATCH, nested MULTI, or distributed transactions.
Metrics (pedagogical): the Kernel tracks total_commands, keyspace_hits, and keyspace_misses. INFO returns a # Stats text bulk string with those counters. Covered by the Tokio TCP e2e harness — not Prometheus, OpenTelemetry, histograms, or tracing.
Tracing (pedagogical): the Kernel keeps a fixed-capacity ring buffer of command spans (id + command name). TRACES returns a # Traces text bulk string with the recent sequence. Covered by the Tokio TCP e2e harness — not OpenTelemetry, OTLP, or W3C Trace Context.
Authentication (pedagogical): the Kernel accepts an optional requirepass (Kernel::with_requirepass). When set, each connection starts unauthenticated and every command except AUTH <password> returns -NOAUTH Authentication required.; a matching AUTH returns +OK and unlocks that connection only, a wrong one returns -ERR invalid password. Without a requirepass the server stays open and AUTH returns -ERR AUTH called without any password configured. AUTH inside MULTI is rejected, never queued. The default cargo run server has no password; requirepass is set in the composition root and is covered by the Tokio TCP e2e harness — not ACL, multiple users, AUTH username password, or TLS.
Requirements: Rust (stable, edition 2021). Tokio is pulled in via Cargo.toml for the async TCP edge.
git clone https://github.com/samuelfabel/janus.git
cd janus
cargo test
cargo build --releasecargo run --release
# listens on 0.0.0.0:6380
cargo run --release -- --bind 127.0.0.1:6380
# or
JANUS_BIND=127.0.0.1:6380 cargo run --release
# optional snapshot path (SAVE writes here; process loads it on boot)
cargo run --release -- --dbfile /tmp/janus.snap
# or
JANUS_DBFILE=/tmp/janus.snap cargo run --release
# optional WAL path (mutations append here; process replays on boot)
cargo run --release -- --wal /tmp/janus.wal
# or
JANUS_WAL=/tmp/janus.wal cargo run --releaseQuick check with any RESP client (optional), for example:
printf '*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n' | nc 127.0.0.1 6380
printf '*3\r\n$6\r\nEXPIRE\r\n$3\r\nkey\r\n$2\r\n10\r\n' | nc 127.0.0.1 6380
printf '*2\r\n$3\r\nTTL\r\n$3\r\nkey\r\n' | nc 127.0.0.1 6380
printf '*1\r\n$4\r\nSAVE\r\n' | nc 127.0.0.1 6380
printf '*1\r\n$5\r\nMULTI\r\n' | nc 127.0.0.1 6380
printf '*3\r\n$3\r\nSET\r\n$1\r\na\r\n$1\r\n1\r\n' | nc 127.0.0.1 6380
printf '*1\r\n$4\r\nEXEC\r\n' | nc 127.0.0.1 6380
printf '*2\r\n$3\r\nGET\r\n$3\r\nkey\r\n' | nc 127.0.0.1 6380Without --dbfile / JANUS_DBFILE, SAVE returns an error (ERR save disabled).
--dbfile and --wal cannot both be set (ERR conflicting persistence).
Automated coverage lives in cargo test (Tokio TCP e2e harness on an ephemeral port, including EXPIRE/TTL, SAVE/restore, WAL recovery, multi-client shared-store concurrency, MULTI/EXEC/DISCARD transactions, the AUTH / requirepass gate, and the in-process primary→replica replication harness).
Multi-stage image (Rust builder → Debian slim runtime, non-root user). cargo run / the image entrypoint use the same Tokio server binary.
Default listen address (when the server binary binds): 0.0.0.0:6380 via JANUS_BIND or --bind (avoids clashing with Redis on 6379).
docker build -t janus:local .
docker run --rm -p 6380:6380 janus:localOverride the listen address when the binary supports it:
docker run --rm -p 6380:6380 -e JANUS_BIND=0.0.0.0:6380 janus:local
# or
docker run --rm -p 7000:7000 janus:local --bind 0.0.0.0:7000Compose:
docker compose up --buildPublic landing page (English): source in site/, published via GitHub Pages.
cd site
npm install
npm run buildcargo test
cargo checkOptional local git hooks (rejects tool co-author trailers in commit messages):
./scripts/install-git-hooks.shSee CONTRIBUTING.md. This project follows the Code of Conduct.
Please report vulnerabilities privately — see SECURITY.md.