Design an In-Memory Key-Value Store
Build a thread-safe in-memory key-value store with structured values, attribute-based search, type validation, and basic CRUD operations.
Design and implement an in-memory key-value store similar to a simplified version of Redis.
The store maintains key-value pairs where each key is a string and its value is a structured object containing multiple attributes.
For example:
"course_101": {
"name": "System Design",
"price": 1499.00,
"published": true,
"duration": 45
}
The system should support storing, retrieving, deleting, listing, and searching entries while maintaining thread safety and consistent attribute data types.
This one tests whether you can model a Redis-like attribute store cleanly — structured values with a global type registry, CRUD with exact output contracts, and thread-safe search indexing that stays correct under concurrent access.
Objective
The primary objective is to design and implement a thread-safe, in-memory key-value store that supports string keys, typed structured values (String / Integer / Double / Boolean), type-validated put, get, delete, keys, and attribute-based search — with strict output rules and concurrent correctness.
Functional Requirements
Requirements are split into three tiers so you know what to prioritize under time pressure: build first, guard invariants strictly, and handle I/O and edge cases correctly.
Part 1 — Basic Requirements
Core functionality you must build and get working first.
1. In-Memory Storage
The complete data store exists in memory. No database or file-system persistence — focus on modelling, type registry, and thread-safe operations.
2. Keys
3. Structured Values
Example:
"product_501": {
"name": "Mechanical Keyboard",
"price": 2499.00,
"stock": 120,
"available": true
}
4. Thread Safety
Part 2 — Core Operations
1. get(String key)
get("product_501") → name: Mechanical Keyboard, price: 2499.00, stock: 120, available: true
2. put(String key, List<Pair<String, String>> attributes)
Example:
put product_501 name Mechanical-Keyboard price 2499.00 stock 120 available true
3. delete(String key)
Remove the specified key and its value. If the key does not exist, no output is required.
4. keys()
5. search(String attributeKey, String attributeValue)
Part 3 — Validations, Representation & I/O
1. Attribute Type Validation
Example — stock first seen as integer:
stock = 100 → type = Integer
stock = 250 → valid
stock = 250.50 → Data Type Error (double vs integer)
Similarly:
available = true → type = Boolean
available = 1 → Data Type Error
Type validation is global — do not store the entry if any attribute fails. The established type map remains unchanged on error.
2. Object Representation
3. Input Format
4. Output Rules
Example Usage: Full Walkthrough
Here's how a sample session runs end-to-end — each command with its immediate output, using varied entries so every case is distinct (like Parking Lot's car → bike → truck flow).
1. Create entries (put — no output on success)
> put product_101 name Wireless-Mouse price 899.00 stock 50 available true
> put course_101 name System-Design price 1499.00 duration 45 published true
> put product_205 name USB-C-Hub price 1499.00 stock 30 available true
2. Get & sorted keys
> get product_101
name: Wireless-Mouse, price: 899.00, stock: 50, available: true
> keys
course_101,product_101,product_205
> search available true
product_101,product_205
Covers String (name), Double (price 899.00), Integer (stock 50), and Boolean (available true) in one round.
3. Search by different attributes
> search stock 30
product_205
> search duration 45
course_101
> search published true
course_101
Each attribute pulls a different subset — not just available — and results stay sorted.
4. Type validation — Data Type Error (Double vs Integer)
price was first seen as Double (899.00 on product_101), so an Integer must be rejected and the old entry kept.
> put product_501 name Laptop-Stand price 1999 stock 15 available false
Data Type Error
> get product_501
No entry found for product_501
> put product_501 name Laptop-Stand price 1999.00 stock 15 available false
> get product_501
name: Laptop-Stand, price: 1999.00, stock: 15, available: false
Type is fixed on first occurrence across the entire store. A bad put stores nothing and the registry stays unchanged — next retry with 1999.00 (Double) succeeds.
5. Replace, delete, and missing key
put on an existing key completely replaces it; delete is silent.
> put product_101 name Wireless-Mouse price 999.00 stock 75 available true
> get product_101
name: Wireless-Mouse, price: 999.00, stock: 75, available: true
> delete course_101
> get course_101
No entry found for course_101
> keys
product_101,product_205,product_501
6. Search after mutation
> search price 999.00
product_101
> search available true
product_101,product_205
> search available false
product_501
One walkthrough hits all contracts — typed puts with replacement, sorted keys, filtered search, global Data Type Error guard, and missing-key handling — while staying thread-safe for concurrent get/put/delete/search.