Cachetron is a simple in-memory data structure store that can be used as an application cache or a quick-response database.
It is a key-value store that provides access to data structures via a set of commands that are sent using a client-server model with TCP sockets.
Cachetron supports the following commands:
GET <key>
: Get the value of a key.SET <key> <value>
: Set the value of a key.DEL <key>
: Delete a key.KEYS
: Get all keys.ZADD <key> <score> <value>
: Add a value to a sorted set.ZREM <key> <value>
: Remove a value from a sorted set.ZSCORE <key> <value>
: Get the score of a value in a sorted set.ZQUERY <key> <min> <max>
: Get all values in a sorted set with scores betweenmin
andmax
.EXISTS <key>
: Check if a key exists.EXPIRE <key> <milliseconds>
: Set a key to expire inmilliseconds
milliseconds.TTL <key>
: Get the time-to-live of a key in milliseconds.COMMAND [list]
: Get a list of all commands or their verbose descriptions.SHUTDOWN
: Shutdown the server.
These commands are similar to those provided by Redis, but Cachetron is not intended to be a drop-in replacement for Redis.
It is a simple project that I created to learn more about networking and data structures in C.
Cachetron uses CMake as its build system, and it is intended for Linux systems only.
To build Cachetron, you will need to have the following installed:
CMake
3.27 or laterClang 18
and later orGCC 13
and later. C23 support is required.Ninja
1.11 or later (optional, but recommended)Python
3.11 or later (optional, for testing)
To build Cachetron, follow these steps:
# Clone the repository (or download the source code)
git clone https://github.com/dr8co/Cachetron.git
# Change directory to the project root
cd Cachetron
# Build from the main branch
git checkout main
# Create a build directory
mkdir build
# Configure CMake
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
# Build the server and client binaries
cmake --build build --target server client -j $(nproc)
Replace -G Ninja
with -G "Unix Makefiles"
if you don't have Ninja installed,
or remove it to use the default generator for your system.
Other generators may be used as well.
Pass the number of jobs to the -j
flag to speed up the build process.
The above $(nproc)
command will use the number of processors available on your system,
assuming you are on a Linux system (Which is the only target system for this project).
This builds the project in release mode. To build in debug mode, replace Release
with Debug
.
The built binaries will be in the build
directory.
To run Cachetron, you will need to start the server and connect to it using a client.
To start the server, run it from the build
directory:
# Assuming you are still in the project root
./build/server
The server will start listening on localhost:1234
by default.
If the port is already in use, the server will exit with an error.
To change the port, pass it with the --port
flag:
./build/server --port 12345
The server should be running before you start the client. Leave it running in the background or in a separate terminal.
Use the client to run the commands:
# Assuming you are still in the project root
./build/client COMMAND
Make sure both the client and the server are using the same port.
Like the server, the client will use localhost:1234
by default.
To change the port, pass it with the --port
flag:
./build/client --port 12345 COMMAND
Replace COMMAND
with one of the supported commands listed above.
The server runs indefinitely until you send the SHUTDOWN
command,
or you stop it using Ctrl+C
or by sending appropriate signals to the process.
The server prints 'EOF'
to the console after executing each command.
Caveats:
- The server does not support multiple clients at the same time.
- The client currently does not support interactive mode. Only one command can be sent at a time. If the port was changed, it must be passed with every command.
A python script is provided to run tests on the server.
Python 3.11 or later and the termcolor
package are required to run the tests.
The project uses Poetry to manage the script's virtual environment and dependencies.
The pyproject.toml file contains the Poetry configuration.
Use it to install the dependencies and activate the virtual environment:
# Install poetry
curl -sSL https://install.python-poetry.org | python3 -
# Install dependencies
poetry install
# Activate the virtual environment
poetry shell
To run the tests, invoke the script from the same directory as the client:
# Assuming you are still in the project root
cp test_cmds.py build/
./build/test_cmds.py
The script assumes that the server is running on localhost:1234
.
If not, it will search for the server executable in its
working directory and start it.
The server path can be passed with --server
flag:
./test_cmds.py --server ./build/server
If the port is in use, pass a different port with the --port
flag:
./test_cmds.py --server ./build/server --port 12345
The script also searches for the client executable in the same directory.
The client path can be passed with --client
flag:
./test_cmds.py --client ./build/client
The script will run a series of commands and check the output. Unexpected output will be logged to the console.
To suppress color output, run the script with --no-color
flag:
./test_cmds.py --server ./build/server --client ./build/client --no-color
Alternatively, you can set the NO_COLOR
environment variable:
NO_COLOR=1 ./test_cmds.py --server ./build/server --client ./build/client
Remember to deactivate the virtual environment when you are done:
# Exit the virtual environment
exit
Note: Running the script is roughly similar to:
# Running the server in the background
./build/server > /dev/null 2>&1 &
# Running the tests with the client in a loop
# The tests are predefined in the script
for (( i = 0; i < cmds_len; i++ )); do
output=$(./build/client COMMAND) # The command is different for each iteration
# Log the output if it is unexpected
if [ "$output" != "${expected_output[$i]}" ]; then
env echo -e "Test $i failed: Expected:\n '${expected_output[$i]}'\nbut got:\n'$output'"
fi
done
# The last command stops the server
./build/client SHUTDOWN
The server uses a set of data structures to store the keys and values.
These data structures are tested using the Google Test framework.
The Google Test Suite requires a C++-14 capable compiler.
Since the project is built with C23 support, a C++-14 capable compiler should be available.
The tests have been configured to run with the CMake build system.
To run the tests, you need to build the test binaries:
# From the project root,
# Configure CMake if you haven't already
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
# Build all targets
cmake --build build --target all -j $(nproc)
After building the project, you can run the tests:
# Assuming you are still in the project root and you have built the project
cd build && ctest -C Release -j $(nproc)
Remember to replace -C Release
with -C Debug
if you built the project in debug mode.
Do not try running the tests if you haven't built the test binaries.
Cachetron is licensed under the GNU General Public License v3.0.
See LICENSE for more information.