Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

22 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Redis Clone - Java Implementation

A multi-threaded in-memory key-value store inspired by Redis, built in Java with concurrent client support, persistence, and key expiration. Handles 50+ simultaneous connections with zero blocking.

πŸ“‹ Features

Core Functionality

  • GET/SET/DEL Commands - Basic key-value operations
  • Key Expiration (TTL) - Automatic removal of expired keys using EX parameter
  • Multi-Threaded Concurrency - ExecutorService thread pool for 50+ simultaneous clients
  • Thread-Safe Storage - ConcurrentHashMap for atomic operations without locks
  • Persistence (AOF) - Append-only file for crash recovery and durability
  • Concurrent Command Processing - Each client executes independently in worker threads

Network & Protocol

  • TCP Server - Listens on port 6379 (default Redis port)
  • Text-Based Protocol - Simple command parsing (space-separated arguments)
  • Connection Management - Graceful client disconnection handling

Data Management

  • Memory Efficient - Expired keys are lazily removed during access
  • Concurrent Command Processing - Each client runs in its own thread
  • Atomic Operations - Using Java's ConcurrentHashMap for thread safety

πŸ—οΈ Architecture

Project Structure

src/main/java/com/osama/redisclone/
β”œβ”€β”€ Main.java                 # Application entry point
β”œβ”€β”€ command/
β”‚   β”œβ”€β”€ CommandProcessor.java # Command parsing and execution
β”‚   └── ParsedCommand.java    # Parsed command representation
β”œβ”€β”€ model/
β”‚   └── Entry.java            # Key-value entry with expiration
β”œβ”€β”€ persistence/
β”‚   └── PersistenceManager.java # AOF file management
β”œβ”€β”€ server/
β”‚   └── RedisServer.java      # TCP server with thread pool
└── store/
    └── InMemoryStore.java    # Thread-safe in-memory storage

Key Design Decisions

1. Thread Pool for Concurrent Clients

ExecutorService clientPool = Executors.newCachedThreadPool();

while (true) {
    Socket clientSocket = serverSocket.accept();  // Main thread
    clientPool.submit(() -> handleClient(clientSocket));  // Worker thread
}
  • Main thread accepts new connections in a loop
  • Worker threads from the pool handle each client independently
  • newCachedThreadPool() dynamically creates/reuses threads as needed
  • While one thread reads from Client A, another reads from Client B
  • Result: True parallelism - multiple clients served simultaneously
  • Scalability: Tested with 50 concurrent clients, all executing in parallel

2. Persistence Strategy (Append-Only File)

  • Commands are logged to redis-clone.aof for durability
  • On startup, all persisted commands are replayed to restore state
  • Non-persistence variant (processWithoutPersistence) used during replay to avoid duplicate logging
  • Ensures data survives server crashes

3. Lazy Key Expiration

if (entry.isExpired()) {
    data.remove(key, entry);
    return null;
}
  • Keys are checked for expiration during access (lazy deletion)
  • No background cleanup thread needed
  • Memory efficient and avoids thundering herd problem

4. Thread-Safe Store

  • ConcurrentHashMap instead of HashMap for thread safety
  • No explicit synchronization needed for concurrent operations
  • Atomic operations maintain consistency across threads

πŸ“¦ Technology Stack

  • Language: Java 17
  • Build Tool: Maven 3.6+
  • Testing: JUnit 5
  • Concurrency: Java ExecutorService Thread Pool

πŸš€ Getting Started

Prerequisites

  • Java 17 or higher
  • Maven 3.6 or higher

Building the Project

mvn clean compile

Running the Server

mvn exec:java -Dexec.mainClass="com.osama.redisclone.Main"

The server will start on port 6379 and automatically replay any persisted commands from redis-clone.aof.

Testing with netcat

# In another terminal
nc localhost 6379

# Try these commands:
SET mykey "Hello, Redis!"
GET mykey
DEL mykey
GET mykey
SET counter 5 EX 10
GET counter
EXIT

πŸ§ͺ Running Tests

