Redic is a from-scratch Redis-compatible server written in C. It speaks the RESP protocol, accepts concurrent client connections (one thread per client), parses incoming commands against declarative argument schemas, and dispatches them to a single-threaded data store.
The data layer uses an actor pattern to guarantee serializable access without locks. All reads and writes go through a message-passing pipeline rather than touching shared memory directly:
- Sewer — a channel backed by a ring buffer that passes poop (messages) from client threads down to the data store. Client threads push an operation in and block until they get a response back through a per-request reply channel.
- Septic Tank — where all the poop ends up. A single-threaded actor that drains the sewer one message at a time, executes the operation against the in-memory hashmap, and flushes the result back to the caller.
- Potty — a dedicated persistence actor for write mutations (
SET,DEL). Successful mutations are forwarded from the septic tank to potty in the same operation order so they can be written as an append-only stream for recovery.
Because the septic tank is the only thread that ever touches the data, there are no data races and no mutexes needed.
Potty is Redic's append-only persistence path (Redis-style AOF direction):
- The septic tank executes commands first, then forwards only successful mutations to potty.
- Potty receives mutation payloads (
SepticTankMutation) through its own sewer channel. - This keeps persistence ordering consistent with in-memory write ordering because both are driven by the single septic tank actor.
Current status: potty scaffolding and mutation routing are implemented; on-disk flush/replay logic is still in progress.
- Make sure you have
makeand any C compiler installed on your system. - Run
git clone git@github.com:WinterCore/redic.git && cd redic - To build the project, simply run
make - And finally, to run the server
./Redic(it will run on port 6969 by default)
- You can use any Redis cli or you can just use
redis-cliwhich comes bundled with Redis - Don't forget to specify the port of Redic when running commands, eg:
redis-cli -p 6969 SET foo bar
- TCP server with configurable port
- Concurrent client connections (one thread per client)
- RESP protocol parser (simple string, bulk string, array, integer, error, null)
- RESP serializer
- Actor pattern for data layer — single-threaded data store (septic tank) with lock-free reads/writes via message-passing (sewer channels + ring buffer)
- TTL stored per key with lazy expiry on access
- Inline command support (plain-text commands via telnet/netcat)
- Pipelining (handle multiple commands in a single read)
- Active expiry — background task that periodically sweeps expired keys
- Commands
-
PING [message] -
SET key value [NX|XX] [GET] [EX|PX|EXAT|PXAT|KEEPTTL] -
GET key -
DEL key [key ...] -
TTL key -
INFO -
EXISTS key [key ...] -
EXPIRE key seconds -
INCR/DECR/INCRBY/DECRBY -
APPEND key value -
MGET key [key ...]/MSET key value [key value ...] -
KEYS pattern -
TYPE key -
RENAME key newkey - Lists (
LPUSH,RPUSH,LPOP,RPOP,LRANGE) - Hashes (
HSET,HGET,HGETALL,HDEL) - Sets (
SADD,SREM,SMEMBERS,SISMEMBER)
-
- AOF persistence — potty actor/mutation routing exists; still need durable flush format, fsync policy, startup replay, and compaction
- Replication — replica handshake (
PING→REPLCONF→PSYNC), full resync on connect, partial resync via replication backlog after reconnect - Transactions —
MULTI/EXEC/DISCARDwithWATCHfor optimistic locking - Pub/Sub —
SUBSCRIBE/PUBLISH/UNSUBSCRIBEwith fan-out to blocking subscribers
