Home|memQ Docs

Get started with memQ

memQ is a blazing-fast, Redis-inspired in-memory key-value store built from scratch in Go. It features LRU eviction, TTL, snapshot persistence, TCP server with RESP protocol, and an HTTP REST API.

Installation

Clone, configure, and run. Three steps to your own in-memory store.

1

Clone the repository

Start by cloning the memQ repository from GitHub.

Terminal
git clone https://github.com/satwaraa/memQ.git
cd memQ
2

Configure environment

Create a .env file in the project root with your settings.

.env
CAPACITY=1000
TCP_PORT=6379
HTTP_PORT=8080
3

Run the server

Start memQ with a single command. This launches the CLI, TCP server, and HTTP API simultaneously.

Terminal
go run cmd/kvstore/main.go

You'll see the interactive CLI prompt: memQ>

Quick Start

Once memQ is running, you can interact with it three ways.

CLI

Interactive REPL with 15+ commands

TCP / netcat

Redis-compatible RESP protocol on port 6379

HTTP API

JSON REST endpoints on port 8080

CLI session
memQ> SET user:1 "Alice"
OK

memQ> GET user:1
"Alice"

memQ> SETEX session:abc 3600 "token"
OK (expires in 3600s)

memQ> STATS
Keys: 2
Capacity: 1000
Hits: 1
Misses: 0
Evictions: 0

Configuration

memQ reads configuration from a .env file or environment variables.

VariableRequiredDefaultDescription
CAPACITYYesMaximum number of keys in the store
TCP_PORTYesPort for TCP server (RESP protocol)
HTTP_PORTNo8080Port for HTTP REST API
MemoryNo*Memory limit (alternative to CAPACITY)

* Either CAPACITY or Memory must be provided.

CLI Reference

Full-featured interactive REPL with 15+ commands.

Key Operations

Commands
SET <key> <value>          Set a key-value pair
GET <key>                  Get value by key
DELETE <key>               Delete a key
EXISTS <key>               Check if key exists (1/0)
KEYS                       List all keys
CLEAR                      Remove all keys

TTL Commands

Commands
SETEX <key> <sec> <value>  Set with expiration (seconds)
TTL <key>                  Get remaining time to live
EXPIRE <key> <seconds>     Set expiration on existing key
Example
memQ> SETEX cache:token 300 "abc123"
OK (expires in 300s)

memQ> TTL cache:token
285 (seconds)

memQ> EXPIRE cache:token 600
OK (expires in 600s)

Persistence

Commands
SAVE                       Save snapshot to disk
LOAD                       Load snapshot from disk

Snapshots are saved as JSON to memQ_data.json. Auto-save runs every minute. Data is also saved on graceful shutdown (Ctrl+C).

Utility

Commands
STATS                      Show hit/miss/eviction statistics
HELP                       Show all available commands
QUIT                       Exit CLI (auto-saves)

TCP Server

Redis-compatible TCP server using RESP serialization. Connect with netcat or any Redis client library.

Connecting

Terminal
# Via netcat
nc localhost 6379

# Send commands
SET name Alice
+OK

GET name
$5
Alice

PING
+PONG

Supported Commands

All CLI commands are available over TCP, plus PING.

PING, SET, GET, DEL, EXISTS, SETEX, TTL,
EXPIRE, KEYS, SAVE, LOAD, CLEAR, STATS,
HELP, QUIT

HTTP REST API

Full JSON REST API on port 8080 (configurable via HTTP_PORT).

Key Endpoints

POST/keys/{key}

Set a key-value pair. Optional TTL in seconds.

curl
curl -X POST localhost:8080/keys/user:1 \
  -H "Content-Type: application/json" \
  -d '{"value": "Alice"}'

# With TTL
curl -X POST localhost:8080/keys/session:abc \
  -H "Content-Type: application/json" \
  -d '{"value": "token123", "ttl": 3600}'
GET/keys/{key}

Retrieve a value by key.

curl
curl localhost:8080/keys/user:1

# Response: {"key": "user:1", "value": "Alice"}
DELETE/keys/{key}

Delete a key.

curl
curl -X DELETE localhost:8080/keys/user:1

# Response: {"status": "OK", "key": "user:1"}
GET/keys

List all keys in the store.

curl
curl localhost:8080/keys

# Response: {"keys": ["user:1", "session:abc"], "count": 2}

Admin Endpoints

GET/stats

Get store statistics.

Response
{
  "keys": 42,
  "capacity": 1000,
  "hits": 156,
  "misses": 3,
  "evictions": 0
}
POST/save

Trigger manual snapshot to disk.

POST/load

Load snapshot from disk.

Architecture

memQ is built with zero external dependencies for the core engine. All data structures are implemented from scratch.

Project Structure

Directory layout
memQ/
├── cmd/kvstore/main.go          # Entry point
├── env/env.go                   # Configuration loader
├── internal/
│   ├── cli/cli.go               # Interactive REPL
│   ├── protocol/resp.go         # RESP serialization
│   ├── server/
│   │   ├── server.go            # TCP server
│   │   └── http_server.go       # HTTP REST API
│   └── store/
│       ├── store.go             # Core store + LRU
│       ├── lru.go               # Doubly-linked list
│       ├── ttl.go               # TTL / expiry logic
│       └── persistence.go       # Snapshot save/load
└── tests/                       # Integration tests

LRU Eviction

When the store reaches capacity, the Least Recently Used key is automatically evicted. The implementation uses a doubly-linked list + hashmap for O(1) operations.

┌─────────────────────────────────────────────────┐
│  HashMap: map[string]*Node  →  O(1) lookup      │
│                                                  │
│  LRU List (doubly-linked):                       │
│  HEAD ←→ Node ←→ Node ←→ ... ←→ TAIL            │
│  (MRU)                            (LRU)          │
│                                                  │
│  On GET/SET: move node to HEAD                   │
│  On capacity full: evict TAIL                    │
└─────────────────────────────────────────────────┘

Thread safety via sync.RWMutex — concurrent reads, exclusive writes.

TTL & Expiry

Keys support optional Time-To-Live. A background goroutine cleans expired keys every minute.

// Each Node stores:
type Node struct {
    key      string
    value    string
    expireAt *time.Time  // nil = no expiration
    prev     *Node
    next     *Node
}

// Lazy expiry on GET + background cleaner
// store.StartTTLCleaner(1 * time.Minute)

Persistence

JSON snapshots preserve data across restarts. The LRU order is maintained during save/load.

memQ_data.json
{
  "version": "1.0",
  "capacity": 1000,
  "entries": [
    {
      "key": "user:1",
      "value": "Alice"
    },
    {
      "key": "session:abc",
      "value": "token123",
      "expire_at": "2026-02-26T00:00:00Z"
    }
  ]
}

Auto-save: Every 1 minute via background goroutine

Graceful shutdown: Saves on Ctrl+C (SIGINT/SIGTERM)

Load on startup: Automatically loads from snapshot file

TTL preservation: Expired keys are skipped during load

Built with Go · View on GitHub