Commit fb65a72153bca297b152595a415959dfe0f5e1f4
1 parent
c21560d9
Rename redisx->redox, refactor
Move as much as possible into the .cpp file, and clean things up.
Showing
6 changed files
with
95 additions
and
81 deletions
CMakeLists.txt
| 1 | 1 | cmake_minimum_required(VERSION 2.8.4) |
| 2 | -project(redisx) | |
| 2 | +project(redox) | |
| 3 | 3 | |
| 4 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -O3") |
| 5 | 5 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -g -fno-omit-frame-pointer") |
| ... | ... | @@ -12,7 +12,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fPIC -Wall -O3") |
| 12 | 12 | set(SRC_DIR ${CMAKE_SOURCE_DIR}/src) |
| 13 | 13 | |
| 14 | 14 | set(SRC_CORE |
| 15 | - ${SRC_DIR}/redisx.cpp | |
| 15 | + ${SRC_DIR}/redox.cpp | |
| 16 | 16 | ) |
| 17 | 17 | |
| 18 | 18 | set(SRC_ALL ${SRC_CORE}) | ... | ... |
examples/simple_loop.cpp
| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | */ |
| 4 | 4 | |
| 5 | 5 | #include <iostream> |
| 6 | -#include "../src/redisx.hpp" | |
| 6 | +#include "../src/redox.hpp" | |
| 7 | 7 | |
| 8 | 8 | using namespace std; |
| 9 | -using namespace redisx; | |
| 9 | +using namespace redox; | |
| 10 | 10 | |
| 11 | 11 | double time_s() { |
| 12 | 12 | unsigned long ms = chrono::system_clock::now().time_since_epoch() / chrono::microseconds(1); |
| ... | ... | @@ -15,7 +15,7 @@ double time_s() { |
| 15 | 15 | |
| 16 | 16 | int main(int argc, char* argv[]) { |
| 17 | 17 | |
| 18 | - Redis rdx = {"localhost", 6379}; | |
| 18 | + Redox rdx = {"localhost", 6379}; | |
| 19 | 19 | rdx.run(); |
| 20 | 20 | // |
| 21 | 21 | // Command<int>* del_cmd = rdx.command_blocking<int>("DEL simple_loop:count"); | ... | ... |
examples/simple_sync_loop.cpp
| ... | ... | @@ -3,10 +3,10 @@ |
| 3 | 3 | */ |
| 4 | 4 | |
| 5 | 5 | #include <iostream> |
| 6 | -#include "../src/redisx.hpp" | |
| 6 | +#include "../src/redox.hpp" | |
| 7 | 7 | |
| 8 | 8 | using namespace std; |
| 9 | -using namespace redisx; | |
| 9 | +using namespace redox; | |
| 10 | 10 | |
| 11 | 11 | double time_s() { |
| 12 | 12 | unsigned long ms = chrono::system_clock::now().time_since_epoch() / chrono::microseconds(1); |
| ... | ... | @@ -15,7 +15,7 @@ double time_s() { |
| 15 | 15 | |
| 16 | 16 | int main(int argc, char* argv[]) { |
| 17 | 17 | |
| 18 | - Redis rdx = {"localhost", 6379}; | |
| 18 | + Redox rdx = {"localhost", 6379}; | |
| 19 | 19 | rdx.run(); |
| 20 | 20 | |
| 21 | 21 | if(rdx.command_blocking("DEL simple_loop:count")) cout << "Deleted simple_loop:count" << endl; | ... | ... |
src/command.hpp
| ... | ... | @@ -12,7 +12,7 @@ |
| 12 | 12 | #include <hiredis/adapters/libev.h> |
| 13 | 13 | #include <hiredis/async.h> |
| 14 | 14 | |
| 15 | -namespace redisx { | |
| 15 | +namespace redox { | |
| 16 | 16 | |
| 17 | 17 | static const int REDISX_UNINIT = -1; |
| 18 | 18 | static const int REDISX_OK = 0; |
| ... | ... | @@ -25,7 +25,7 @@ static const int REDISX_TIMEOUT = 5; |
| 25 | 25 | template<class ReplyT> |
| 26 | 26 | class Command { |
| 27 | 27 | |
| 28 | -friend class Redis; | |
| 28 | +friend class Redox; | |
| 29 | 29 | |
| 30 | 30 | public: |
| 31 | 31 | Command( | ... | ... |
src/redisx.cpp renamed to src/redox.cpp
| 1 | 1 | /** |
| 2 | -* Redis C++11 wrapper. | |
| 2 | +* Redox C++11 wrapper. | |
| 3 | 3 | */ |
| 4 | 4 | |
| 5 | 5 | #include <signal.h> |
| 6 | 6 | #include <string.h> |
| 7 | -//#include <event2/thread.h> | |
| 8 | -#include "redisx.hpp" | |
| 7 | +#include "redox.hpp" | |
| 9 | 8 | |
| 10 | 9 | using namespace std; |
| 11 | 10 | |
| 12 | -namespace redisx { | |
| 11 | +namespace redox { | |
| 13 | 12 | |
| 14 | 13 | // Global mutex to manage waiting for connected state |
| 15 | 14 | // TODO get rid of this as the only global variable? |
| 16 | 15 | mutex connected_lock; |
| 17 | 16 | |
| 18 | -/** | |
| 19 | -* Dummy function given to hiredis to use for freeing reply | |
| 20 | -* objects, so the memory can be managed here instead. | |
| 21 | -*/ | |
| 22 | -void dummy_free_reply(void *reply) {} | |
| 23 | - | |
| 24 | -void connected(const redisAsyncContext *c, int status) { | |
| 17 | +void Redox::connected(const redisAsyncContext *c, int status) { | |
| 25 | 18 | if (status != REDIS_OK) { |
| 26 | 19 | cerr << "[ERROR] Connecting to Redis: " << c->errstr << endl; |
| 27 | 20 | return; |
| 28 | 21 | } |
| 29 | 22 | |
| 30 | - c->c.reader->fn->freeObject = dummy_free_reply; | |
| 23 | + // Disable hiredis automatically freeing reply objects | |
| 24 | + c->c.reader->fn->freeObject = [](void* reply) {}; | |
| 25 | + | |
| 31 | 26 | cout << "Connected to Redis." << endl; |
| 32 | 27 | connected_lock.unlock(); |
| 33 | 28 | } |
| 34 | 29 | |
| 35 | -void disconnected(const redisAsyncContext *c, int status) { | |
| 30 | +void Redox::disconnected(const redisAsyncContext *c, int status) { | |
| 36 | 31 | if (status != REDIS_OK) { |
| 37 | 32 | cerr << "[ERROR] Disconnecting from Redis: " << c->errstr << endl; |
| 38 | 33 | return; |
| 39 | 34 | } |
| 35 | + | |
| 36 | + // Re-enable hiredis automatically freeing reply objects | |
| 40 | 37 | c->c.reader->fn->freeObject = freeReplyObject; |
| 38 | + | |
| 41 | 39 | cout << "Disconnected from Redis." << endl; |
| 42 | 40 | connected_lock.lock(); |
| 43 | 41 | } |
| 44 | 42 | |
| 45 | -Redis::Redis(const string& host, const int port) | |
| 43 | +Redox::Redox(const string& host, const int port) | |
| 46 | 44 | : host(host), port(port), cmd_count(0), to_exit(false) { |
| 47 | 45 | |
| 48 | 46 | lock_guard<mutex> lg(queue_guard); |
| ... | ... | @@ -57,18 +55,18 @@ Redis::Redis(const string& host, const int port) |
| 57 | 55 | } |
| 58 | 56 | |
| 59 | 57 | redisLibevAttach(EV_DEFAULT_ c); |
| 60 | - redisAsyncSetConnectCallback(c, connected); | |
| 61 | - redisAsyncSetDisconnectCallback(c, disconnected); | |
| 58 | + redisAsyncSetConnectCallback(c, Redox::connected); | |
| 59 | + redisAsyncSetDisconnectCallback(c, Redox::disconnected); | |
| 62 | 60 | } |
| 63 | 61 | |
| 64 | -Redis::~Redis() { | |
| 62 | +Redox::~Redox() { | |
| 65 | 63 | redisAsyncDisconnect(c); |
| 66 | 64 | stop(); |
| 67 | 65 | } |
| 68 | 66 | |
| 69 | -void Redis::run_blocking() { | |
| 67 | +void Redox::run_blocking() { | |
| 70 | 68 | |
| 71 | - // Events to connect to Redis | |
| 69 | + // Events to connect to Redox | |
| 72 | 70 | ev_run(EV_DEFAULT_ EVRUN_NOWAIT); |
| 73 | 71 | lock_guard<mutex> lg(connected_lock); |
| 74 | 72 | |
| ... | ... | @@ -85,29 +83,57 @@ void Redis::run_blocking() { |
| 85 | 83 | exit_waiter.notify_one(); |
| 86 | 84 | } |
| 87 | 85 | |
| 88 | -void Redis::run() { | |
| 86 | +void Redox::run() { | |
| 89 | 87 | |
| 90 | 88 | event_loop_thread = thread([this] { run_blocking(); }); |
| 91 | 89 | event_loop_thread.detach(); |
| 92 | 90 | } |
| 93 | 91 | |
| 94 | -void Redis::stop() { | |
| 92 | +void Redox::stop() { | |
| 95 | 93 | to_exit = true; |
| 96 | 94 | } |
| 97 | 95 | |
| 98 | -void Redis::block() { | |
| 96 | +void Redox::block() { | |
| 99 | 97 | unique_lock<mutex> ul(exit_waiter_lock); |
| 100 | 98 | exit_waiter.wait(ul, [this]() { return to_exit.load(); }); |
| 101 | 99 | } |
| 102 | 100 | |
| 101 | +template<class ReplyT> | |
| 102 | +void invoke_callback( | |
| 103 | + Command<ReplyT>* cmd_obj, | |
| 104 | + redisReply* reply | |
| 105 | +); | |
| 106 | + | |
| 107 | +template<class ReplyT> | |
| 108 | +void Redox::command_callback(redisAsyncContext *c, void *r, void *privdata) { | |
| 109 | + | |
| 110 | + auto *cmd_obj = (Command<ReplyT> *) privdata; | |
| 111 | + cmd_obj->reply_obj = (redisReply *) r; | |
| 112 | + | |
| 113 | + if (cmd_obj->reply_obj->type == REDIS_REPLY_ERROR) { | |
| 114 | + std::cerr << "[ERROR redisx.hpp:121] " << cmd_obj->cmd << ": " << cmd_obj->reply_obj->str << std::endl; | |
| 115 | + cmd_obj->invoke_error(REDISX_ERROR_REPLY); | |
| 116 | + | |
| 117 | + } else if(cmd_obj->reply_obj->type == REDIS_REPLY_NIL) { | |
| 118 | + std::cerr << "[WARNING] " << cmd_obj->cmd << ": Nil reply." << std::endl; | |
| 119 | + cmd_obj->invoke_error(REDISX_NIL_REPLY); | |
| 120 | + | |
| 121 | + } else { | |
| 122 | + invoke_callback<ReplyT>(cmd_obj, cmd_obj->reply_obj); | |
| 123 | + } | |
| 124 | + | |
| 125 | + // Free the reply object unless told not to | |
| 126 | + if(cmd_obj->free_memory) cmd_obj->free_reply_object(); | |
| 127 | +} | |
| 128 | + | |
| 103 | 129 | /** |
| 104 | -* Submit an asynchronous command to the Redis server. Return | |
| 130 | +* Submit an asynchronous command to the Redox server. Return | |
| 105 | 131 | * true if succeeded, false otherwise. |
| 106 | 132 | */ |
| 107 | 133 | template<class ReplyT> |
| 108 | 134 | bool submit_to_server(Command<ReplyT>* cmd_obj) { |
| 109 | 135 | cmd_obj->pending++; |
| 110 | - if (redisAsyncCommand(cmd_obj->c, command_callback<ReplyT>, (void*)cmd_obj, cmd_obj->cmd.c_str()) != REDIS_OK) { | |
| 136 | + if (redisAsyncCommand(cmd_obj->c, Redox::command_callback<ReplyT>, (void*)cmd_obj, cmd_obj->cmd.c_str()) != REDIS_OK) { | |
| 111 | 137 | cerr << "[ERROR] Could not send \"" << cmd_obj->cmd << "\": " << cmd_obj->c->errstr << endl; |
| 112 | 138 | cmd_obj->invoke_error(REDISX_SEND_ERROR); |
| 113 | 139 | return false; |
| ... | ... | @@ -129,7 +155,7 @@ void submit_command_callback(struct ev_loop* loop, ev_timer* timer, int revents) |
| 129 | 155 | } |
| 130 | 156 | |
| 131 | 157 | template<class ReplyT> |
| 132 | -bool Redis::process_queued_command(void* cmd_ptr) { | |
| 158 | +bool Redox::process_queued_command(void* cmd_ptr) { | |
| 133 | 159 | |
| 134 | 160 | auto& command_map = get_command_map<ReplyT>(); |
| 135 | 161 | |
| ... | ... | @@ -153,7 +179,7 @@ bool Redis::process_queued_command(void* cmd_ptr) { |
| 153 | 179 | return true; |
| 154 | 180 | } |
| 155 | 181 | |
| 156 | -void Redis::process_queued_commands() { | |
| 182 | +void Redox::process_queued_commands() { | |
| 157 | 183 | |
| 158 | 184 | lock_guard<mutex> lg(queue_guard); |
| 159 | 185 | |
| ... | ... | @@ -172,20 +198,24 @@ void Redis::process_queued_commands() { |
| 172 | 198 | } |
| 173 | 199 | } |
| 174 | 200 | |
| 175 | -long Redis::num_commands_processed() { | |
| 201 | +long Redox::num_commands_processed() { | |
| 176 | 202 | lock_guard<mutex> lg(queue_guard); |
| 177 | 203 | return cmd_count; |
| 178 | 204 | } |
| 179 | 205 | |
| 180 | 206 | // ---------------------------- |
| 181 | 207 | |
| 182 | -template<> unordered_map<void*, Command<redisReply*>*>& Redis::get_command_map() { return commands_redis_reply; } | |
| 208 | +template<> unordered_map<void*, Command<redisReply*>*>& | |
| 209 | +Redox::get_command_map() { return commands_redis_reply; } | |
| 210 | + | |
| 183 | 211 | template<> |
| 184 | 212 | void invoke_callback(Command<redisReply*>* cmd_obj, redisReply* reply) { |
| 185 | 213 | cmd_obj->invoke(reply); |
| 186 | 214 | } |
| 187 | 215 | |
| 188 | -template<> unordered_map<void*, Command<string>*>& Redis::get_command_map() { return commands_string_r; } | |
| 216 | +template<> unordered_map<void*, Command<string>*>& | |
| 217 | +Redox::get_command_map() { return commands_string_r; } | |
| 218 | + | |
| 189 | 219 | template<> |
| 190 | 220 | void invoke_callback(Command<string>* cmd_obj, redisReply* reply) { |
| 191 | 221 | if(reply->type != REDIS_REPLY_STRING && reply->type != REDIS_REPLY_STATUS) { |
| ... | ... | @@ -198,7 +228,9 @@ void invoke_callback(Command<string>* cmd_obj, redisReply* reply) { |
| 198 | 228 | cmd_obj->invoke(s); |
| 199 | 229 | } |
| 200 | 230 | |
| 201 | -template<> unordered_map<void*, Command<char*>*>& Redis::get_command_map() { return commands_char_p; } | |
| 231 | +template<> unordered_map<void*, Command<char*>*>& | |
| 232 | +Redox::get_command_map() { return commands_char_p; } | |
| 233 | + | |
| 202 | 234 | template<> |
| 203 | 235 | void invoke_callback(Command<char*>* cmd_obj, redisReply* reply) { |
| 204 | 236 | if(reply->type != REDIS_REPLY_STRING && reply->type != REDIS_REPLY_STATUS) { |
| ... | ... | @@ -209,7 +241,9 @@ void invoke_callback(Command<char*>* cmd_obj, redisReply* reply) { |
| 209 | 241 | cmd_obj->invoke(reply->str); |
| 210 | 242 | } |
| 211 | 243 | |
| 212 | -template<> unordered_map<void*, Command<int>*>& Redis::get_command_map() { return commands_int; } | |
| 244 | +template<> unordered_map<void*, Command<int>*>& | |
| 245 | +Redox::get_command_map() { return commands_int; } | |
| 246 | + | |
| 213 | 247 | template<> |
| 214 | 248 | void invoke_callback(Command<int>* cmd_obj, redisReply* reply) { |
| 215 | 249 | if(reply->type != REDIS_REPLY_INTEGER) { |
| ... | ... | @@ -220,7 +254,9 @@ void invoke_callback(Command<int>* cmd_obj, redisReply* reply) { |
| 220 | 254 | cmd_obj->invoke((int)reply->integer); |
| 221 | 255 | } |
| 222 | 256 | |
| 223 | -template<> unordered_map<void*, Command<long long int>*>& Redis::get_command_map() { return commands_long_long_int; } | |
| 257 | +template<> unordered_map<void*, Command<long long int>*>& | |
| 258 | +Redox::get_command_map() { return commands_long_long_int; } | |
| 259 | + | |
| 224 | 260 | template<> |
| 225 | 261 | void invoke_callback(Command<long long int>* cmd_obj, redisReply* reply) { |
| 226 | 262 | if(reply->type != REDIS_REPLY_INTEGER) { |
| ... | ... | @@ -235,11 +271,11 @@ void invoke_callback(Command<long long int>* cmd_obj, redisReply* reply) { |
| 235 | 271 | // Helpers |
| 236 | 272 | // ---------------------------- |
| 237 | 273 | |
| 238 | -void Redis::command(const string& cmd) { | |
| 274 | +void Redox::command(const string& cmd) { | |
| 239 | 275 | command<redisReply*>(cmd, NULL); |
| 240 | 276 | } |
| 241 | 277 | |
| 242 | -bool Redis::command_blocking(const string& cmd) { | |
| 278 | +bool Redox::command_blocking(const string& cmd) { | |
| 243 | 279 | Command<redisReply*>* c = command_blocking<redisReply*>(cmd); |
| 244 | 280 | bool succeeded = (c->status() == REDISX_OK); |
| 245 | 281 | c->free(); | ... | ... |
src/redisx.hpp renamed to src/redox.hpp
| 1 | 1 | /** |
| 2 | -* Redis C++11 wrapper. | |
| 2 | +* Redox C++11 wrapper. | |
| 3 | 3 | */ |
| 4 | 4 | |
| 5 | 5 | #pragma once |
| ... | ... | @@ -22,14 +22,14 @@ |
| 22 | 22 | |
| 23 | 23 | #include "command.hpp" |
| 24 | 24 | |
| 25 | -namespace redisx { | |
| 25 | +namespace redox { | |
| 26 | 26 | |
| 27 | -class Redis { | |
| 27 | +class Redox { | |
| 28 | 28 | |
| 29 | 29 | public: |
| 30 | 30 | |
| 31 | - Redis(const std::string& host, const int port); | |
| 32 | - ~Redis(); | |
| 31 | + Redox(const std::string& host, const int port); | |
| 32 | + ~Redox(); | |
| 33 | 33 | |
| 34 | 34 | void run(); |
| 35 | 35 | void run_blocking(); |
| ... | ... | @@ -57,13 +57,19 @@ public: |
| 57 | 57 | |
| 58 | 58 | long num_commands_processed(); |
| 59 | 59 | |
| 60 | + template<class ReplyT> | |
| 61 | + static void command_callback(redisAsyncContext *c, void *r, void *privdata); | |
| 62 | + | |
| 63 | + static void connected(const redisAsyncContext *c, int status); | |
| 64 | + static void disconnected(const redisAsyncContext *c, int status); | |
| 65 | + | |
| 60 | 66 | // void publish(std::string channel, std::string msg); |
| 61 | 67 | // void subscribe(std::string channel, std::function<void(std::string channel, std::string msg)> callback); |
| 62 | 68 | // void unsubscribe(std::string channel); |
| 63 | 69 | |
| 64 | 70 | private: |
| 65 | 71 | |
| 66 | - // Redis server | |
| 72 | + // Redox server | |
| 67 | 73 | std::string host; |
| 68 | 74 | int port; |
| 69 | 75 | |
| ... | ... | @@ -98,35 +104,7 @@ private: |
| 98 | 104 | // --------------------------- |
| 99 | 105 | |
| 100 | 106 | template<class ReplyT> |
| 101 | -void invoke_callback( | |
| 102 | - Command<ReplyT>* cmd_obj, | |
| 103 | - redisReply* reply | |
| 104 | -); | |
| 105 | - | |
| 106 | -template<class ReplyT> | |
| 107 | -void command_callback(redisAsyncContext *c, void *r, void *privdata) { | |
| 108 | - | |
| 109 | - auto *cmd_obj = (Command<ReplyT> *) privdata; | |
| 110 | - cmd_obj->reply_obj = (redisReply *) r; | |
| 111 | - | |
| 112 | - if (cmd_obj->reply_obj->type == REDIS_REPLY_ERROR) { | |
| 113 | - std::cerr << "[ERROR redisx.hpp:121] " << cmd_obj->cmd << ": " << cmd_obj->reply_obj->str << std::endl; | |
| 114 | - cmd_obj->invoke_error(REDISX_ERROR_REPLY); | |
| 115 | - | |
| 116 | - } else if(cmd_obj->reply_obj->type == REDIS_REPLY_NIL) { | |
| 117 | - std::cerr << "[WARNING] " << cmd_obj->cmd << ": Nil reply." << std::endl; | |
| 118 | - cmd_obj->invoke_error(REDISX_NIL_REPLY); | |
| 119 | - | |
| 120 | - } else { | |
| 121 | - invoke_callback<ReplyT>(cmd_obj, cmd_obj->reply_obj); | |
| 122 | - } | |
| 123 | - | |
| 124 | - // Free the reply object unless told not to | |
| 125 | - if(cmd_obj->free_memory) cmd_obj->free_reply_object(); | |
| 126 | -} | |
| 127 | - | |
| 128 | -template<class ReplyT> | |
| 129 | -Command<ReplyT>* Redis::command( | |
| 107 | +Command<ReplyT>* Redox::command( | |
| 130 | 108 | const std::string& cmd, |
| 131 | 109 | const std::function<void(const std::string&, const ReplyT&)>& callback, |
| 132 | 110 | const std::function<void(const std::string&, int status)>& error_callback, |
| ... | ... | @@ -142,7 +120,7 @@ Command<ReplyT>* Redis::command( |
| 142 | 120 | } |
| 143 | 121 | |
| 144 | 122 | template<class ReplyT> |
| 145 | -bool Redis::cancel(Command<ReplyT>* cmd_obj) { | |
| 123 | +bool Redox::cancel(Command<ReplyT>* cmd_obj) { | |
| 146 | 124 | |
| 147 | 125 | if(cmd_obj == NULL) { |
| 148 | 126 | std::cerr << "[ERROR] Canceling null command." << std::endl; |
| ... | ... | @@ -161,7 +139,7 @@ bool Redis::cancel(Command<ReplyT>* cmd_obj) { |
| 161 | 139 | } |
| 162 | 140 | |
| 163 | 141 | template<class ReplyT> |
| 164 | -Command<ReplyT>* Redis::command_blocking(const std::string& cmd) { | |
| 142 | +Command<ReplyT>* Redox::command_blocking(const std::string& cmd) { | |
| 165 | 143 | |
| 166 | 144 | ReplyT val; |
| 167 | 145 | std::atomic_int status(REDISX_UNINIT); | ... | ... |