A Redis-compatible server written in Rust. It uses RESP2, persists writes to an append-only file, and accepts connections from any standard Redis client.
cargo build --release
Requires Rust 2024 edition (stable ≥ 1.85).
tinyredis # defaults
tinyredis /path/to/tinyredis.conf
All directives are optional. Unknown directives are silently ignored.
bind 127.0.0.1
port 6379
appendonly yes
appendfilename "tinyredis.aof"
appendfsync everysec # always | everysec | no
maxmemory 0 # bytes; 0 = no limit; supports kb/mb/gb suffixes
maxmemory-policy noeviction
requirepass "" # empty = no authentication
appendfsync controls how often the AOF file is flushed to disk:
| value | behaviour |
|---|---|
always |
sync after every write |
everysec |
sync once per second in the background (default) |
no |
let the OS decide |
maxmemory-policy controls what happens when used memory exceeds maxmemory:
| policy | behaviour |
|---|---|
noeviction |
return an error on writes (default) |
allkeys-lru |
evict any key by approximate LRU |
volatile-lru |
evict a TTL key by approximate LRU |
allkeys-random |
evict any key at random |
volatile-random |
evict a random TTL key |
volatile-ttl |
evict the TTL key with the shortest remaining lifetime |
SET GET DEL EXISTS TYPE EXPIRE EXPIREAT PEXPIRE PEXPIREAT TTL PTTL PERSIST STRLEN APPEND GETDEL GETSET INCR INCRBY DECR DECRBY INCRBYFLOAT MGET MSET
SET supports EX, PX, EXAT, PXAT, NX, XX, GET, KEEPTTL.
HSET HMSET HGET HMGET HDEL HEXISTS HLEN HKEYS HVALS HGETALL HINCRBY HINCRBYFLOAT HSETNX
LPUSH RPUSH LPOP RPOP LLEN LRANGE LINDEX LSET LINSERT LREM LTRIM LMOVE
SADD SREM SISMEMBER SMISMEMBER SMEMBERS SCARD SRANDMEMBER SPOP SUNION SINTER SDIFF SUNIONSTORE SINTERSTORE SDIFFSTORE SMOVE
ZADD ZREM ZSCORE ZINCRBY ZRANK ZREVRANK ZCARD ZCOUNT ZRANGE ZRANGEBYSCORE ZREVRANGEBYSCORE ZRANGEBYLEX ZPOPMIN ZPOPMAX ZRANDMEMBER ZUNIONSTORE ZINTERSTORE
ZADD supports NX, XX, GT, LT, CH, INCR. ZRANGE supports the unified BYSCORE/BYLEX/REV/LIMIT syntax from Redis 6.2.
KEYS SCAN DBSIZE RENAME FLUSHDB FLUSHALL
MULTI EXEC DISCARD
Commands queued inside MULTI are executed atomically on EXEC. Per-command errors do not abort the transaction.
PING ECHO QUIT AUTH CLIENT ID CLIENT GETNAME CLIENT SETNAME CLIENT LIST
INFO BGREWRITEAOF
BGREWRITEAOF rewrites the AOF to a compact snapshot of the current keyspace, then atomically replaces the existing file.
On startup, tinyredis replays the AOF file to restore state. Every mutating command is appended to the file in RESP2 format. Commands with redundant representations are canonicalized before logging (e.g. ZINCRBY is logged as ZADD, ZPOPMIN/ZPOPMAX as ZREM).
BGREWRITEAOF compacts the AOF by serializing the live keyspace into a minimal set of commands (SET, RPUSH, HSET, SADD, ZADD, with PEXPIREAT where applicable), writing to a temporary file, then renaming it into place.
cargo test
Integration tests use the redis crate to connect to a live server instance spun up per test. AOF is disabled in tests.
src/
main.rs entry point, config loading, AOF setup
server.rs accept loop, per-connection handler, MULTI/CLIENT state
connection.rs buffered RESP2 reader/writer
parser.rs RESP2 frame parsing and serialization
store.rs in-memory key-value store, eviction, snapshot
persistence.rs AOF writer, fsync policy, BGREWRITEAOF
config.rs config file parser
stats.rs server stats, client registry
commands/
core.rs SET, GET, DEL, EXPIRE, TTL, TYPE, ...
extra.rs INCR, APPEND, MSET, GETDEL, ...
hash.rs H* commands
list.rs L* commands
set.rs S* commands
zset.rs Z* commands
keyspace.rs KEYS, SCAN, RENAME, FLUSH*, BGREWRITEAOF
info.rs INFO
Values are stored as Bytes (zero-copy clones). Lists use VecDeque, sorted sets use a dual-index of HashMap<String, f64> and BTreeMap<(OrderedFloat<f64>, String), ()> for O(log N) insert and O(N) range queries. The LRU clock is a separate HashMap<String, u64> to avoid touching the entry struct.