From 1874f12c778f72bfdfaf24dc571762b6ec7882a0 Mon Sep 17 00:00:00 2001 From: Hayk Martirosyan Date: Tue, 27 Jan 2015 13:36:39 -0800 Subject: [PATCH] Improve CMake procedure, create dynamic lib, document --- CMakeLists.txt | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- README.md | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------------------------------------- 2 files changed, 137 insertions(+), 110 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f15bff6..6eca8c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,17 @@ cmake_minimum_required(VERSION 2.8.4) project(redox) -option(library "Build Redox as a library." ON) -option(tests "Build all tests." ON) -option(examples "Build all examples." ON) +set(REDOX_VERSION_MAJOR 0) +set(REDOX_VERSION_MINOR 2) +set(REDOX_VERSION_PATCH 0) +set(REDOX_VERSION_STRING ${REDOX_VERSION_MAJOR}.${REDOX_VERSION_MINOR}.${REDOX_VERSION_PATCH}) -# Use RelWithDebInfo if no configuration specified +option(lib "Build Redox as a dynamic library." ON) +option(static_lib "Build Redox as a static library." OFF) +option(tests "Build all tests." OFF) +option(examples "Build all examples." OFF) + +# Use Release if no configuration specified if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) @@ -33,20 +39,34 @@ set(SRC_ALL ${SRC_CORE} ${SRC_LOGGER}) include_directories(${SRC_DIR}) -# --------------------------------------------------------- -# Linked libraries -# --------------------------------------------------------- - -set(LIB_REDOX redox hiredis ev pthread) +# Dependent libraries - you may have to change +# pthread to whatever C++11 threads depends on +# for your platform +set(REDOX_LIB_DEPS hiredis ev pthread) # --------------------------------------------------------- # Library generation # --------------------------------------------------------- -if (library) +if (lib) add_library(redox SHARED ${SRC_ALL}) + target_link_libraries(redox ${REDOX_LIB_DEPS}) + + set_target_properties(redox + PROPERTIES VERSION ${REDOX_VERSION_STRING} + SOVERSION ${REDOX_VERSION_MAJOR}) + +endif() + +if (static_lib) + add_library(redox_static STATIC ${SRC_ALL}) + target_link_libraries(redox_static ${REDOX_LIB_DEPS}) + + set_target_properties(redox_static + PROPERTIES VERSION ${REDOX_VERSION_STRING} + SOVERSION ${REDOX_VERSION_MAJOR}) endif() @@ -61,7 +81,7 @@ if (tests) add_executable(test_redox test/test.cpp) target_include_directories(test_redox PUBLIC ${GTEST_INCLUDE_DIRS}) - target_link_libraries(test_redox ${LIB_REDOX} gtest) + target_link_libraries(test_redox redox gtest) # So that we can run 'make test' add_test(test_redox test_redox) @@ -74,36 +94,78 @@ endif() if (examples) add_executable(basic examples/basic.cpp) - target_link_libraries(basic ${LIB_REDOX}) + target_link_libraries(basic redox) add_executable(basic_threaded examples/basic_threaded.cpp) - target_link_libraries(basic_threaded ${LIB_REDOX}) + target_link_libraries(basic_threaded redox) add_executable(lpush_benchmark examples/lpush_benchmark.cpp) - target_link_libraries(lpush_benchmark ${LIB_REDOX}) + target_link_libraries(lpush_benchmark redox) add_executable(speed_test_async examples/speed_test_async.cpp) - target_link_libraries(speed_test_async ${LIB_REDOX}) + target_link_libraries(speed_test_async redox) add_executable(speed_test_sync examples/speed_test_sync.cpp) - target_link_libraries(speed_test_sync ${LIB_REDOX}) + target_link_libraries(speed_test_sync redox) add_executable(speed_test_async_multi examples/speed_test_async_multi.cpp) - target_link_libraries(speed_test_async_multi ${LIB_REDOX}) + target_link_libraries(speed_test_async_multi redox) add_executable(data_types examples/data_types.cpp) - target_link_libraries(data_types ${LIB_REDOX}) + target_link_libraries(data_types redox) add_executable(multi_client examples/multi-client.cpp) - target_link_libraries(multi_client ${LIB_REDOX}) + target_link_libraries(multi_client redox) add_executable(binary_data examples/binary_data.cpp) - target_link_libraries(binary_data ${LIB_REDOX}) + target_link_libraries(binary_data redox) add_executable(pub_sub examples/pub_sub.cpp) - target_link_libraries(pub_sub ${LIB_REDOX}) + target_link_libraries(pub_sub redox) add_executable(speed_test_pubsub examples/speed_test_pubsub ${SRC_ALL}) - target_link_libraries(speed_test_pubsub ${LIB_REDOX}) + target_link_libraries(speed_test_pubsub redox) + + add_custom_target(examples) + add_dependencies(examples + basic basic_threaded lpush_benchmark speed_test_async speed_test_sync + speed_test_async_multi data_types multi_client binary_data pub_sub + speed_test_pubsub + ) endif() + +# --------------------------------------------------------- +# Install (sudo make install) +# --------------------------------------------------------- + +# Install the dynamic library to /usr/lib +install(TARGETS redox DESTINATION lib) + +# Install the headers into /usr/include/redox +set(INC_CORE ${SRC_DIR}/client.hpp ${SRC_DIR}/subscriber.hpp) +set(INC_UTILS ${SRC_DIR}/utils/logger.hpp) +install(FILES ${INC_CORE} DESTINATION include/redox) +install(FILES ${INC_UTILS} DESTINATION include/redox/utils) + +# Install the top-level header into /usr/include directly +set(INC_WRAPPER ${SRC_DIR}/redox.hpp) +install(FILES ${INC_WRAPPER} DESTINATION include) + +# --------------------------------------------------------- +# Create system package (make package) +# --------------------------------------------------------- + +# build a CPack driven installer package +include(InstallRequiredSystemLibraries) +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "C++11 client for Redis") +set(CPACK_PACKAGE_VENDOR "Hayk Martirosyan") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Hayk Martirosyan ") +set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") +set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +#set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.3.1-6), libgcc1 (>= 1:3.4.2-12)") +set(CPACK_PACKAGE_VERSION_MAJOR "${REDOX_VERSION_MAJOR}") +set(CPACK_PACKAGE_VERSION_MINOR "${REDOX_VERSION_MINOR}") +set(CPACK_PACKAGE_VERSION_PATCH "${REDOX_VERSION_PATCH}") +set(CPACK_GENERATOR "DEB") +include(CPack) diff --git a/README.md b/README.md index f09e539..2956e11 100644 --- a/README.md +++ b/README.md @@ -3,33 +3,45 @@ 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](https://github.com/redis/hiredis/) -(but uses only its asynchronous API, even for synchronous calls) and -[libev](http://manpages.ubuntu.com/manpages/raring/man3/ev.3.html). - - * A single `command()` method, templated by the user based on the expected return type - * Callbacks are [std::functions](http://en.cppreference.com/w/cpp/utility/functional/function), - 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 +Redox is a C++ interface to the +[Redis](http://redis.io/) key-value store that makes it easy to write applications +that are both elegant and high-performance. Communication should be a means to an +end, not something we spend a lot of time worrying about. Redox takes care of the +details so you can move on to the interesting part. + +**Features:** + + * Runs Redis commands from strings, no explicit wrappers for the API + * Callbacks can be lambdas, class methods, bind expressions - anything + [std::function](http://en.cppreference.com/w/cpp/utility/functional/function) can hold + * Fully 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, < 1k SLOC * Access to low-level reply objects when needed * 100% clean Valgrind reports + * Accessible and robust error handling + * Fast - developed for robotics applications + +Redox is built on top of +[hiredis](https://github.com/redis/hiredis/) and +[libev](http://manpages.ubuntu.com/manpages/raring/man3/ev.3.html). It uses only the +asynchronous API of hiredis, even for synchronous commands. ## 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. +Benchmarks are given by averaging the results of five trials of the speed tests +in `examples/` on an AWS t2.medium instance running Ubuntu 14.04 (64-bit). + +Local Redis server, TCP connection: + + * 100 commandLoop calls (`speed_test_async_multi`): **710,014 commands/s** + * One commandLoop call (`speed_test_async`): **195,159 commands/s** + * Looped commandSync call (`speed_test_sync`): **23,609 commands/s** - * 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** +Results are comparable to that of an +average laptop. On a high-end laptop or PC, `speed_test_async_multi` usually tops +1 million commands per second. All results are slightly faster if over Unix sockets +than TCP. -## Build from source +## Build library from source Instructions provided are for Ubuntu, but Redox is fully platform-independent. Get the build environment: @@ -40,76 +52,29 @@ Get the dependencies: sudo apt-get install libhiredis-dev libev-dev -For testing: +Build the library: - sudo apt-get install libgtest-dev + mkdir build && cd build + cmake .. + make -Build Redox and examples using CMake (a helper script is provided): +Install into the system (optional): - cd redox - ./make.sh + sudo make install -## 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 - Command* command( - const std::string& cmd, - const std::function& callback = nullptr, - const std::function& 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 - Command* command_blocking(const std::string& cmd); +## Build examples and test suite +To build the examples, use ccmake or the following: + + cmake -Dexamples=ON .. + make examples + +To run the test suite, first make sure you have +[gtest](https://code.google.com/p/googletest/) set up, +then: + cmake -Dtests=ON .. + make test_redox + ./test_redox + +## Tutorial +Coming soon. Take a look at `examples/` for now. -- libgit2 0.21.4