This project is a Java implementation of a Redis server, built as part of the Codecrafters "Build Your Own Redis" challenge. It demonstrates key concepts in building distributed systems, network protocols, and in-memory databases.
This Redis implementation covers the fundamental components of a modern in-memory data store:
- RESP Protocol: Complete implementation of the Redis Serialization Protocol for client-server communication.
- Multi-threaded Server: Uses Java's virtual threads to handle concurrent client connections efficiently.
- Data Structures: Support for strings, lists, sorted sets, and streams with Redis-compatible operations.
- Persistence: RDB file loading and parsing for data durability.
- Replication: Master-slave replication with automatic synchronization.
- Pub/Sub Messaging: Publisher-subscriber pattern for real-time messaging.
- Transactions: ACID-compliant transaction support with MULTI/EXEC/DISCARD.
- Expiration: Time-based key expiration with automatic cleanup.
- String Operations:
GET
,SET
,INCR
with optional expiration times - Configuration:
CONFIG GET
for server configuration retrieval - Key Management:
KEYS
,TYPE
commands for key introspection - Server Info:
INFO
,PING
,ECHO
for server status and diagnostics
- Push Operations:
LPUSH
,RPUSH
for adding elements - Pop Operations:
LPOP
,BLPOP
(blocking) for removing elements - Range Operations:
LRANGE
for retrieving ranges of elements - Metadata:
LLEN
for list length information
- Insertion:
ZADD
for adding scored members - Ranking:
ZRANK
for member position queries - Range Queries:
ZRANGE
for retrieving members by rank - Metadata:
ZCARD
,ZSCORE
for set information - Removal:
ZREM
for removing members
- Stream Creation:
XADD
for adding entries with unique IDs - Range Queries:
XRANGE
for retrieving entries by ID range - Blocking Reads:
XREAD
with optional blocking for real-time consumption
- Pub/Sub:
SUBSCRIBE
,UNSUBSCRIBE
,PUBLISH
for message broadcasting - Transactions:
MULTI
,EXEC
,DISCARD
for atomic command execution - Replication:
PSYNC
,REPLCONF
,WAIT
for master-slave synchronization
- RDB Loading: Automatic loading of Redis Database files on startup
- Key Expiration: Automatic cleanup of expired keys with millisecond precision
- Blocking Operations: Non-blocking server design with blocking client operations
- Error Handling: Comprehensive error reporting following Redis conventions
The server uses Java's virtual threads to handle client connections concurrently. Each client connection runs in its own virtual thread, allowing for high concurrency with minimal resource overhead.
Commands are processed using the Command pattern, with each Redis command implemented as a separate class that implements the Command
interface.
The storage layer provides a thread-safe, concurrent map with support for:
- Key-value storage with expiration
- Type-specific operations (lists, sorted sets, streams)
- Atomic operations and transactions
Complete implementation of the Redis Serialization Protocol (RESP) for:
- Parsing client requests
- Serializing server responses
- Handling different data types (strings, arrays, integers, errors)
The Redis server processes client requests through several stages:
-
Connection Handling: When a client connects, the server creates a new
Client
instance running in a virtual thread. -
Request Parsing: The
Deserializer
class parses incoming RESP-formatted requests intoRValue
objects representing the command and arguments. -
Command Routing: The
Redis
class routes parsed commands to the appropriateCommand
implementation based on the command name. -
Command Execution: Each command class implements the
Command
interface with anexecute
method that:- Validates arguments
- Performs the requested operation
- Returns a properly formatted response
-
Response Serialization: Results are serialized back to RESP format and sent to the client.
-
State Management: The server maintains:
- Storage: Thread-safe key-value store with expiration
- Replication: List of connected replica servers
- Pub/Sub: Channel subscriptions and message routing
- Transactions: Queued commands for atomic execution
- Java 21 or later (for virtual thread support)
- Maven 3.6+ for dependency management
-
Clone the repository:
git clone https://github.com/Md-Talim/codecrafters-redis-java.git cd codecrafters-redis-java
-
Build the project:
mvn compile
Basic Usage:
./your_program.sh
With Configuration Options:
./your_program.sh --port 6380 --dir /tmp --dbfilename dump.rdb
As a Replica Server:
./your_program.sh --port 6380 --replicaof "localhost 6379"
Available Configuration Options:
Option | Description | Default | Example |
---|---|---|---|
--port |
Port number for the server | 6379 | --port 6380 |
--dir |
Directory for RDB files | - | --dir /tmp |
--dbfilename |
RDB filename | - | --dbfilename dump.rdb |
--replicaof |
Master server for replication | - | --replicaof "localhost 6379" |
Once the server is running, you can connect using the standard Redis CLI:
redis-cli -p 6379
# Basic string operations
127.0.0.1:6379> SET mykey "Hello, Redis!"
OK
127.0.0.1:6379> GET mykey
"Hello, Redis!"
# List operations
127.0.0.1:6379> LPUSH mylist "world" "hello"
(integer) 2
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "world"
# Sorted set operations
127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
(integer) 3
127.0.0.1:6379> ZRANGE myset 0 -1
1) "one"
2) "two"
3) "three"
# Stream operations
127.0.0.1:6379> XADD mystream * field1 value1 field2 value2
"1234567890-0"
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1234567890-0"
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
# Pub/Sub messaging
127.0.0.1:6379> SUBSCRIBE news
Reading messages... (press Ctrl-C to quit)
# In another terminal:
127.0.0.1:6379> PUBLISH news "Hello subscribers!"
(integer) 1
# Transactions
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> SET key1 "value1"
QUEUED
127.0.0.1:6379> SET key2 "value2"
QUEUED
127.0.0.1:6379> EXEC
1) OK
2) OK
redis-java/
βββ src/main/java/redis/
β βββ Main.java # Application entry point
β βββ Redis.java # Core server orchestration
β βββ client/ # Client connection handling
β β βββ Client.java # Individual client management
β β βββ ReplicaClient.java # Replica server client
β βββ command/ # Redis command implementations
β β βββ Command.java # Command interface
β β βββ CommandRegistry.java # Command registration
β β βββ core/ # Basic commands (GET, SET, etc.)
β β βββ list/ # List operations (LPUSH, RPUSH, etc.)
β β βββ sortedset/ # Sorted set operations (ZADD, ZRANGE, etc.)
β β βββ stream/ # Stream operations (XADD, XREAD, etc.)
β β βββ pubsub/ # Pub/Sub commands
β β βββ replication/ # Replication commands
β β βββ transaction/ # Transaction commands
β βββ configuration/ # Server configuration management
β βββ pubsub/ # Pub/Sub message handling
β βββ rdb/ # RDB file parsing and loading
β βββ resp/ # RESP protocol implementation
β βββ store/ # Storage engine and data structures
β βββ stream/ # Stream data structure implementation
β βββ util/ # Utility classes (tracked I/O streams)
βββ your_program.sh # Server startup script
βββ README.md # This file
GET key
- Get value of keySET key value [PX milliseconds]
- Set key to value with optional expirationINCR key
- Increment integer value of key
LPUSH key element...
- Prepend elements to listRPUSH key element...
- Append elements to listLPOP key [count]
- Remove and return first element(s)BLPOP key timeout
- Blocking version of LPOPLRANGE key start stop
- Get range of elementsLLEN key
- Get list length
ZADD key score member
- Add member with scoreZRANGE key start stop
- Get members by rank rangeZRANK key member
- Get rank of memberZCARD key
- Get number of membersZSCORE key member
- Get score of memberZREM key member
- Remove member
XADD key id field value...
- Add entry to streamXRANGE key start end
- Get entries by ID rangeXREAD [BLOCK milliseconds] STREAMS key... id...
- Read from streams
SUBSCRIBE channel...
- Subscribe to channelsUNSUBSCRIBE [channel...]
- Unsubscribe from channelsPUBLISH channel message
- Publish message to channel
MULTI
- Start transactionEXEC
- Execute queued commandsDISCARD
- Discard queued commands
PING
- Test server connectivityECHO message
- Echo message backCONFIG GET parameter
- Get configuration parameterINFO
- Get server informationKEYS pattern
- Get keys matching patternTYPE key
- Get type of key
PSYNC replicationid offset
- Synchronize with masterREPLCONF option value
- Configure replicationWAIT numreplicas timeout
- Wait for replica acknowledgments
- Challenge: Handle thousands of concurrent connections efficiently.
- Solution: Used Java 21's virtual threads for lightweight concurrency and
ConcurrentHashMap
for thread-safe storage.
- Challenge: Parse and serialize Redis protocol messages correctly.
- Solution: Implemented a robust
Deserializer
andRValue
hierarchy with proper serialization methods.
- Challenge: Implement blocking commands like
BLPOP
without blocking the server. - Solution: Used
ReentrantLock
withCondition
variables for efficient waiting and notification.
- Challenge: Automatic expiration of keys without memory leaks.
- Solution: Implemented lazy expiration checking during key access with
CacheEntry
wrapper objects.
- Challenge: Keep replica servers synchronized with master state.
- Solution: Implemented command propagation with offset tracking and acknowledgment waiting. This was one of the most complex parts of the project, and I benefited from studying Enzo Caceres' implementation to understand the intricacies of the PSYNC protocol and replica management.
- Challenge: Implement Redis streams with unique ID generation and range queries.
- Solution: Created custom
Stream
class with proper ID comparison and concurrent read/write operations.
- Throughput: Capable of handling thousands of concurrent connections using virtual threads
- Memory: Efficient memory usage with lazy expiration and concurrent data structures
- Latency: Low-latency responses through optimized command routing and minimal allocations
- Scalability: Master-slave replication support for horizontal scaling
The implementation has been tested against the CodeCrafters test suite, which validates:
- Protocol compliance with official Redis specification
- Correct behavior for all implemented commands
- Proper error handling and edge cases
- Replication functionality
- Transaction atomicity
- Pub/Sub message delivery
- This project implements the Redis server as described in the CodeCrafters "Build Your Own Redis" challenge
- Thanks to the Redis team for creating such an elegant and well-documented protocol