Name Last Update
examples Loading commit data...
src Loading commit data...
test Loading commit data...
.gitignore Loading commit data...
CMakeLists.txt Loading commit data...
LICENSE Loading commit data...
README.md Loading commit data...
make.sh Loading commit data...

README.md

redox

Modern, asynchronous, and wicked fast C++11 client for Redis

Overview

Redox provides an elegant high-level interface to Redis that makes it easy to write high-performance applications. It is built on top of hiredis (but uses only its asynchronous API, even for synchronous calls) and libev.

  • A single command() method, templated by the user based on the expected return type
  • Callbacks are std::functions, so they can capture state - lambdas, member functions, bind expressions
  • Thread-safe - use one Redox object in multiple threads or multiple Redox objects in one thread
  • Automatic pipelining, even for synchronous calls from separate threads
  • Small,
  • Access to low-level reply objects when needed
  • 100% clean Valgrind reports

Performance Benchmarks

Benchmarks are given by averaging the results of five trials of various programs in examples/. The results are on an AWS t2.medium instance running Ubuntu 14.04 (64-bit). During these tests, Redox communicated with a local Redis server over TCP. Results are slightly faster using Unix sockets.

  • 100 repeating asynchronous commands (speed_test_async_multi): 710,014 commands/s
  • One repeating asynchronous command (speed_test_async): 195,159 commands/s
  • One blocking command in a loop (speed_test_sync): 23,609 commands/s

Build from source

Instructions provided are for Ubuntu, but Redox is fully platform-independent.

Get the build environment:

sudo apt-get install git cmake build-essential

Get the dependencies:

sudo apt-get install libhiredis-dev libev-dev

For testing:

sudo apt-get install libgtest-dev

Build Redox and examples using CMake (a helper script is provided):

cd redox
./make.sh

Tutorial

Coming soon. For now, look at the example programs located in examples/, and the snippets posted below.

Basic synchronous usage:

redox::Redox rdx = {"localhost", 6379}; // Initialize Redox
rdx.start(); // Start the event loop

rdx.del("occupation");

if(!rdx.set("occupation", "carpenter")) // Set a key, check if succeeded
  cerr << "Failed to set key!" << endl;

cout << "key = occupation, value = \"" << rdx.get("occupation") << "\"" << endl;

rdx.stop(); // Shut down the event loop

Output: key = occupation, value = "carpenter"

The command method launches a command asynchronously. This is the root of every method in Redox that executes a command:

/**
* Create an asynchronous Redis command to be executed. Return a pointer to a
* Command object that represents this command. If the command succeeded, the
* callback is invoked with a reference to the reply. If something went wrong,
* the error_callback is invoked with an error_code. One of the two is guaranteed
* to be invoked. The method is templated by the expected data type of the reply,
* and can be one of {redisReply*, string, char*, int, long long int, nullptr_t}.
*
*            cmd: The command to be run.
*       callback: A function invoked on a successful reply from the server.
* error_callback: A function invoked on some error state.
*         repeat: If non-zero, executes the command continuously at the given rate
*                 in seconds, until cancel() is called on the Command object.
*          after: If non-zero, executes the command after the given delay in seconds.
*    free_memory: If true (default), Redox automatically frees the Command object and
*                 reply from the server after a callback is invoked. If false, the
*                 user is responsible for calling free() on the Command object.
*/
template<class ReplyT>
Command<ReplyT>* command(
  const std::string& cmd,
  const std::function<void(const std::string&, const ReplyT&)>& callback = nullptr,
  const std::function<void(const std::string&, int status)>& error_callback = nullptr,
  double repeat = 0.0,
  double after = 0.0,
  bool free_memory = true
);

The command_blocking method is the root of all synchronous calls. It calls command then uses a condition variable to wait for a reply.

/**
* A wrapper around command() for synchronous use. Waits for a reply, populates it
* into the Command object, and returns when complete. The user can retrieve the
* results from the Command object - ok() will tell you if the call succeeded,
* status() will give the error code, and reply() will return the reply data if
* the call succeeded.
*/
template<class ReplyT>
Command<ReplyT>* command_blocking(const std::string& cmd);