A high-performance, multithreaded Key-Value engine written in Modern C++ (C++20).
You can clone the repository and build it locally:
# 1. Clone the repository
git clone https://github.com/DoanTrungHuy/Spindle.git
cd Spindle
# 2. Build the project
mkdir build && cd build
cmake ..
make -j$(nproc)Add the following to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(
Spindle
GIT_REPOSITORY https://github.com/DoanTrungHuy/Spindle.git
GIT_TAG master
)
FetchContent_MakeAvailable(Spindle)
# Link it to your executable
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE spindle)Start the Spindle server from the build directory.
# Start with default settings (Host: 0.0.0.0, Port: 8888, Threads: 4)
./spindle_app
# Start with custom host, port, and number of threads
./spindle_app --host 127.0.0.1 --port 6379 --threads 8Spindle uses a simple text-based TCP protocol. You can connect to it using any language that supports TCP sockets. The default server socket is 0.0.0.0:8888 (reachable via 127.0.0.1 locally). Commands are sent with a newline character (\n) at the end.
SET <key> <value> [EX seconds | PX milliseconds]-> Returns(integer) 1\nGET <key>-> Returns<value>\nor(nil)\nif not foundDEL <key>-> Returns(integer) 1\nif deleted,(integer) 0\nif not foundTTL <key>-> Returns(integer) <seconds>\n(-1 if no TTL, -2 if not found)PERSIST <key>-> Returns(integer) 1\nif TTL removed,(integer) 0\nif not found
A Java client is provided in the clients/java/ directory.
import clients.java.SpindleClient;
public class Main {
public static void main(String[] args) {
SpindleClient client = new SpindleClient("127.0.0.1", 8888);
try {
client.connect();
// Set key with expiration
client.setEx("session:1", "active", 3600);
System.out.println(client.get("session:1"));
client.delete("session:1");
} catch (Exception e) {
e.printStackTrace();
} finally {
client.close();
}
}
}A Python client is provided in the clients/python/ directory.
import sys
# Assuming you are in the project root
sys.path.append('clients/python')
from spindle import SpindleClient
# Connect to the server (default is 127.0.0.1:8888)
client = SpindleClient(host='127.0.0.1', port=8888)
client.connect()
client.set("session:1", "active", ex=3600) # Set key with expiration
print(client.get("session:1"))
client.delete("session:1")
client.close()A JavaScript client (using Promises) is provided in the clients/javascript/ directory.
const SpindleClient = require('./clients/javascript/spindle');
async function main() {
const client = new SpindleClient('127.0.0.1', 8888);
try {
await client.connect();
// Set key with expiration
await client.set("session:1", "active", { ex: 3600 });
console.log(await client.get("session:1"));
await client.delete("session:1");
} catch (err) {
console.error(err);
} finally {
client.close();
}
}
main();You can test the server directly from your terminal using nc (netcat):
# Connect to Spindle
nc 127.0.0.1 8888
# Then type commands:
SET mykey hello
(integer) 1
GET mykey
hello
DEL mykey
(integer) 1Since Spindle is built on a simple raw text-based TCP protocol, you do not need any special database drivers. You can build your own client in absolutely any programming language using its standard built-in TCP Socket library (e.g., TcpClient in C#, fsockopen in PHP, std::net::TcpStream in Rust).
To interact with Spindle:
- Open a TCP connection to the server IP and port.
- Send your command as a string, terminated by a newline character
\n. - Read the response string (also terminated by
\n).
- High Performance: Optimized with low-level techniques (Slab Allocation, Spinlocks, Reactor pattern).
- Multithreaded: Built to handle concurrent workloads efficiently.
- Persistent: Includes a Write-Ahead Log (WAL) flusher for data safety.
- Easy to integrate: CMake-friendly and exportable as a static/shared library.
This project is licensed under the MIT License - see the LICENSE file for details.
