{"id":13418907,"url":"https://github.com/hmartiro/redox","last_synced_at":"2025-04-05T10:08:50.275Z","repository":{"id":24965090,"uuid":"28383189","full_name":"hmartiro/redox","owner":"hmartiro","description":"Modern, asynchronous, and wicked fast C++11 client for Redis","archived":false,"fork":false,"pushed_at":"2022-08-20T14:13:55.000Z","size":274,"stargazers_count":389,"open_issues_count":34,"forks_count":101,"subscribers_count":36,"default_branch":"master","last_synced_at":"2025-03-29T09:09:50.077Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hmartiro.png","metadata":{"files":{"readme":"README.md","changelog":"HISTORY.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-23T07:00:00.000Z","updated_at":"2025-02-03T06:15:02.000Z","dependencies_parsed_at":"2022-08-23T08:31:40.652Z","dependency_job_id":null,"html_url":"https://github.com/hmartiro/redox","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hmartiro%2Fredox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hmartiro%2Fredox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hmartiro%2Fredox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hmartiro%2Fredox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hmartiro","download_url":"https://codeload.github.com/hmartiro/redox/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247318744,"owners_count":20919484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T22:01:08.697Z","updated_at":"2025-04-05T10:08:50.255Z","avatar_url":"https://github.com/hmartiro.png","language":"C++","readme":"redox\n======\nModern, asynchronous, and wicked fast C++11 client for Redis\n[![Build Status](https://travis-ci.org/hmartiro/redox.svg?branch=feature%2Ftravis-ci)]\n(https://travis-ci.org/hmartiro/redox)\n\nRedox is a C++ interface to the\n[Redis](http://redis.io/) key-value store that makes it easy to write applications\nthat are both elegant and high-performance. Communication should be a means to an\nend, not something we spend a lot of time worrying about. Redox takes care of the\ndetails so you can move on to the interesting part of your project.\n\n**Features:**\n\n * Expressive asynchronous and synchronous API, templated by return value\n * Callbacks can be lambdas, class methods, bind expressions, or any\n   [std::function](http://en.cppreference.com/w/cpp/utility/functional/function)\n * Thread-safe - use one client in multiple threads or multiple clients in one\n * Automatic pipelining, even for synchronous calls from separate threads\n * Low-level access when needed\n * Accessible and robust error handling\n * Configurable logging level and output to any ostream\n * Full support for binary data (keys and values)\n * Fast - developed for robotics applications\n * 100% clean Valgrind reports\n\nRedox is built on top of\n[hiredis](https://github.com/redis/hiredis/) and\n[libev](http://manpages.ubuntu.com/manpages/raring/man3/ev.3.html). It uses only the\nasynchronous API of hiredis, even for synchronous commands. There is no dependency on\nBoost or any other libraries.\n\n## Benchmarks\nBenchmarks are given by averaging the results of ten trials of the speed tests\nin `examples/` on an AWS t2.medium instance running Ubuntu 14.04 (64-bit) and a\nlocal Redis server.\n\n * `speed_test_async_multi` over TCP: **879,589 commands/s**\n * `speed_test_async_multi` over Unix socket: **901,683 commands/s**\n * `speed_test_async` over TCP: **203,285 commands/s**\n * `speed_test_async` over Unix socket: **301,823 commands/s**\n * `speed_test_sync` over TCP: **21,072 commands/s**\n * `speed_test_sync` over Unix socket: **24,911 commands/s**\n\nA mid-range laptop gives comparable results. Numbers can be much higher on a high-end machine.\n\n## Tutorial\nThis section introduces the main features of redox. Look in `examples/` for more inspiration.\n\n#### Hello world\nHere is the simplest possible redox program:\n\n```c++\n#include \u003ciostream\u003e\n#include \u003credox.hpp\u003e\n\nusing namespace std;\nusing namespace redox;\n\nint main(int argc, char* argv[]) {\n\n  Redox rdx;\n  if(!rdx.connect(\"localhost\", 6379)) return 1;\n\n  rdx.set(\"hello\", \"world!\");\n  cout \u003c\u003c \"Hello, \" \u003c\u003c rdx.get(\"hello\") \u003c\u003c endl;\n\n  rdx.disconnect();\n  return 0;\n}\n```\n\nCompile and run:\n\n    $ g++ hello.cpp -o hello -std=c++11 -lredox -lev -lhiredis\n    $ ./hello\n    Hello, world!\n\nThis example is synchronous, in the sense that the commands don't return until\na reply is received from the server.\n\n#### Asynchronous commands\nIn a high-performance application, we don't want to wait for a reply, but instead\ndo other work. At the core of Redox is a generic asynchronous API for executing\nany Redis command and providing a reply callback. The `command` method accepts a\nRedis command in the form of an STL vector of strings, and a callback to be invoked\nwhen a reply is received or if there is an error.\n\n```c++\nrdx.command\u003cstring\u003e({\"GET\", \"hello\"}, [](Command\u003cstring\u003e\u0026 c) {\n  if(c.ok()) {\n    cout \u003c\u003c \"Hello, async \" \u003c\u003c c.reply() \u003c\u003c endl;\n  } else {\n    cerr \u003c\u003c \"Command has error code \" \u003c\u003c c.status() \u003c\u003c endl;\n  }\n});\n```\n\nThis statement tells redox to run the command `GET hello`. The `\u003cstring\u003e` template\nparameter means that we want the reply to be put into a string and that we expect\nthe server to respond with something that can be put into a string. The full list\nof reply types is listed in this document and covers convenient access to anything\nreturned from the Redis protocol. The input vector can contain arbitrary binary\ndata.\n\nThe second argument is a callback function that accepts a reference to a Command object\nof the requested reply type. The Command object contains the reply and any error\ninformation. If `c.ok()` is true, the expected reply is accessed from\n`c.reply()` (a string in this case). If `c.ok()` is false, then the error\ncode is given by `c.status()`, which can report an error or nil reply, a reply of\nthe wrong type, a send error, etc. The callback is guaranteed to be invoked\nexactly once, and the memory for the Command object is freed automatically once\nthe callback returns.\n\nHere is a simple example of running `GET hello` asynchronously ten times:\n\n```c++\nRedox rdx;\n\n// Block until connected, localhost by default\nif(!rdx.connect()) return 1;\n\nauto got_reply = [](Command\u003cstring\u003e\u0026 c) {\n  if(!c.ok()) return;\n  cout \u003c\u003c c.cmd() \u003c\u003c \": \" \u003c\u003c c.reply() \u003c\u003c endl;\n};\n\nfor(int i = 0; i \u003c 10; i++) rdx.command\u003cstring\u003e({\"GET\", \"hello\"}, got_reply);\n\n// Do useful work\nthis_thread::sleep_for(chrono::milliseconds(10));\n\nrdx.disconnect(); // Block until disconnected\n```\n\nThe `.command()` method returns immediately, so this program doesn't wait for a reply\nfrom the server - it just pauses for ten milliseconds and then shuts down. If we want to\nshut down after we get all replies, we could do something like this:\n\n```c++\nRedox rdx;\nif(!rdx.connect()) return 1;\n\nint total = 10; // Number of commands to run\natomic_int count(0); // Number of replies expected\nauto got_reply = [\u0026](Command\u003cstring\u003e\u0026 c) {\n  count++;\n  if(c.ok()) cout \u003c\u003c c.cmd() \u003c\u003c \" #\" \u003c\u003c count \u003c\u003c \": \" \u003c\u003c c.reply() \u003c\u003c endl;\n  if(count == total) rdx.stop(); // Signal to shut down\n};\n\nfor(int i = 0; i \u003c total; i++) rdx.command\u003cstring\u003e({\"GET\", \"hello\"}, got_reply);\n\n// Do useful work\n\nrdx.wait(); // Block until shut down complete\n```\n\nThis example tracks of how how many replies are received and signals the Redox\ninstance to stop once they all process. We use an `std::atomic_int` to be safe\nbecause the callback is invoked from a separate thread. The `stop()` method\nsignals Redox to shut down its event loop and disconnect from Redis. The `wait()`\nmethod blocks until `stop()` has been called and everything is brought down.\nThe `disconnect()` method used earlier is just a call to `stop()` and then a\ncall to `wait()`.\n\n#### Synchronous commands\nRedox implements synchronous commands by running asynchronous commands and waiting\non them with condition variables. That way, we can reap the benefits of pipelining\nbetween synchronous commands in different threads. The `commandSync` method provides\na similar API to `command`, but instead of a callback returns a Command object when\na reply is received.\n\n```c++\nCommand\u003cstring\u003e\u0026 c = rdx.commandSync\u003cstring\u003e({\"GET\", \"hello\"});\nif(c.ok()) cout \u003c\u003c c.cmd() \u003c\u003c \": \" \u003c\u003c c.reply() \u003c\u003c endl;\nc.free();\n```\n\nWhen using synchronous commands, the user is responsible for freeing the memory of\nthe Command object by calling `c.free()`. The `c.cmd()` method just returns a string\nrepresentation of the command (`GET hello` in this case).\n\n#### Looping and delayed commands\nWe often want to run commands on regular invervals. Redox provides the `commandLoop`\nmethod to accomplish this. It is easier to use and more efficient than running individual\ncommands in a loop, because it only creates a single Command object.\n`commandLoop` takes a command vector, a callback, and an interval (in seconds)\nto repeat the command. It then runs the command on the given interval until the user\ncalls `c.free()`.\n\n```c++\nCommand\u003cstring\u003e\u0026 cmd = rdx.commandLoop\u003cstring\u003e({\"GET\", \"hello\"}, [](Command\u003cstring\u003e\u0026 c) {\n  if(c.ok()) cout \u003c\u003c c.cmd() \u003c\u003c \": \" \u003c\u003c c.reply() \u003c\u003c endl;\n}, 0.1);\n\nthis_thread::sleep_for(chrono::seconds(1));\ncmd.free();\nrdx.disconnect();\n```\n\nFinally, `commandDelayed` runs a command after a specified delay (in seconds). It does\nnot return a command object, because the memory is automatically freed after the callback\nis invoked.\n\n```c++\nrdx.commandDelayed\u003cstring\u003e({\"GET\", \"hello\"}, [](Command\u003cstring\u003e\u0026 c) {\n  if(c.ok()) cout \u003c\u003c c.cmd() \u003c\u003c \": \" \u003c\u003c c.reply() \u003c\u003c endl;\n}, 1);\nthis_thread::sleep_for(chrono::seconds(2));\n```\n\n#### Convenience methods\nThe four methods `command`, `commandSync`, `commandLoop`, and `commandDelayed` form\nthe core of Redox's functionality. There are convenience methods provided that are\nsimple wrappers over the core methods. Some examples of those are `.get()`, `.set()`,\n`.del()`, and `.publish()`. These methods are nice because they return simple values,\nand there are no Command objects or template parameters. However, they make strong\nassumptions about how to deal with errors (ignore or throw exceptions), and since\ntheir implementations are a few lines of code it is often easier to create custom\nconvenience methods for your application.\n\n#### Publisher / Subscriber\nRedox provides an API for the pub/sub functionality of Redis. Publishing is done just like\nany other command using a Redox instance. There is a separate Subscriber class that\nreceives messages and provides subscribe/unsubscribe and psubscribe/punsubscribe methods.\n\n```c++\nRedox rdx; Subscriber sub;\nif(!rdx.connect() || !sub.connect()) return 1;\n\nsub.subscribe(\"hello\", [](const string\u0026 topic, const string\u0026 msg) {\n  cout \u003c\u003c topic \u003c\u003c \": \" \u003c\u003c msg \u003c\u003c endl;\n});\n\nfor(int i = 0; i \u003c 10; i++) {\n  rdx.publish(\"hello\", \"this is a pubsub message\");\n  this_thread::sleep_for(chrono::milliseconds(500));\n}\n\nsub.disconnect(); rdx.disconnect();\n```\n\n#### strToVec and vecToStr\nRedox provides helper methods to convert between a string command and\na vector of strings as needed by its API. `rdx.strToVec(\"GET foo\")`\nwill return an `std::vector\u003cstd::string\u003e` containing `GET` and `foo`\nas entries. `rdx.vecToStr({\"GET\", \"foo\"})` will return the string `GET foo`.\n\n#### No-Wait Mode\nRedox provides a no-wait mode, which tells the event loop not to sleep\nin between processing events. It means that the event thread will run\nat 100% CPU, but it can greatly improve performance when critical. It is\ndisabled by default and can be enabled with `rdx.noWait(true);`.\n\n## Reply types\nThese the available template parameters in redox and the Redis\n[return types](http://redis.io/topics/protocol) they can hold.\nIf a given command returns an incompatible type you will get\na `WRONG_TYPE` or `NIL_REPLY` status.\n\n * `\u003credisReply*\u003e`: All reply types, returns the hiredis struct directly\n * `\u003cchar*\u003e`: Simple Strings, Bulk Strings\n * `\u003cstd::string\u003e`: Simple Strings, Bulk Strings\n * `\u003clong long int\u003e`: Integers\n * `\u003cint\u003e`: Integers (careful about overflow, `long long int` recommended)\n * `\u003cstd::nullptr_t\u003e`: Null Bulk Strings, any other receiving a nil reply will get a NIL_REPLY status\n * `\u003cstd::vector\u003cstd::string\u003e\u003e`: Arrays of Simple Strings or Bulk Strings (in received order)\n * `\u003cstd::set\u003cstd::string\u003e\u003e`: Arrays of Simple Strings or Bulk Strings (in sorted order)\n * `\u003cstd::unordered_set\u003cstd::string\u003e\u003e`: Arrays of Simple Strings or Bulk Strings (in no order)\n\n## Installation\nInstructions provided are for Ubuntu, but all components are platform-independent.\n\n#### Build from source\nGet the build environment and dependencies:\n\n    sudo apt-get install git cmake build-essential\n    sudo apt-get install libhiredis-dev libev-dev\n\nBuild the library:\n\n    mkdir build \u0026\u0026 cd build\n    cmake ..\n    make\n\nInstall into system directories (optional):\n\n    sudo make install\n\n#### Build examples and test suite\nEnable examples using ccmake or the following:\n\n    cmake -Dexamples=ON ..\n    make examples\n\nTo run the test suite, first make sure you have\n[gtest](https://code.google.com/p/googletest/) set up,\nthen:\n\n    cmake -Dtests=ON ..\n    make test_redox\n    ./test_redox\n\n#### Build documentation\nRedox documentation is generated using [doxygen](http://doxygen.org).\n\n    cd docs\n    doxygen\n\nThe documentation can then be viewed in a browser at `docs/html/index.html`.\n\n#### Build RPM and DEB packages\nBasic support to build RPMs and DEBs is in the build system. To build them, issue\nthe following commands:\n\n    mkdir release \u0026\u0026 cd release\n    cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo ..\n    make package\n\nNOTE: To build RPM packages, you will need rpmbuild.\n\n## Contributing\nRedox is in its early stages and I am looking for feedback and contributors to make\nit easier, faster, and more robust. Open issues on GitHub or message me directly.\n\nRedox is not currently recommended for production use. It has no support yet for sentinels\nor clusters. Feel free to provide them!\n","funding_links":[],"categories":["TODO scan for Android support in followings","C++","Redis Client","Libraries","\u003ca name=\"C%2B%2B\"\u003e\u003c/a\u003eC++"],"sub_categories":["C++","Database"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhmartiro%2Fredox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhmartiro%2Fredox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhmartiro%2Fredox/lists"}