Execute all unit tests:

mvn test

Test Coverage

  • CommandProcessorTest - Tests command parsing and execution
  • InMemoryStoreTest - Tests concurrent access and expiration

πŸ“ Command Reference

Command Syntax Description
SET SET key value [EX seconds] Set a key with optional TTL
GET GET key Retrieve value for a key
DEL DEL key Delete a key (returns 1 if deleted, 0 if not found)
EXIT EXIT Close client connection

Examples

SET name osama                 # Set a key
GET name                       # Get the value
SET temp "temporary" EX 60     # Set with 60-second expiration
DEL name                       # Delete the key
GET name                       # Returns (nil) - key was deleted

πŸ”„ Persistent Data

The append-only file (redis-clone.aof) stores all write commands. On server restart:

  1. All persisted commands are read from the file
  2. Commands are replayed in order
  3. Server state is restored exactly as it was before shutdown

This ensures no data loss in case of unexpected crashes.

🎯 Performance Characteristics

Operation Complexity Notes
GET O(1) HashMap lookup, with expiry check
SET O(1) HashMap insertion
DEL O(1) HashMap removal
Expiry Check O(1) Performed during key access
Concurrent Requests O(1) Each client in separate thread, no queuing

Concurrency Performance

  • 10 clients Γ— 20 commands each: 210 responses in ~100ms (parallel)
  • 50 clients Γ— 10 commands each: 500 commands in ~100ms (parallel)
  • No bottlenecks: Thread pool scales dynamically with demand
  • Zero waiting: While one client waits for I/O, others execute

πŸ” Thread Safety & Concurrency

Multi-Threaded Architecture

Client 1 ─┐
Client 2 ─┼─→ Main Thread Accept ─→ Thread Pool ─→ Worker Thread 1
Client 3 ──                         (Dispatcher)   β†’ Worker Thread 2
Client 4 β”€β”˜                                        β†’ Worker Thread 3
                                                    β†’ Worker Thread N

Why It's Safe

  • ConcurrentHashMap ensures atomic read/write operations from multiple threads
  • ExecutorService provides proper thread pool management and lifecycle
  • No race conditions:
    • All store operations are atomic via ConcurrentHashMap
    • Each client runs independently in its own thread
    • Expiration checks are performed atomically during access
    • No shared mutable state across threads
  • No deadlocks: No locks used; all operations are lock-free or atomic
  • Data consistency: Commands execute in the order received per client

πŸ“š Learning Outcomes

This project demonstrates:

  • Concurrent Programming: Thread pools and ExecutorService
  • Data Structures: HashMap vs ConcurrentHashMap
  • Networking: TCP servers and socket programming
  • File I/O: Persistence and data recovery
  • Clean Architecture: Separation of concerns across modules
  • Software Design: Factory pattern for command processing

πŸ› οΈ Future Enhancements

Potential features for future versions:

  • INCR/DECR - Atomic counters
  • KEYS - Pattern-based key search
  • TTL - Query remaining time-to-live
  • FLUSHDB - Clear all data
  • INFO - Server statistics
  • CONFIG - Configuration management
  • RESP Protocol - Redis Serialization Protocol for compatibility
  • Pub/Sub - Message publishing and subscription
  • Data Structures - Lists, Sets, Hashes (beyond strings)
  • LRU Eviction - Memory limit with eviction policy

πŸ“– Development Notes

Connecting with Real Redis Clients

Currently, this implementation uses a simplified text protocol. To use with Redis CLI or other clients that expect RESP (Redis Serialization Protocol), the protocol layer would need to be updated.

Memory Management

The current implementation has no built-in memory limits. As an enhancement, LRU (Least Recently Used) eviction could be implemented to manage memory when limits are exceeded.

Persistence Details

  • Write-only operations (SET, DEL) are persisted
  • Read-only operations (GET) are not logged
  • AOF entries are in plain text for debugging

About

Multi-threaded Redis clone in Java with TCP networking, persistence (AOF), TTL expiration, and concurrent client support.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages