Commit b4f96a55f52e5a064ad3722cd58754ca25388763
1 parent
38dffef5
Improve client API, split off Subscriber class
Refactor state management code to use three methods .connect(), .disconnect(), and .wait(). Start conforming to uniform coding style already applied to Command class. Split off subscribe functionality into its own class Subscriber. This is good because it was introducing unnecessary state and complexity into the main client. Now, Redox handles publishing like any other command and the Subscriber receives messages.
Showing
18 changed files
with
618 additions
and
612 deletions
CMakeLists.txt
| @@ -24,6 +24,7 @@ set(SRC_DIR ${CMAKE_SOURCE_DIR}/src) | @@ -24,6 +24,7 @@ set(SRC_DIR ${CMAKE_SOURCE_DIR}/src) | ||
| 24 | set(SRC_CORE | 24 | set(SRC_CORE |
| 25 | ${SRC_DIR}/redox.cpp | 25 | ${SRC_DIR}/redox.cpp |
| 26 | ${SRC_DIR}/command.cpp | 26 | ${SRC_DIR}/command.cpp |
| 27 | + ${SRC_DIR}/subscriber.cpp | ||
| 27 | ) | 28 | ) |
| 28 | 29 | ||
| 29 | set(SRC_LOGGER ${SRC_DIR}/utils/logger.cpp) | 30 | set(SRC_LOGGER ${SRC_DIR}/utils/logger.cpp) |
examples/basic.cpp
| @@ -13,7 +13,7 @@ int main(int argc, char* argv[]) { | @@ -13,7 +13,7 @@ int main(int argc, char* argv[]) { | ||
| 13 | 13 | ||
| 14 | Redox rdx = {"localhost", 6379, nullptr, cout, redox::log::Info}; // Initialize Redox | 14 | Redox rdx = {"localhost", 6379, nullptr, cout, redox::log::Info}; // Initialize Redox |
| 15 | 15 | ||
| 16 | - if(!rdx.start()) return 1; // Start the event loop | 16 | + if(!rdx.connect()) return 1; // Start the event loop |
| 17 | 17 | ||
| 18 | rdx.del("occupation"); | 18 | rdx.del("occupation"); |
| 19 | 19 | ||
| @@ -22,6 +22,5 @@ int main(int argc, char* argv[]) { | @@ -22,6 +22,5 @@ int main(int argc, char* argv[]) { | ||
| 22 | 22 | ||
| 23 | cout << "key = \"occupation\", value = \"" << rdx.get("occupation") << "\"" << endl; | 23 | cout << "key = \"occupation\", value = \"" << rdx.get("occupation") << "\"" << endl; |
| 24 | 24 | ||
| 25 | - rdx.stop(); // Shut down the event loop | ||
| 26 | return 0; | 25 | return 0; |
| 27 | } | 26 | } |
examples/basic_threaded.cpp
| @@ -15,7 +15,7 @@ redox::Redox rdx = {"localhost", 6379}; | @@ -15,7 +15,7 @@ redox::Redox rdx = {"localhost", 6379}; | ||
| 15 | 15 | ||
| 16 | int main(int argc, char* argv[]) { | 16 | int main(int argc, char* argv[]) { |
| 17 | 17 | ||
| 18 | - if(!rdx.start()) return 1; | 18 | + if(!rdx.connect()) return 1; |
| 19 | 19 | ||
| 20 | thread setter([]() { | 20 | thread setter([]() { |
| 21 | for(int i = 0; i < 5000; i++) { | 21 | for(int i = 0; i < 5000; i++) { |
| @@ -41,7 +41,5 @@ int main(int argc, char* argv[]) { | @@ -41,7 +41,5 @@ int main(int argc, char* argv[]) { | ||
| 41 | setter.join(); | 41 | setter.join(); |
| 42 | getter.join(); | 42 | getter.join(); |
| 43 | 43 | ||
| 44 | - rdx.stop(); | ||
| 45 | - | ||
| 46 | return 0; | 44 | return 0; |
| 47 | }; | 45 | }; |
examples/binary_data.cpp
| @@ -23,18 +23,18 @@ std::string random_string(size_t length) { | @@ -23,18 +23,18 @@ std::string random_string(size_t length) { | ||
| 23 | int main(int argc, char* argv[]) { | 23 | int main(int argc, char* argv[]) { |
| 24 | 24 | ||
| 25 | redox::Redox rdx = {"localhost", 6379}; // Initialize Redox | 25 | redox::Redox rdx = {"localhost", 6379}; // Initialize Redox |
| 26 | - if(!rdx.start()) return 1; // Start the event loop | 26 | + if(!rdx.connect()) return 1; // Start the event loop |
| 27 | 27 | ||
| 28 | rdx.del("binary"); | 28 | rdx.del("binary"); |
| 29 | 29 | ||
| 30 | string binary_data = random_string(10000); | 30 | string binary_data = random_string(10000); |
| 31 | 31 | ||
| 32 | - auto& c = rdx.command_blocking<string>("SET binary \"" + binary_data + "\""); | 32 | + auto& c = rdx.commandSync<string>("SET binary \"" + binary_data + "\""); |
| 33 | if(c.ok()) cout << "Reply: " << c.reply() << endl; | 33 | if(c.ok()) cout << "Reply: " << c.reply() << endl; |
| 34 | else cerr << "Failed to set key! Status: " << c.status() << endl; | 34 | else cerr << "Failed to set key! Status: " << c.status() << endl; |
| 35 | c.free(); | 35 | c.free(); |
| 36 | 36 | ||
| 37 | - auto& c2 = rdx.command_blocking<string>("GET binary"); | 37 | + auto& c2 = rdx.commandSync<string>("GET binary"); |
| 38 | if(c2.ok()) { | 38 | if(c2.ok()) { |
| 39 | if(c2.reply() == binary_data) cout << "Binary data matches!" << endl; | 39 | if(c2.reply() == binary_data) cout << "Binary data matches!" << endl; |
| 40 | else cerr << "Binary data differs!" << endl; | 40 | else cerr << "Binary data differs!" << endl; |
| @@ -42,6 +42,5 @@ int main(int argc, char* argv[]) { | @@ -42,6 +42,5 @@ int main(int argc, char* argv[]) { | ||
| 42 | else cerr << "Failed to get key! Status: " << c2.status() << endl; | 42 | else cerr << "Failed to get key! Status: " << c2.status() << endl; |
| 43 | c2.free(); | 43 | c2.free(); |
| 44 | 44 | ||
| 45 | - rdx.stop(); // Shut down the event loop | ||
| 46 | return 0; | 45 | return 0; |
| 47 | } | 46 | } |
examples/data_types.cpp
| @@ -15,11 +15,11 @@ using redox::Command; | @@ -15,11 +15,11 @@ using redox::Command; | ||
| 15 | int main(int argc, char* argv[]) { | 15 | int main(int argc, char* argv[]) { |
| 16 | 16 | ||
| 17 | redox::Redox rdx; // Initialize Redox (default host/port) | 17 | redox::Redox rdx; // Initialize Redox (default host/port) |
| 18 | - if(!rdx.start()) return 1; // Start the event loop | 18 | + if(!rdx.connect()) return 1; // Start the event loop |
| 19 | 19 | ||
| 20 | rdx.del("mylist"); | 20 | rdx.del("mylist"); |
| 21 | 21 | ||
| 22 | - rdx.command_blocking("LPUSH mylist 1 2 3 4 5 6 7 8 9 10"); | 22 | + rdx.commandSync("LPUSH mylist 1 2 3 4 5 6 7 8 9 10"); |
| 23 | 23 | ||
| 24 | rdx.command<vector<string>>("LRANGE mylist 0 4", | 24 | rdx.command<vector<string>>("LRANGE mylist 0 4", |
| 25 | [](Command<vector<string>>& c){ | 25 | [](Command<vector<string>>& c){ |
| @@ -46,10 +46,10 @@ int main(int argc, char* argv[]) { | @@ -46,10 +46,10 @@ int main(int argc, char* argv[]) { | ||
| 46 | for (const string& s : c.reply()) cout << s << " "; | 46 | for (const string& s : c.reply()) cout << s << " "; |
| 47 | cout << endl; | 47 | cout << endl; |
| 48 | } | 48 | } |
| 49 | - rdx.stop_signal(); | 49 | + rdx.disconnect(); |
| 50 | } | 50 | } |
| 51 | ); | 51 | ); |
| 52 | 52 | ||
| 53 | - rdx.block(); // Shut down the event loop | 53 | + rdx.wait(); |
| 54 | return 0; | 54 | return 0; |
| 55 | } | 55 | } |
examples/lpush_benchmark.cpp
| @@ -17,7 +17,7 @@ double time_s() { | @@ -17,7 +17,7 @@ double time_s() { | ||
| 17 | int main(int argc, char* argv[]) { | 17 | int main(int argc, char* argv[]) { |
| 18 | 18 | ||
| 19 | redox::Redox rdx; | 19 | redox::Redox rdx; |
| 20 | - if(!rdx.start()) return 1; | 20 | + if(!rdx.connect()) return 1; |
| 21 | 21 | ||
| 22 | rdx.del("test"); | 22 | rdx.del("test"); |
| 23 | 23 | ||
| @@ -43,15 +43,12 @@ int main(int argc, char* argv[]) { | @@ -43,15 +43,12 @@ int main(int argc, char* argv[]) { | ||
| 43 | cout << "Total time: " << t2 - t0 << "s" << endl; | 43 | cout << "Total time: " << t2 - t0 << "s" << endl; |
| 44 | cout << "Result: " << (double)len / (t2-t0) << " commands/s" << endl; | 44 | cout << "Result: " << (double)len / (t2-t0) << " commands/s" << endl; |
| 45 | 45 | ||
| 46 | - rdx.stop_signal(); | 46 | + rdx.disconnect(); |
| 47 | } | 47 | } |
| 48 | }); | 48 | }); |
| 49 | } | 49 | } |
| 50 | t1 = time_s(); | 50 | t1 = time_s(); |
| 51 | 51 | ||
| 52 | - rdx.block(); | ||
| 53 | - | ||
| 54 | - cout << "Commands processed: " << rdx.num_commands_processed() << endl; | ||
| 55 | - | 52 | + rdx.wait(); |
| 56 | return 0; | 53 | return 0; |
| 57 | }; | 54 | }; |
examples/multi-client.cpp
| @@ -13,7 +13,7 @@ int main(int argc, char* argv[]) { | @@ -13,7 +13,7 @@ int main(int argc, char* argv[]) { | ||
| 13 | 13 | ||
| 14 | redox::Redox rdx1, rdx2, rdx3; | 14 | redox::Redox rdx1, rdx2, rdx3; |
| 15 | 15 | ||
| 16 | - if(!rdx1.start() || !rdx2.start() || !rdx3.start()) return 1; | 16 | + if(!rdx1.connect() || !rdx2.connect() || !rdx3.connect()) return 1; |
| 17 | 17 | ||
| 18 | rdx1.del("occupation"); | 18 | rdx1.del("occupation"); |
| 19 | 19 | ||
| @@ -22,9 +22,5 @@ int main(int argc, char* argv[]) { | @@ -22,9 +22,5 @@ int main(int argc, char* argv[]) { | ||
| 22 | 22 | ||
| 23 | cout << "key = occupation, value = \"" << rdx3.get("occupation") << "\"" << endl; | 23 | cout << "key = occupation, value = \"" << rdx3.get("occupation") << "\"" << endl; |
| 24 | 24 | ||
| 25 | - rdx1.stop(); | ||
| 26 | - rdx2.stop(); | ||
| 27 | - rdx3.stop(); | ||
| 28 | - | ||
| 29 | return 0; | 25 | return 0; |
| 30 | } | 26 | } |
examples/pub_sub.cpp
| 1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
| 2 | #include <iostream> | 2 | #include <iostream> |
| 3 | #include "../src/redox.hpp" | 3 | #include "../src/redox.hpp" |
| 4 | +#include "../src/subscriber.hpp" | ||
| 4 | 5 | ||
| 5 | using namespace std; | 6 | using namespace std; |
| 6 | 7 | ||
| 7 | int main(int argc, char *argv[]) { | 8 | int main(int argc, char *argv[]) { |
| 8 | 9 | ||
| 9 | - redox::Redox rdx; // Initialize Redox (default host/port) | ||
| 10 | - if (!rdx.start()) return 1; // Start the event loop | 10 | + redox::Redox publisher; // Initialize Redox (default host/port) |
| 11 | + if (!publisher.connect()) return 1; // Start the event loop | ||
| 11 | 12 | ||
| 12 | - redox::Redox rdx_pub; | ||
| 13 | - if(!rdx_pub.start()) return 1; | 13 | + redox::Subscriber subscriber; |
| 14 | + if(!subscriber.connect()) return 1; | ||
| 14 | 15 | ||
| 15 | auto got_message = [](const string& topic, const string& msg) { | 16 | auto got_message = [](const string& topic, const string& msg) { |
| 16 | cout << topic << ": " << msg << endl; | 17 | cout << topic << ": " << msg << endl; |
| @@ -24,31 +25,30 @@ int main(int argc, char *argv[]) { | @@ -24,31 +25,30 @@ int main(int argc, char *argv[]) { | ||
| 24 | cout << "> Unsubscribed from " << topic << endl; | 25 | cout << "> Unsubscribed from " << topic << endl; |
| 25 | }; | 26 | }; |
| 26 | 27 | ||
| 27 | - rdx.psubscribe("news", got_message, subscribed, unsubscribed); | ||
| 28 | - rdx.subscribe("sports", got_message, subscribed, unsubscribed); | 28 | + subscriber.psubscribe("news", got_message, subscribed, unsubscribed); |
| 29 | + subscriber.subscribe("sports", got_message, subscribed, unsubscribed); | ||
| 29 | 30 | ||
| 30 | - this_thread::sleep_for(chrono::milliseconds(20)); | ||
| 31 | - for(auto s : rdx.subscribed_topics()) cout << "topic: " << s << endl; | 31 | + this_thread::sleep_for(chrono::milliseconds(10)); |
| 32 | 32 | ||
| 33 | - rdx_pub.publish("news", "hello!"); | ||
| 34 | - rdx_pub.publish("news", "whatup"); | ||
| 35 | - rdx_pub.publish("sports", "yo"); | 33 | + publisher.publish("news", "one"); |
| 34 | + publisher.publish("news", "two", [](const string& topic, const string& msg) { | ||
| 35 | + cout << "published to " << topic << ": " << msg << endl; | ||
| 36 | + }); | ||
| 37 | + publisher.publish("sports", "three"); | ||
| 36 | 38 | ||
| 37 | - this_thread::sleep_for(chrono::seconds(1)); | ||
| 38 | - rdx.unsubscribe("sports"); | ||
| 39 | - rdx_pub.publish("sports", "yo"); | ||
| 40 | - rdx_pub.publish("news", "whatup"); | 39 | + this_thread::sleep_for(chrono::milliseconds(10)); |
| 40 | + subscriber.unsubscribe("sports"); | ||
| 41 | + publisher.publish("sports", "\"UH OH\""); | ||
| 42 | + publisher.publish("news", "four"); | ||
| 41 | 43 | ||
| 42 | - this_thread::sleep_for(chrono::milliseconds(1)); | ||
| 43 | - rdx.punsubscribe("news"); | 44 | + this_thread::sleep_for(chrono::milliseconds(10)); |
| 45 | + subscriber.punsubscribe("news"); | ||
| 46 | + this_thread::sleep_for(chrono::milliseconds(10)); | ||
| 44 | 47 | ||
| 45 | - rdx_pub.publish("sports", "yo"); | ||
| 46 | - rdx_pub.publish("news", "whatup", [](const string& topic, const string& msg) { | ||
| 47 | - cout << "published to " << topic << ": " << msg << endl; | ||
| 48 | - }); | ||
| 49 | - rdx_pub.publish("news", "whatup"); | ||
| 50 | - rdx.block(); | ||
| 51 | - rdx_pub.block(); | 48 | + publisher.publish("sports", "\"UH OH\""); |
| 49 | + publisher.publish("news", "\"UH OH\""); | ||
| 50 | + | ||
| 51 | + this_thread::sleep_for(chrono::milliseconds(10)); | ||
| 52 | 52 | ||
| 53 | return 0; | 53 | return 0; |
| 54 | } | 54 | } |
examples/speed_test_async.cpp
| @@ -19,9 +19,9 @@ double time_s() { | @@ -19,9 +19,9 @@ double time_s() { | ||
| 19 | int main(int argc, char* argv[]) { | 19 | int main(int argc, char* argv[]) { |
| 20 | 20 | ||
| 21 | Redox rdx = {"/var/run/redis/redis.sock", nullptr}; | 21 | Redox rdx = {"/var/run/redis/redis.sock", nullptr}; |
| 22 | - if(!rdx.start()) return 1; | 22 | + if(!rdx.connect()) return 1; |
| 23 | 23 | ||
| 24 | - bool status = rdx.command_blocking("SET simple_loop:count 0"); | 24 | + bool status = rdx.commandSync("SET simple_loop:count 0"); |
| 25 | if(status) { | 25 | if(status) { |
| 26 | cout << "Reset the counter to zero." << endl; | 26 | cout << "Reset the counter to zero." << endl; |
| 27 | } else { | 27 | } else { |
| @@ -40,10 +40,10 @@ int main(int argc, char* argv[]) { | @@ -40,10 +40,10 @@ int main(int argc, char* argv[]) { | ||
| 40 | double t0 = time_s(); | 40 | double t0 = time_s(); |
| 41 | atomic_int count(0); | 41 | atomic_int count(0); |
| 42 | 42 | ||
| 43 | - Command<int>& cmd = rdx.command_looping<int>( | 43 | + Command<int>& cmd = rdx.commandLoop<int>( |
| 44 | cmd_str, | 44 | cmd_str, |
| 45 | [&count, &rdx](Command<int>& c) { | 45 | [&count, &rdx](Command<int>& c) { |
| 46 | - if(!c.ok()) { | 46 | + if (!c.ok()) { |
| 47 | cerr << "Bad reply: " << c.status() << endl; | 47 | cerr << "Bad reply: " << c.status() << endl; |
| 48 | } | 48 | } |
| 49 | count++; | 49 | count++; |
| @@ -65,6 +65,5 @@ int main(int argc, char* argv[]) { | @@ -65,6 +65,5 @@ int main(int argc, char* argv[]) { | ||
| 65 | 65 | ||
| 66 | cout << "Final value of counter: " << final_count << endl; | 66 | cout << "Final value of counter: " << final_count << endl; |
| 67 | 67 | ||
| 68 | - rdx.stop(); | ||
| 69 | return 0; | 68 | return 0; |
| 70 | } | 69 | } |
examples/speed_test_async_multi.cpp
| @@ -20,7 +20,7 @@ double time_s() { | @@ -20,7 +20,7 @@ double time_s() { | ||
| 20 | int main(int argc, char* argv[]) { | 20 | int main(int argc, char* argv[]) { |
| 21 | 21 | ||
| 22 | Redox rdx = {"localhost", 6379}; | 22 | Redox rdx = {"localhost", 6379}; |
| 23 | - if(!rdx.start()) return 1; | 23 | + if(!rdx.connect()) return 1; |
| 24 | 24 | ||
| 25 | if(rdx.set("simple_loop:count", "0")) { | 25 | if(rdx.set("simple_loop:count", "0")) { |
| 26 | cout << "Reset the counter to zero." << endl; | 26 | cout << "Reset the counter to zero." << endl; |
| @@ -43,15 +43,15 @@ int main(int argc, char* argv[]) { | @@ -43,15 +43,15 @@ int main(int argc, char* argv[]) { | ||
| 43 | 43 | ||
| 44 | vector<Command<int>*> commands; | 44 | vector<Command<int>*> commands; |
| 45 | for(int i = 0; i < parallel; i++) { | 45 | for(int i = 0; i < parallel; i++) { |
| 46 | - commands.push_back(&rdx.command_looping<int>( | ||
| 47 | - cmd_str, | 46 | + commands.push_back(&rdx.commandLoop<int>( |
| 47 | + cmd_str, | ||
| 48 | [&count, &rdx](Command<int>& c) { | 48 | [&count, &rdx](Command<int>& c) { |
| 49 | - if(!c.ok()) { | 49 | + if (!c.ok()) { |
| 50 | cerr << "Bad reply: " << c.status() << endl; | 50 | cerr << "Bad reply: " << c.status() << endl; |
| 51 | } | 51 | } |
| 52 | count++; | 52 | count++; |
| 53 | }, | 53 | }, |
| 54 | - dt | 54 | + dt |
| 55 | )); | 55 | )); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| @@ -65,8 +65,6 @@ int main(int argc, char* argv[]) { | @@ -65,8 +65,6 @@ int main(int argc, char* argv[]) { | ||
| 65 | // Get the final value of the counter | 65 | // Get the final value of the counter |
| 66 | long final_count = stol(rdx.get("simple_loop:count")); | 66 | long final_count = stol(rdx.get("simple_loop:count")); |
| 67 | 67 | ||
| 68 | - rdx.stop(); | ||
| 69 | - | ||
| 70 | cout << "Sent " << count << " commands in " << t_elapsed << "s, " | 68 | cout << "Sent " << count << " commands in " << t_elapsed << "s, " |
| 71 | << "that's " << actual_freq << " commands/s." << endl; | 69 | << "that's " << actual_freq << " commands/s." << endl; |
| 72 | 70 |
examples/speed_test_pubsub.cpp
| 1 | #include <iostream> | 1 | #include <iostream> |
| 2 | #include "../src/redox.hpp" | 2 | #include "../src/redox.hpp" |
| 3 | +#include "../src/subscriber.hpp" | ||
| 3 | 4 | ||
| 4 | using namespace std; | 5 | using namespace std; |
| 5 | using redox::Redox; | 6 | using redox::Redox; |
| 6 | using redox::Command; | 7 | using redox::Command; |
| 8 | +using redox::Subscriber; | ||
| 7 | 9 | ||
| 8 | double time_s() { | 10 | double time_s() { |
| 9 | unsigned long ms = chrono::system_clock::now().time_since_epoch() / chrono::microseconds(1); | 11 | unsigned long ms = chrono::system_clock::now().time_since_epoch() / chrono::microseconds(1); |
| @@ -13,10 +15,10 @@ double time_s() { | @@ -13,10 +15,10 @@ double time_s() { | ||
| 13 | int main(int argc, char *argv[]) { | 15 | int main(int argc, char *argv[]) { |
| 14 | 16 | ||
| 15 | Redox rdx_pub; | 17 | Redox rdx_pub; |
| 16 | - Redox rdx_sub; | 18 | + Subscriber rdx_sub; |
| 17 | 19 | ||
| 18 | - if(!rdx_pub.start()) return 1; | ||
| 19 | - if(!rdx_sub.start()) return 1; | 20 | + if(!rdx_pub.connect()) return 1; |
| 21 | + if(!rdx_sub.connect()) return 1; | ||
| 20 | 22 | ||
| 21 | atomic_int count(0); | 23 | atomic_int count(0); |
| 22 | auto got_message = [&count](const string& topic, const string& msg) { | 24 | auto got_message = [&count](const string& topic, const string& msg) { |
| @@ -41,12 +43,13 @@ int main(int argc, char *argv[]) { | @@ -41,12 +43,13 @@ int main(int argc, char *argv[]) { | ||
| 41 | rdx_pub.publish("speedtest", "hello"); | 43 | rdx_pub.publish("speedtest", "hello"); |
| 42 | t1 = time_s(); | 44 | t1 = time_s(); |
| 43 | } | 45 | } |
| 44 | - this_thread::sleep_for(chrono::milliseconds(1000)); | ||
| 45 | - rdx_pub.stop(); | ||
| 46 | - rdx_sub.stop(); | 46 | + |
| 47 | + this_thread::sleep_for(chrono::milliseconds(10)); | ||
| 47 | 48 | ||
| 48 | double t = t1 - t0; | 49 | double t = t1 - t0; |
| 49 | cout << "Total of messages sent in " << t << "s is " << count << endl; | 50 | cout << "Total of messages sent in " << t << "s is " << count << endl; |
| 50 | double msg_per_s = count / t; | 51 | double msg_per_s = count / t; |
| 51 | cout << "Messages per second: " << msg_per_s << endl; | 52 | cout << "Messages per second: " << msg_per_s << endl; |
| 53 | + | ||
| 54 | + return 0; | ||
| 52 | } | 55 | } |
examples/speed_test_sync.cpp
| @@ -18,9 +18,9 @@ double time_s() { | @@ -18,9 +18,9 @@ double time_s() { | ||
| 18 | int main(int argc, char* argv[]) { | 18 | int main(int argc, char* argv[]) { |
| 19 | 19 | ||
| 20 | Redox rdx = {"localhost", 6379}; | 20 | Redox rdx = {"localhost", 6379}; |
| 21 | - if(!rdx.start()) return 1; | 21 | + if(!rdx.connect()) return 1; |
| 22 | 22 | ||
| 23 | - if(rdx.command_blocking("SET simple_loop:count 0")) { | 23 | + if(rdx.commandSync("SET simple_loop:count 0")) { |
| 24 | cout << "Reset the counter to zero." << endl; | 24 | cout << "Reset the counter to zero." << endl; |
| 25 | } else { | 25 | } else { |
| 26 | cerr << "Failed to reset counter." << endl; | 26 | cerr << "Failed to reset counter." << endl; |
| @@ -37,7 +37,7 @@ int main(int argc, char* argv[]) { | @@ -37,7 +37,7 @@ int main(int argc, char* argv[]) { | ||
| 37 | int count = 0; | 37 | int count = 0; |
| 38 | 38 | ||
| 39 | while(time_s() < t_end) { | 39 | while(time_s() < t_end) { |
| 40 | - Command<int>& c = rdx.command_blocking<int>(cmd_str); | 40 | + Command<int>& c = rdx.commandSync<int>(cmd_str); |
| 41 | if(!c.ok()) cerr << "Bad reply, code: " << c.status() << endl; | 41 | if(!c.ok()) cerr << "Bad reply, code: " << c.status() << endl; |
| 42 | c.free(); | 42 | c.free(); |
| 43 | count++; | 43 | count++; |
| @@ -48,8 +48,6 @@ int main(int argc, char* argv[]) { | @@ -48,8 +48,6 @@ int main(int argc, char* argv[]) { | ||
| 48 | 48 | ||
| 49 | long final_count = stol(rdx.get("simple_loop:count")); | 49 | long final_count = stol(rdx.get("simple_loop:count")); |
| 50 | 50 | ||
| 51 | - rdx.stop(); | ||
| 52 | - | ||
| 53 | cout << "Sent " << count << " commands in " << t_elapsed << "s, " | 51 | cout << "Sent " << count << " commands in " << t_elapsed << "s, " |
| 54 | << "that's " << actual_freq << " commands/s." << endl; | 52 | << "that's " << actual_freq << " commands/s." << endl; |
| 55 | 53 |
src/command.hpp
| @@ -54,7 +54,7 @@ public: | @@ -54,7 +54,7 @@ public: | ||
| 54 | /** | 54 | /** |
| 55 | * This method returns once this command's callback has been invoked | 55 | * This method returns once this command's callback has been invoked |
| 56 | * (or would have been invoked if there is none) since the last call | 56 | * (or would have been invoked if there is none) since the last call |
| 57 | - * to block(). If it is the first call, then returns once the callback | 57 | + * to wait(). If it is the first call, then returns once the callback |
| 58 | * is invoked for the first time. | 58 | * is invoked for the first time. |
| 59 | */ | 59 | */ |
| 60 | void wait(); | 60 | void wait(); |
src/redox.cpp
| @@ -3,72 +3,72 @@ | @@ -3,72 +3,72 @@ | ||
| 3 | */ | 3 | */ |
| 4 | 4 | ||
| 5 | #include <signal.h> | 5 | #include <signal.h> |
| 6 | -#include "redox.hpp" | ||
| 7 | #include <string.h> | 6 | #include <string.h> |
| 7 | +#include "redox.hpp" | ||
| 8 | 8 | ||
| 9 | using namespace std; | 9 | using namespace std; |
| 10 | 10 | ||
| 11 | namespace redox { | 11 | namespace redox { |
| 12 | 12 | ||
| 13 | -void Redox::connected_callback(const redisAsyncContext *ctx, int status) { | 13 | +void Redox::connectedCallback(const redisAsyncContext* ctx, int status) { |
| 14 | 14 | ||
| 15 | Redox* rdx = (Redox*) ctx->data; | 15 | Redox* rdx = (Redox*) ctx->data; |
| 16 | 16 | ||
| 17 | if (status != REDIS_OK) { | 17 | if (status != REDIS_OK) { |
| 18 | - rdx->logger.fatal() << "Could not connect to Redis: " << ctx->errstr; | ||
| 19 | - rdx->connect_state = REDOX_CONNECT_ERROR; | 18 | + rdx->logger_.fatal() << "Could not connect to Redis: " << ctx->errstr; |
| 19 | + rdx->connect_state_ = CONNECT_ERROR; | ||
| 20 | 20 | ||
| 21 | } else { | 21 | } else { |
| 22 | // Disable hiredis automatically freeing reply objects | 22 | // Disable hiredis automatically freeing reply objects |
| 23 | ctx->c.reader->fn->freeObject = [](void *reply) {}; | 23 | ctx->c.reader->fn->freeObject = [](void *reply) {}; |
| 24 | - rdx->connect_state = REDOX_CONNECTED; | ||
| 25 | - rdx->logger.info() << "Connected to Redis."; | 24 | + rdx->connect_state_ = CONNECTED; |
| 25 | + rdx->logger_.info() << "Connected to Redis."; | ||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | - rdx->connect_waiter.notify_all(); | ||
| 29 | - if(rdx->user_connection_callback) rdx->user_connection_callback(rdx->connect_state); | 28 | + rdx->connect_waiter_.notify_all(); |
| 29 | + if(rdx->user_connection_callback_) rdx->user_connection_callback_(rdx->connect_state_); | ||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | -void Redox::disconnected_callback(const redisAsyncContext *ctx, int status) { | 32 | +void Redox::disconnectedCallback(const redisAsyncContext* ctx, int status) { |
| 33 | 33 | ||
| 34 | Redox* rdx = (Redox*) ctx->data; | 34 | Redox* rdx = (Redox*) ctx->data; |
| 35 | 35 | ||
| 36 | if (status != REDIS_OK) { | 36 | if (status != REDIS_OK) { |
| 37 | - rdx->logger.error() << "Could not disconnect from Redis: " << ctx->errstr; | ||
| 38 | - rdx->connect_state = REDOX_DISCONNECT_ERROR; | 37 | + rdx->logger_.error() << "Could not disconnect from Redis: " << ctx->errstr; |
| 38 | + rdx->connect_state_ = DISCONNECT_ERROR; | ||
| 39 | } else { | 39 | } else { |
| 40 | - rdx->logger.info() << "Disconnected from Redis as planned."; | ||
| 41 | - rdx->connect_state = REDOX_DISCONNECTED; | 40 | + rdx->logger_.info() << "Disconnected from Redis as planned."; |
| 41 | + rdx->connect_state_ = DISCONNECTED; | ||
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | - rdx->stop_signal(); | ||
| 45 | - rdx->connect_waiter.notify_all(); | ||
| 46 | - if(rdx->user_connection_callback) rdx->user_connection_callback(rdx->connect_state); | 44 | + rdx->disconnect(); |
| 45 | + rdx->connect_waiter_.notify_all(); | ||
| 46 | + if(rdx->user_connection_callback_) rdx->user_connection_callback_(rdx->connect_state_); | ||
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void Redox::init_ev() { | 49 | void Redox::init_ev() { |
| 50 | signal(SIGPIPE, SIG_IGN); | 50 | signal(SIGPIPE, SIG_IGN); |
| 51 | - evloop = ev_loop_new(EVFLAG_AUTO); | ||
| 52 | - ev_set_userdata(evloop, (void*)this); // Back-reference | 51 | + evloop_ = ev_loop_new(EVFLAG_AUTO); |
| 52 | + ev_set_userdata(evloop_, (void*)this); // Back-reference | ||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | void Redox::init_hiredis() { | 55 | void Redox::init_hiredis() { |
| 56 | 56 | ||
| 57 | - ctx->data = (void*)this; // Back-reference | 57 | + ctx_->data = (void*)this; // Back-reference |
| 58 | 58 | ||
| 59 | - if (ctx->err) { | ||
| 60 | - logger.error() << "Could not create a hiredis context: " << ctx->errstr; | ||
| 61 | - connect_state = REDOX_CONNECT_ERROR; | ||
| 62 | - connect_waiter.notify_all(); | 59 | + if (ctx_->err) { |
| 60 | + logger_.error() << "Could not create a hiredis context: " << ctx_->errstr; | ||
| 61 | + connect_state_ = CONNECT_ERROR; | ||
| 62 | + connect_waiter_.notify_all(); | ||
| 63 | return; | 63 | return; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // Attach event loop to hiredis | 66 | // Attach event loop to hiredis |
| 67 | - redisLibevAttach(evloop, ctx); | 67 | + redisLibevAttach(evloop_, ctx_); |
| 68 | 68 | ||
| 69 | // Set the callbacks to be invoked on server connection/disconnection | 69 | // Set the callbacks to be invoked on server connection/disconnection |
| 70 | - redisAsyncSetConnectCallback(ctx, Redox::connected_callback); | ||
| 71 | - redisAsyncSetDisconnectCallback(ctx, Redox::disconnected_callback); | 70 | + redisAsyncSetConnectCallback(ctx_, Redox::connectedCallback); |
| 71 | + redisAsyncSetDisconnectCallback(ctx_, Redox::disconnectedCallback); | ||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | Redox::Redox( | 74 | Redox::Redox( |
| @@ -76,14 +76,14 @@ Redox::Redox( | @@ -76,14 +76,14 @@ Redox::Redox( | ||
| 76 | function<void(int)> connection_callback, | 76 | function<void(int)> connection_callback, |
| 77 | ostream& log_stream, | 77 | ostream& log_stream, |
| 78 | log::Level log_level | 78 | log::Level log_level |
| 79 | -) : host(host), port(port), | ||
| 80 | - logger(log_stream, log_level), | ||
| 81 | - user_connection_callback(connection_callback) { | 79 | +) : host_(host), port_(port), |
| 80 | + logger_(log_stream, log_level), | ||
| 81 | + user_connection_callback_(connection_callback) { | ||
| 82 | 82 | ||
| 83 | init_ev(); | 83 | init_ev(); |
| 84 | 84 | ||
| 85 | // Connect over TCP | 85 | // Connect over TCP |
| 86 | - ctx = redisAsyncConnect(host.c_str(), port); | 86 | + ctx_ = redisAsyncConnect(host.c_str(), port); |
| 87 | 87 | ||
| 88 | init_hiredis(); | 88 | init_hiredis(); |
| 89 | } | 89 | } |
| @@ -93,13 +93,13 @@ Redox::Redox( | @@ -93,13 +93,13 @@ Redox::Redox( | ||
| 93 | function<void(int)> connection_callback, | 93 | function<void(int)> connection_callback, |
| 94 | ostream& log_stream, | 94 | ostream& log_stream, |
| 95 | log::Level log_level | 95 | log::Level log_level |
| 96 | -) : host(), port(), path(path), logger(log_stream, log_level), | ||
| 97 | - user_connection_callback(connection_callback) { | 96 | +) : host_(), port_(), path_(path), logger_(log_stream, log_level), |
| 97 | + user_connection_callback_(connection_callback) { | ||
| 98 | 98 | ||
| 99 | init_ev(); | 99 | init_ev(); |
| 100 | 100 | ||
| 101 | // Connect over unix sockets | 101 | // Connect over unix sockets |
| 102 | - ctx = redisAsyncConnectUnix(path.c_str()); | 102 | + ctx_ = redisAsyncConnectUnix(path.c_str()); |
| 103 | 103 | ||
| 104 | init_hiredis(); | 104 | init_hiredis(); |
| 105 | } | 105 | } |
| @@ -108,142 +108,127 @@ void break_event_loop(struct ev_loop* loop, ev_async* async, int revents) { | @@ -108,142 +108,127 @@ void break_event_loop(struct ev_loop* loop, ev_async* async, int revents) { | ||
| 108 | ev_break(loop, EVBREAK_ALL); | 108 | ev_break(loop, EVBREAK_ALL); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | -void Redox::run_event_loop() { | 111 | +void Redox::runEventLoop() { |
| 112 | 112 | ||
| 113 | // Events to connect to Redox | 113 | // Events to connect to Redox |
| 114 | - ev_run(evloop, EVRUN_NOWAIT); | 114 | + ev_run(evloop_, EVRUN_NOWAIT); |
| 115 | 115 | ||
| 116 | // Block until connected to Redis, or error | 116 | // Block until connected to Redis, or error |
| 117 | - unique_lock<mutex> ul(connect_lock); | ||
| 118 | - connect_waiter.wait(ul, [this] { return connect_state != REDOX_NOT_YET_CONNECTED; }); | 117 | + unique_lock<mutex> ul(connect_lock_); |
| 118 | + connect_waiter_.wait(ul, [this] { return connect_state_ != NOT_YET_CONNECTED; }); | ||
| 119 | 119 | ||
| 120 | // Handle connection error | 120 | // Handle connection error |
| 121 | - if(connect_state != REDOX_CONNECTED) { | ||
| 122 | - logger.warning() << "Did not connect, event loop exiting."; | ||
| 123 | - running_waiter.notify_one(); | 121 | + if(connect_state_ != CONNECTED) { |
| 122 | + logger_.warning() << "Did not connect, event loop exiting."; | ||
| 123 | + running_waiter_.notify_one(); | ||
| 124 | return; | 124 | return; |
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | // Set up asynchronous watcher which we signal every | 127 | // Set up asynchronous watcher which we signal every |
| 128 | // time we add a command | 128 | // time we add a command |
| 129 | - ev_async_init(&async_w, process_queued_commands); | ||
| 130 | - ev_async_start(evloop, &async_w); | 129 | + ev_async_init(&watcher_command_, proccessQueuedCommands); |
| 130 | + ev_async_start(evloop_, &watcher_command_); | ||
| 131 | 131 | ||
| 132 | // Set up an async watcher to break the loop | 132 | // Set up an async watcher to break the loop |
| 133 | - ev_async_init(&async_stop, break_event_loop); | ||
| 134 | - ev_async_start(evloop, &async_stop); | 133 | + ev_async_init(&watcher_stop_, break_event_loop); |
| 134 | + ev_async_start(evloop_, &watcher_stop_); | ||
| 135 | 135 | ||
| 136 | - running = true; | ||
| 137 | - running_waiter.notify_one(); | 136 | + running_ = true; |
| 137 | + running_waiter_.notify_one(); | ||
| 138 | 138 | ||
| 139 | // Run the event loop | 139 | // Run the event loop |
| 140 | - while (!to_exit) { | 140 | + while (!to_exit_) { |
| 141 | // logger.info() << "Event loop running"; | 141 | // logger.info() << "Event loop running"; |
| 142 | - ev_run(evloop, EVRUN_NOWAIT); | 142 | + ev_run(evloop_, EVRUN_NOWAIT); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | - logger.info() << "Stop signal detected."; | 145 | + logger_.info() << "Stop signal detected. Disconnecting from Redis."; |
| 146 | + if(connect_state_ == CONNECTED) redisAsyncDisconnect(ctx_); | ||
| 146 | 147 | ||
| 147 | - // Run a few more times to clear out canceled events | 148 | + // Run a few more times to disconnect and clear out canceled events |
| 148 | for(int i = 0; i < 100; i++) { | 149 | for(int i = 0; i < 100; i++) { |
| 149 | - ev_run(evloop, EVRUN_NOWAIT); | 150 | + ev_run(evloop_, EVRUN_NOWAIT); |
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | - if(commands_created != commands_deleted) { | ||
| 153 | - logger.error() << "All commands were not freed! " | ||
| 154 | - << commands_deleted << "/" << commands_created; | 153 | + if(commands_created_ != commands_deleted_) { |
| 154 | + logger_.error() << "All commands were not freed! " | ||
| 155 | + << commands_deleted_ << "/" << commands_created_; | ||
| 155 | } | 156 | } |
| 156 | 157 | ||
| 157 | - exited = true; | ||
| 158 | - running = false; | 158 | + exited_ = true; |
| 159 | + running_ = false; | ||
| 159 | 160 | ||
| 160 | // Let go for block_until_stopped method | 161 | // Let go for block_until_stopped method |
| 161 | - exit_waiter.notify_one(); | 162 | + exit_waiter_.notify_one(); |
| 162 | 163 | ||
| 163 | - logger.info() << "Event thread exited."; | 164 | + logger_.info() << "Event thread exited."; |
| 164 | } | 165 | } |
| 165 | 166 | ||
| 166 | -bool Redox::start() { | 167 | +bool Redox::connect() { |
| 167 | 168 | ||
| 168 | - event_loop_thread = thread([this] { run_event_loop(); }); | 169 | + event_loop_thread_ = thread([this] { runEventLoop(); }); |
| 169 | 170 | ||
| 170 | // Block until connected and running the event loop, or until | 171 | // Block until connected and running the event loop, or until |
| 171 | // a connection error happens and the event loop exits | 172 | // a connection error happens and the event loop exits |
| 172 | - unique_lock<mutex> ul(running_waiter_lock); | ||
| 173 | - running_waiter.wait(ul, [this] { | ||
| 174 | - return running.load() || connect_state == REDOX_CONNECT_ERROR; | 173 | + unique_lock<mutex> ul(running_waiter_lock_); |
| 174 | + running_waiter_.wait(ul, [this] { | ||
| 175 | + return running_.load() || connect_state_ == CONNECT_ERROR; | ||
| 175 | }); | 176 | }); |
| 176 | 177 | ||
| 177 | // Return if succeeded | 178 | // Return if succeeded |
| 178 | - return connect_state == REDOX_CONNECTED; | ||
| 179 | -} | ||
| 180 | - | ||
| 181 | -void Redox::stop_signal() { | ||
| 182 | - to_exit = true; | ||
| 183 | - logger.debug() << "stop_signal() called, breaking event loop"; | ||
| 184 | - ev_async_send(evloop, &async_stop); | ||
| 185 | -} | ||
| 186 | - | ||
| 187 | -void Redox::block() { | ||
| 188 | - unique_lock<mutex> ul(exit_waiter_lock); | ||
| 189 | - exit_waiter.wait(ul, [this] { return exited.load(); }); | 179 | + return connect_state_ == CONNECTED; |
| 190 | } | 180 | } |
| 191 | 181 | ||
| 192 | -void Redox::stop() { | ||
| 193 | - stop_signal(); | ||
| 194 | - block(); | 182 | +void Redox::disconnect() { |
| 183 | + to_exit_ = true; | ||
| 184 | + logger_.debug() << "disconnect() called, breaking event loop"; | ||
| 185 | + ev_async_send(evloop_, &watcher_stop_); | ||
| 195 | } | 186 | } |
| 196 | 187 | ||
| 197 | -void Redox::disconnect() { | ||
| 198 | - stop_signal(); | ||
| 199 | - if(connect_state == REDOX_CONNECTED) { | ||
| 200 | - redisAsyncDisconnect(ctx); | ||
| 201 | - block(); | ||
| 202 | - } | 188 | +void Redox::wait() { |
| 189 | + unique_lock<mutex> ul(exit_waiter_lock_); | ||
| 190 | + exit_waiter_.wait(ul, [this] { return exited_.load(); }); | ||
| 203 | } | 191 | } |
| 204 | 192 | ||
| 205 | Redox::~Redox() { | 193 | Redox::~Redox() { |
| 206 | 194 | ||
| 207 | disconnect(); | 195 | disconnect(); |
| 208 | 196 | ||
| 209 | - if(event_loop_thread.joinable()) | ||
| 210 | - event_loop_thread.join(); | 197 | + if(event_loop_thread_.joinable()) |
| 198 | + event_loop_thread_.join(); | ||
| 211 | 199 | ||
| 212 | - ev_loop_destroy(evloop); | 200 | + ev_loop_destroy(evloop_); |
| 213 | 201 | ||
| 214 | - logger.info() << "Redox created " << commands_created | ||
| 215 | - << " Commands and freed " << commands_deleted << "."; | 202 | + logger_.info() << "Redox created " << commands_created_ |
| 203 | + << " Commands and freed " << commands_deleted_ << "."; | ||
| 216 | } | 204 | } |
| 217 | 205 | ||
| 218 | template<class ReplyT> | 206 | template<class ReplyT> |
| 219 | -Command<ReplyT>* Redox::find_command(long id) { | 207 | +Command<ReplyT>* Redox::findCommand(long id) { |
| 220 | 208 | ||
| 221 | - lock_guard<mutex> lg(command_map_guard); | 209 | + lock_guard<mutex> lg(command_map_guard_); |
| 222 | 210 | ||
| 223 | - auto& command_map = get_command_map<ReplyT>(); | 211 | + auto& command_map = getCommandMap<ReplyT>(); |
| 224 | auto it = command_map.find(id); | 212 | auto it = command_map.find(id); |
| 225 | if(it == command_map.end()) return nullptr; | 213 | if(it == command_map.end()) return nullptr; |
| 226 | return it->second; | 214 | return it->second; |
| 227 | } | 215 | } |
| 228 | 216 | ||
| 229 | template<class ReplyT> | 217 | template<class ReplyT> |
| 230 | -void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) { | 218 | +void Redox::commandCallback(redisAsyncContext* ctx, void* r, void* privdata) { |
| 231 | 219 | ||
| 232 | Redox* rdx = (Redox*) ctx->data; | 220 | Redox* rdx = (Redox*) ctx->data; |
| 233 | long id = (long)privdata; | 221 | long id = (long)privdata; |
| 234 | redisReply* reply_obj = (redisReply*) r; | 222 | redisReply* reply_obj = (redisReply*) r; |
| 235 | 223 | ||
| 236 | - Command<ReplyT>* c = rdx->find_command<ReplyT>(id); | 224 | + Command<ReplyT>* c = rdx->findCommand<ReplyT>(id); |
| 237 | if(c == nullptr) { | 225 | if(c == nullptr) { |
| 238 | -// rdx->logger.warning() << "Couldn't find Command " << id << " in command_map (command_callback)."; | 226 | +// rdx->logger.warning() << "Couldn't find Command " << id << " in command_map (commandCallback)."; |
| 239 | freeReplyObject(reply_obj); | 227 | freeReplyObject(reply_obj); |
| 240 | return; | 228 | return; |
| 241 | } | 229 | } |
| 242 | 230 | ||
| 243 | c->processReply(reply_obj); | 231 | c->processReply(reply_obj); |
| 244 | - | ||
| 245 | - // Increment the Redox object command counter | ||
| 246 | - rdx->cmd_count++; | ||
| 247 | } | 232 | } |
| 248 | 233 | ||
| 249 | /** | 234 | /** |
| @@ -251,7 +236,7 @@ void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) { | @@ -251,7 +236,7 @@ void Redox::command_callback(redisAsyncContext *ctx, void *r, void *privdata) { | ||
| 251 | * true if succeeded, false otherwise. | 236 | * true if succeeded, false otherwise. |
| 252 | */ | 237 | */ |
| 253 | template<class ReplyT> | 238 | template<class ReplyT> |
| 254 | -bool Redox::submit_to_server(Command<ReplyT>* c) { | 239 | +bool Redox::submitToServer(Command<ReplyT>* c) { |
| 255 | 240 | ||
| 256 | Redox* rdx = c->rdx_; | 241 | Redox* rdx = c->rdx_; |
| 257 | c->pending_++; | 242 | c->pending_++; |
| @@ -270,8 +255,8 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | @@ -270,8 +255,8 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | ||
| 270 | 255 | ||
| 271 | string format = c->cmd_.substr(0, first) + "%b"; | 256 | string format = c->cmd_.substr(0, first) + "%b"; |
| 272 | string value = c->cmd_.substr(first+1, last-first-1); | 257 | string value = c->cmd_.substr(first+1, last-first-1); |
| 273 | - if (redisAsyncCommand(rdx->ctx, command_callback<ReplyT>, (void*)c->id_, format.c_str(), value.c_str(), value.size()) != REDIS_OK) { | ||
| 274 | - rdx->logger.error() << "Could not send \"" << c->cmd_ << "\": " << rdx->ctx->errstr; | 258 | + if (redisAsyncCommand(rdx->ctx_, commandCallback < ReplyT > , (void*) c->id_, format.c_str(), value.c_str(), value.size()) != REDIS_OK) { |
| 259 | + rdx->logger_.error() << "Could not send \"" << c->cmd_ << "\": " << rdx->ctx_->errstr; | ||
| 275 | c->reply_status_ = Command<ReplyT>::SEND_ERROR; | 260 | c->reply_status_ = Command<ReplyT>::SEND_ERROR; |
| 276 | c->invoke(); | 261 | c->invoke(); |
| 277 | return false; | 262 | return false; |
| @@ -280,8 +265,8 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | @@ -280,8 +265,8 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | ||
| 280 | } | 265 | } |
| 281 | } | 266 | } |
| 282 | 267 | ||
| 283 | - if (redisAsyncCommand(rdx->ctx, command_callback<ReplyT>, (void*)c->id_, c->cmd_.c_str()) != REDIS_OK) { | ||
| 284 | - rdx->logger.error() << "Could not send \"" << c->cmd_ << "\": " << rdx->ctx->errstr; | 268 | + if (redisAsyncCommand(rdx->ctx_, commandCallback < ReplyT > , (void*) c->id_, c->cmd_.c_str()) != REDIS_OK) { |
| 269 | + rdx->logger_.error() << "Could not send \"" << c->cmd_ << "\": " << rdx->ctx_->errstr; | ||
| 285 | c->reply_status_ = Command<ReplyT>::SEND_ERROR; | 270 | c->reply_status_ = Command<ReplyT>::SEND_ERROR; |
| 286 | c->invoke(); | 271 | c->invoke(); |
| 287 | return false; | 272 | return false; |
| @@ -291,15 +276,15 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | @@ -291,15 +276,15 @@ bool Redox::submit_to_server(Command<ReplyT>* c) { | ||
| 291 | } | 276 | } |
| 292 | 277 | ||
| 293 | template<class ReplyT> | 278 | template<class ReplyT> |
| 294 | -void Redox::submit_command_callback(struct ev_loop* loop, ev_timer* timer, int revents) { | 279 | +void Redox::submitCommandCallback(struct ev_loop* loop, ev_timer* timer, int revents) { |
| 295 | 280 | ||
| 296 | Redox* rdx = (Redox*) ev_userdata(loop); | 281 | Redox* rdx = (Redox*) ev_userdata(loop); |
| 297 | long id = (long)timer->data; | 282 | long id = (long)timer->data; |
| 298 | 283 | ||
| 299 | - Command<ReplyT>* c = rdx->find_command<ReplyT>(id); | 284 | + Command<ReplyT>* c = rdx->findCommand<ReplyT>(id); |
| 300 | if(c == nullptr) { | 285 | if(c == nullptr) { |
| 301 | - rdx->logger.error() << "Couldn't find Command " << id | ||
| 302 | - << " in command_map (submit_command_callback)."; | 286 | + rdx->logger_.error() << "Couldn't find Command " << id |
| 287 | + << " in command_map (submitCommandCallback)."; | ||
| 303 | return; | 288 | return; |
| 304 | } | 289 | } |
| 305 | 290 | ||
| @@ -318,23 +303,23 @@ void Redox::submit_command_callback(struct ev_loop* loop, ev_timer* timer, int r | @@ -318,23 +303,23 @@ void Redox::submit_command_callback(struct ev_loop* loop, ev_timer* timer, int r | ||
| 318 | return; | 303 | return; |
| 319 | } | 304 | } |
| 320 | 305 | ||
| 321 | - submit_to_server<ReplyT>(c); | 306 | + submitToServer<ReplyT>(c); |
| 322 | } | 307 | } |
| 323 | 308 | ||
| 324 | template<class ReplyT> | 309 | template<class ReplyT> |
| 325 | -bool Redox::process_queued_command(long id) { | 310 | +bool Redox::proccessQueuedCommand(long id) { |
| 326 | 311 | ||
| 327 | - Command<ReplyT>* c = find_command<ReplyT>(id); | 312 | + Command<ReplyT>* c = findCommand<ReplyT>(id); |
| 328 | if(c == nullptr) return false; | 313 | if(c == nullptr) return false; |
| 329 | 314 | ||
| 330 | if((c->repeat_ == 0) && (c->after_ == 0)) { | 315 | if((c->repeat_ == 0) && (c->after_ == 0)) { |
| 331 | - submit_to_server<ReplyT>(c); | 316 | + submitToServer<ReplyT>(c); |
| 332 | 317 | ||
| 333 | } else { | 318 | } else { |
| 334 | 319 | ||
| 335 | c->timer_.data = (void*)c->id_; | 320 | c->timer_.data = (void*)c->id_; |
| 336 | - ev_timer_init(&c->timer_, submit_command_callback<ReplyT>, c->after_, c->repeat_); | ||
| 337 | - ev_timer_start(evloop, &c->timer_); | 321 | + ev_timer_init(&c->timer_, submitCommandCallback <ReplyT>, c->after_, c->repeat_); |
| 322 | + ev_timer_start(evloop_, &c->timer_); | ||
| 338 | 323 | ||
| 339 | c->timer_guard_.unlock(); | 324 | c->timer_guard_.unlock(); |
| 340 | } | 325 | } |
| @@ -342,7 +327,7 @@ bool Redox::process_queued_command(long id) { | @@ -342,7 +327,7 @@ bool Redox::process_queued_command(long id) { | ||
| 342 | return true; | 327 | return true; |
| 343 | } | 328 | } |
| 344 | 329 | ||
| 345 | -void Redox::process_queued_commands(struct ev_loop* loop, ev_async* async, int revents) { | 330 | +void Redox::proccessQueuedCommands(struct ev_loop* loop, ev_async* async, int revents) { |
| 346 | 331 | ||
| 347 | Redox* rdx = (Redox*) ev_userdata(loop); | 332 | Redox* rdx = (Redox*) ev_userdata(loop); |
| 348 | 333 | ||
| @@ -353,224 +338,60 @@ void Redox::process_queued_commands(struct ev_loop* loop, ev_async* async, int r | @@ -353,224 +338,60 @@ void Redox::process_queued_commands(struct ev_loop* loop, ev_async* async, int r | ||
| 353 | long id = rdx->command_queue.front(); | 338 | long id = rdx->command_queue.front(); |
| 354 | rdx->command_queue.pop(); | 339 | rdx->command_queue.pop(); |
| 355 | 340 | ||
| 356 | - if(rdx->process_queued_command<redisReply*>(id)) {} | ||
| 357 | - else if(rdx->process_queued_command<string>(id)) {} | ||
| 358 | - else if(rdx->process_queued_command<char*>(id)) {} | ||
| 359 | - else if(rdx->process_queued_command<int>(id)) {} | ||
| 360 | - else if(rdx->process_queued_command<long long int>(id)) {} | ||
| 361 | - else if(rdx->process_queued_command<nullptr_t>(id)) {} | ||
| 362 | - else if(rdx->process_queued_command<vector<string>>(id)) {} | ||
| 363 | - else if(rdx->process_queued_command<std::set<string>>(id)) {} | ||
| 364 | - else if(rdx->process_queued_command<unordered_set<string>>(id)) {} | 341 | + if(rdx->proccessQueuedCommand<redisReply*>(id)) {} |
| 342 | + else if(rdx->proccessQueuedCommand<string>(id)) {} | ||
| 343 | + else if(rdx->proccessQueuedCommand<char*>(id)) {} | ||
| 344 | + else if(rdx->proccessQueuedCommand<int>(id)) {} | ||
| 345 | + else if(rdx->proccessQueuedCommand<long long int>(id)) {} | ||
| 346 | + else if(rdx->proccessQueuedCommand<nullptr_t>(id)) {} | ||
| 347 | + else if(rdx->proccessQueuedCommand<vector<string>>(id)) {} | ||
| 348 | + else if(rdx->proccessQueuedCommand<std::set<string>>(id)) {} | ||
| 349 | + else if(rdx->proccessQueuedCommand<unordered_set<string>>(id)) {} | ||
| 365 | else throw runtime_error("Command pointer not found in any queue!"); | 350 | else throw runtime_error("Command pointer not found in any queue!"); |
| 366 | } | 351 | } |
| 367 | } | 352 | } |
| 368 | 353 | ||
| 369 | // --------------------------------- | 354 | // --------------------------------- |
| 370 | -// Pub/Sub methods | ||
| 371 | -// --------------------------------- | ||
| 372 | - | ||
| 373 | -void Redox::subscribe_raw(const string cmd_name, const string topic, | ||
| 374 | - function<void(const string&, const string&)> msg_callback, | ||
| 375 | - function<void(const string&)> sub_callback, | ||
| 376 | - function<void(const string&)> unsub_callback, | ||
| 377 | - function<void(const string&, int)> err_callback | ||
| 378 | -) { | ||
| 379 | - | ||
| 380 | - // Start pubsub mode. No non-sub/unsub commands can be emitted by this client. | ||
| 381 | - pubsub_mode = true; | ||
| 382 | - | ||
| 383 | - command_looping<redisReply*>(cmd_name + " " + topic, | ||
| 384 | - [this, topic, msg_callback, err_callback, sub_callback, unsub_callback](Command<redisReply*>& c) { | ||
| 385 | - | ||
| 386 | - if(!c.ok()) { | ||
| 387 | - if(err_callback) err_callback(topic, c.status()); | ||
| 388 | - return; | ||
| 389 | - } | ||
| 390 | - | ||
| 391 | - redisReply* reply = c.reply(); | ||
| 392 | - | ||
| 393 | - // For debugging only | ||
| 394 | -// cout << "------" << endl; | ||
| 395 | -// cout << cmd << " " << (reply->type == REDIS_REPLY_ARRAY) << " " << (reply->elements) << endl; | ||
| 396 | -// for(int i = 0; i < reply->elements; i++) { | ||
| 397 | -// redisReply* r = reply->element[i]; | ||
| 398 | -// cout << "element " << i << ", reply type = " << r->type << " "; | ||
| 399 | -// if(r->type == REDIS_REPLY_STRING) cout << r->str << endl; | ||
| 400 | -// else if(r->type == REDIS_REPLY_INTEGER) cout << r->integer << endl; | ||
| 401 | -// else cout << "some other type" << endl; | ||
| 402 | -// } | ||
| 403 | -// cout << "------" << endl; | ||
| 404 | - | ||
| 405 | - // TODO cancel this command on unsubscription? | ||
| 406 | - | ||
| 407 | - // If the last entry is an integer, then it is a [p]sub/[p]unsub command | ||
| 408 | - if((reply->type == REDIS_REPLY_ARRAY) && | ||
| 409 | - (reply->element[reply->elements-1]->type == REDIS_REPLY_INTEGER)) { | ||
| 410 | - | ||
| 411 | - if(!strncmp(reply->element[0]->str, "sub", 3)) { | ||
| 412 | - subscribed_topics_.insert(topic); | ||
| 413 | - if(sub_callback) sub_callback(topic); | ||
| 414 | - | ||
| 415 | - } else if(!strncmp(reply->element[0]->str, "psub", 4)) { | ||
| 416 | - psubscribed_topics_.insert(topic); | ||
| 417 | - if (sub_callback) sub_callback(topic); | ||
| 418 | - | ||
| 419 | - } else if(!strncmp(reply->element[0]->str, "uns", 3)) { | ||
| 420 | - subscribed_topics_.erase(topic); | ||
| 421 | - if (unsub_callback) unsub_callback(topic); | ||
| 422 | - | ||
| 423 | - } else if(!strncmp(reply->element[0]->str, "puns", 4)) { | ||
| 424 | - psubscribed_topics_.erase(topic); | ||
| 425 | - if (unsub_callback) unsub_callback(topic); | ||
| 426 | - } | ||
| 427 | - | ||
| 428 | - else logger.error() << "Unknown pubsub message: " << reply->element[0]->str; | ||
| 429 | - } | ||
| 430 | - | ||
| 431 | - // Message for subscribe | ||
| 432 | - else if ((reply->type == REDIS_REPLY_ARRAY) && (reply->elements == 3)) { | ||
| 433 | - char *msg = reply->element[2]->str; | ||
| 434 | - if (msg && msg_callback) msg_callback(topic, reply->element[2]->str); | ||
| 435 | - } | ||
| 436 | - | ||
| 437 | - // Message for psubscribe | ||
| 438 | - else if ((reply->type == REDIS_REPLY_ARRAY) && (reply->elements == 4)) { | ||
| 439 | - char *msg = reply->element[2]->str; | ||
| 440 | - if (msg && msg_callback) msg_callback(reply->element[2]->str, reply->element[3]->str); | ||
| 441 | - } | ||
| 442 | - | ||
| 443 | - else logger.error() << "Unknown pubsub message of type " << reply->type; | ||
| 444 | - }, | ||
| 445 | - 1e10 // To keep the command around for a few hundred years | ||
| 446 | - ); | ||
| 447 | -} | ||
| 448 | - | ||
| 449 | -void Redox::subscribe(const string topic, | ||
| 450 | - function<void(const string&, const string&)> msg_callback, | ||
| 451 | - function<void(const string&)> sub_callback, | ||
| 452 | - function<void(const string&)> unsub_callback, | ||
| 453 | - function<void(const string&, int)> err_callback | ||
| 454 | -) { | ||
| 455 | - if(subscribed_topics_.find(topic) != subscribed_topics_.end()) { | ||
| 456 | - logger.warning() << "Already subscribed to " << topic << "!"; | ||
| 457 | - return; | ||
| 458 | - } | ||
| 459 | - subscribe_raw("SUBSCRIBE", topic, msg_callback, sub_callback, unsub_callback, err_callback); | ||
| 460 | -} | ||
| 461 | - | ||
| 462 | -void Redox::psubscribe(const string topic, | ||
| 463 | - function<void(const string&, const string&)> msg_callback, | ||
| 464 | - function<void(const string&)> sub_callback, | ||
| 465 | - function<void(const string&)> unsub_callback, | ||
| 466 | - function<void(const string&, int)> err_callback | ||
| 467 | -) { | ||
| 468 | - if(psubscribed_topics_.find(topic) != psubscribed_topics_.end()) { | ||
| 469 | - logger.warning() << "Already psubscribed to " << topic << "!"; | ||
| 470 | - return; | ||
| 471 | - } | ||
| 472 | - subscribe_raw("PSUBSCRIBE", topic, msg_callback, sub_callback, unsub_callback, err_callback); | ||
| 473 | -} | ||
| 474 | - | ||
| 475 | -void Redox::unsubscribe_raw(const string cmd_name, const string topic, | ||
| 476 | - function<void(const string&, int)> err_callback | ||
| 477 | -) { | ||
| 478 | - command<redisReply*>(cmd_name + " " + topic, | ||
| 479 | - [topic, err_callback](Command<redisReply*>& c) { | ||
| 480 | - if(!c.ok()) { | ||
| 481 | - if (err_callback) err_callback(topic, c.status()); | ||
| 482 | - } | ||
| 483 | - } | ||
| 484 | - ); | ||
| 485 | -} | ||
| 486 | - | ||
| 487 | -void Redox::unsubscribe(const string topic, | ||
| 488 | - function<void(const string&, int)> err_callback | ||
| 489 | -) { | ||
| 490 | - if(subscribed_topics_.find(topic) == subscribed_topics_.end()) { | ||
| 491 | - logger.warning() << "Cannot unsubscribe from " << topic << ", not subscribed!"; | ||
| 492 | - return; | ||
| 493 | - } | ||
| 494 | - unsubscribe_raw("UNSUBSCRIBE", topic, err_callback); | ||
| 495 | -} | ||
| 496 | - | ||
| 497 | -void Redox::punsubscribe(const string topic, | ||
| 498 | - function<void(const string&, int)> err_callback | ||
| 499 | -) { | ||
| 500 | - if(psubscribed_topics_.find(topic) == psubscribed_topics_.end()) { | ||
| 501 | - logger.warning() << "Cannot punsubscribe from " << topic << ", not psubscribed!"; | ||
| 502 | - return; | ||
| 503 | - } | ||
| 504 | - unsubscribe_raw("PUNSUBSCRIBE", topic, err_callback); | ||
| 505 | -} | ||
| 506 | - | ||
| 507 | -void Redox::publish(const string topic, const string msg, | ||
| 508 | - function<void(const string&, const string&)> pub_callback, | ||
| 509 | - function<void(const string&, int)> err_callback | ||
| 510 | -) { | ||
| 511 | - command<redisReply*>("PUBLISH " + topic + " " + msg, | ||
| 512 | - [topic, msg, err_callback, pub_callback](Command<redisReply*>& c) { | ||
| 513 | - if(!c.ok()) { | ||
| 514 | - if(err_callback) err_callback(topic, c.status()); | ||
| 515 | - } | ||
| 516 | - if(pub_callback) pub_callback(topic, msg); | ||
| 517 | - } | ||
| 518 | - ); | ||
| 519 | -} | ||
| 520 | - | ||
| 521 | -/** | ||
| 522 | -* Throw an exception for any non-pubsub commands. | ||
| 523 | -*/ | ||
| 524 | -void Redox::deny_non_pubsub(const string& cmd) { | ||
| 525 | - | ||
| 526 | - string cmd_name = cmd.substr(0, cmd.find(' ')); | ||
| 527 | - | ||
| 528 | - // Compare with the command's first 5 characters | ||
| 529 | - if(!cmd_name.compare("SUBSCRIBE") || !cmd_name.compare("UNSUBSCRIBE") || | ||
| 530 | - !cmd_name.compare("PSUBSCRIBE") || !cmd_name.compare("PUNSUBSCRIBE")) { | ||
| 531 | - } else { | ||
| 532 | - throw runtime_error("In pub/sub mode, this Redox instance can only issue " | ||
| 533 | - "[p]subscribe/[p]unsubscribe commands! Use another instance for other commands."); | ||
| 534 | - } | ||
| 535 | -} | ||
| 536 | - | ||
| 537 | -// --------------------------------- | ||
| 538 | // get_command_map specializations | 355 | // get_command_map specializations |
| 539 | // --------------------------------- | 356 | // --------------------------------- |
| 540 | 357 | ||
| 541 | template<> unordered_map<long, Command<redisReply*>*>& | 358 | template<> unordered_map<long, Command<redisReply*>*>& |
| 542 | -Redox::get_command_map<redisReply*>() { return commands_redis_reply; } | 359 | +Redox::getCommandMap<redisReply*>() { return commands_redis_reply_; } |
| 543 | 360 | ||
| 544 | template<> unordered_map<long, Command<string>*>& | 361 | template<> unordered_map<long, Command<string>*>& |
| 545 | -Redox::get_command_map<string>() { return commands_string_r; } | 362 | +Redox::getCommandMap<string>() { return commands_string_; } |
| 546 | 363 | ||
| 547 | template<> unordered_map<long, Command<char*>*>& | 364 | template<> unordered_map<long, Command<char*>*>& |
| 548 | -Redox::get_command_map<char*>() { return commands_char_p; } | 365 | +Redox::getCommandMap<char*>() { return commands_char_p_; } |
| 549 | 366 | ||
| 550 | template<> unordered_map<long, Command<int>*>& | 367 | template<> unordered_map<long, Command<int>*>& |
| 551 | -Redox::get_command_map<int>() { return commands_int; } | 368 | +Redox::getCommandMap<int>() { return commands_int_; } |
| 552 | 369 | ||
| 553 | template<> unordered_map<long, Command<long long int>*>& | 370 | template<> unordered_map<long, Command<long long int>*>& |
| 554 | -Redox::get_command_map<long long int>() { return commands_long_long_int; } | 371 | +Redox::getCommandMap<long long int>() { return commands_long_long_int_; } |
| 555 | 372 | ||
| 556 | template<> unordered_map<long, Command<nullptr_t>*>& | 373 | template<> unordered_map<long, Command<nullptr_t>*>& |
| 557 | -Redox::get_command_map<nullptr_t>() { return commands_null; } | 374 | +Redox::getCommandMap<nullptr_t>() { return commands_null_; } |
| 558 | 375 | ||
| 559 | template<> unordered_map<long, Command<vector<string>>*>& | 376 | template<> unordered_map<long, Command<vector<string>>*>& |
| 560 | -Redox::get_command_map<vector<string>>() { return commands_vector_string; } | 377 | +Redox::getCommandMap<vector<string>>() { return commands_vector_string_; } |
| 561 | 378 | ||
| 562 | template<> unordered_map<long, Command<set<string>>*>& | 379 | template<> unordered_map<long, Command<set<string>>*>& |
| 563 | -Redox::get_command_map<set<string>>() { return commands_set_string; } | 380 | +Redox::getCommandMap<set<string>>() { return commands_set_string_; } |
| 564 | 381 | ||
| 565 | template<> unordered_map<long, Command<unordered_set<string>>*>& | 382 | template<> unordered_map<long, Command<unordered_set<string>>*>& |
| 566 | -Redox::get_command_map<unordered_set<string>>() { return commands_unordered_set_string; } | 383 | +Redox::getCommandMap<unordered_set<string>>() { return commands_unordered_set_string_; } |
| 567 | 384 | ||
| 568 | // ---------------------------- | 385 | // ---------------------------- |
| 569 | // Helpers | 386 | // Helpers |
| 570 | // ---------------------------- | 387 | // ---------------------------- |
| 571 | 388 | ||
| 572 | -bool Redox::command_blocking(const string& cmd) { | ||
| 573 | - auto& c = command_blocking<redisReply*>(cmd); | 389 | +void Redox::command(const std::string& cmd) { |
| 390 | + command<redisReply*>(cmd, nullptr); | ||
| 391 | +} | ||
| 392 | + | ||
| 393 | +bool Redox::commandSync(const string& cmd) { | ||
| 394 | + auto& c = commandSync<redisReply*>(cmd); | ||
| 574 | bool succeeded = c.ok(); | 395 | bool succeeded = c.ok(); |
| 575 | c.free(); | 396 | c.free(); |
| 576 | return succeeded; | 397 | return succeeded; |
| @@ -578,7 +399,7 @@ bool Redox::command_blocking(const string& cmd) { | @@ -578,7 +399,7 @@ bool Redox::command_blocking(const string& cmd) { | ||
| 578 | 399 | ||
| 579 | string Redox::get(const string& key) { | 400 | string Redox::get(const string& key) { |
| 580 | 401 | ||
| 581 | - Command<char*>& c = command_blocking<char*>("GET " + key); | 402 | + Command<char*>& c = commandSync<char*>("GET " + key); |
| 582 | if(!c.ok()) { | 403 | if(!c.ok()) { |
| 583 | throw runtime_error("[FATAL] Error getting key " + key + ": Status code " + to_string(c.status())); | 404 | throw runtime_error("[FATAL] Error getting key " + key + ": Status code " + to_string(c.status())); |
| 584 | } | 405 | } |
| @@ -588,11 +409,25 @@ string Redox::get(const string& key) { | @@ -588,11 +409,25 @@ string Redox::get(const string& key) { | ||
| 588 | }; | 409 | }; |
| 589 | 410 | ||
| 590 | bool Redox::set(const string& key, const string& value) { | 411 | bool Redox::set(const string& key, const string& value) { |
| 591 | - return command_blocking("SET " + key + " " + value); | 412 | + return commandSync("SET " + key + " " + value); |
| 592 | } | 413 | } |
| 593 | 414 | ||
| 594 | bool Redox::del(const string& key) { | 415 | bool Redox::del(const string& key) { |
| 595 | - return command_blocking("DEL " + key); | 416 | + return commandSync("DEL " + key); |
| 417 | +} | ||
| 418 | + | ||
| 419 | +void Redox::publish(const string topic, const string msg, | ||
| 420 | + function<void(const string&, const string&)> pub_callback, | ||
| 421 | + function<void(const string&, int)> err_callback | ||
| 422 | +) { | ||
| 423 | + command<redisReply*>("PUBLISH " + topic + " " + msg, | ||
| 424 | + [topic, msg, err_callback, pub_callback](Command<redisReply*>& c) { | ||
| 425 | + if(!c.ok()) { | ||
| 426 | + if(err_callback) err_callback(topic, c.status()); | ||
| 427 | + } | ||
| 428 | + if(pub_callback) pub_callback(topic, msg); | ||
| 429 | + } | ||
| 430 | + ); | ||
| 596 | } | 431 | } |
| 597 | 432 | ||
| 598 | } // End namespace redis | 433 | } // End namespace redis |
src/redox.hpp
| @@ -27,23 +27,25 @@ | @@ -27,23 +27,25 @@ | ||
| 27 | 27 | ||
| 28 | namespace redox { | 28 | namespace redox { |
| 29 | 29 | ||
| 30 | -// Default to a local Redis server | ||
| 31 | static const std::string REDIS_DEFAULT_HOST = "localhost"; | 30 | static const std::string REDIS_DEFAULT_HOST = "localhost"; |
| 32 | static const int REDIS_DEFAULT_PORT = 6379; | 31 | static const int REDIS_DEFAULT_PORT = 6379; |
| 33 | 32 | ||
| 34 | -// Connection status | ||
| 35 | -static const int REDOX_NOT_YET_CONNECTED = 0; | ||
| 36 | -static const int REDOX_CONNECTED = 1; | ||
| 37 | -static const int REDOX_DISCONNECTED = 2; | ||
| 38 | -static const int REDOX_CONNECT_ERROR = 3; | ||
| 39 | -static const int REDOX_DISCONNECT_ERROR = 4; | ||
| 40 | - | 33 | +/** |
| 34 | +* Redox intro here. | ||
| 35 | +*/ | ||
| 41 | class Redox { | 36 | class Redox { |
| 42 | 37 | ||
| 43 | public: | 38 | public: |
| 44 | 39 | ||
| 40 | + // Connection states | ||
| 41 | + static const int NOT_YET_CONNECTED = 0; | ||
| 42 | + static const int CONNECTED = 1; | ||
| 43 | + static const int DISCONNECTED = 2; | ||
| 44 | + static const int CONNECT_ERROR = 3; | ||
| 45 | + static const int DISCONNECT_ERROR = 4; | ||
| 46 | + | ||
| 45 | /** | 47 | /** |
| 46 | - * Initialize everything, connect over TCP to a Redis server. | 48 | + * Initializes everything, connects over TCP to a Redis server. |
| 47 | */ | 49 | */ |
| 48 | Redox( | 50 | Redox( |
| 49 | const std::string& host = REDIS_DEFAULT_HOST, | 51 | const std::string& host = REDIS_DEFAULT_HOST, |
| @@ -54,7 +56,7 @@ public: | @@ -54,7 +56,7 @@ public: | ||
| 54 | ); | 56 | ); |
| 55 | 57 | ||
| 56 | /** | 58 | /** |
| 57 | - * Initialize everything, connect over unix sockets to a Redis server. | 59 | + * Initializes everything, connects over unix sockets to a Redis server. |
| 58 | */ | 60 | */ |
| 59 | Redox( | 61 | Redox( |
| 60 | const std::string& path, | 62 | const std::string& path, |
| @@ -62,29 +64,29 @@ public: | @@ -62,29 +64,29 @@ public: | ||
| 62 | std::ostream& log_stream = std::cout, | 64 | std::ostream& log_stream = std::cout, |
| 63 | log::Level log_level = log::Info | 65 | log::Level log_level = log::Info |
| 64 | ); | 66 | ); |
| 65 | - ~Redox(); | ||
| 66 | 67 | ||
| 67 | /** | 68 | /** |
| 68 | - * Connect to Redis and start the event loop in a separate thread. Returns | ||
| 69 | - * true if and when everything is ready to go, or false on failure. | 69 | + * Disconnects from the Redis server, shuts down the event loop, and cleans up. |
| 70 | + * Internally calls disconnect() and wait(). | ||
| 70 | */ | 71 | */ |
| 71 | - bool start(); | 72 | + ~Redox(); |
| 72 | 73 | ||
| 73 | /** | 74 | /** |
| 74 | - * Signal the event loop to stop processing commands and shut down. | 75 | + * Connects to Redis and starts an event loop in a separate thread. Returns |
| 76 | + * true once everything is ready, or false on failure. | ||
| 75 | */ | 77 | */ |
| 76 | - void stop_signal(); | 78 | + bool connect(); |
| 77 | 79 | ||
| 78 | /** | 80 | /** |
| 79 | - * Wait for the event loop to exit, then return. | 81 | + * Signal the event loop thread to disconnect from Redis and shut down. |
| 80 | */ | 82 | */ |
| 81 | - void block(); | 83 | + void disconnect(); |
| 82 | 84 | ||
| 83 | /** | 85 | /** |
| 84 | - * Signal the event loop to stop, wait for all pending commands to be processed, | ||
| 85 | - * and shut everything down. A simple combination of stop_signal() and block(). | 86 | + * Blocks until the event loop exits and disconnection is complete, then returns. |
| 87 | + * Usually no need to call manually as it is handled in the destructor. | ||
| 86 | */ | 88 | */ |
| 87 | - void stop(); | 89 | + void wait(); |
| 88 | 90 | ||
| 89 | /** | 91 | /** |
| 90 | * Asynchronously runs a command and invokes the callback when a reply is | 92 | * Asynchronously runs a command and invokes the callback when a reply is |
| @@ -101,7 +103,7 @@ public: | @@ -101,7 +103,7 @@ public: | ||
| 101 | /** | 103 | /** |
| 102 | * Asynchronously runs a command and ignores any errors or replies. | 104 | * Asynchronously runs a command and ignores any errors or replies. |
| 103 | */ | 105 | */ |
| 104 | - void command(const std::string& cmd) { command<redisReply*>(cmd, nullptr); } | 106 | + void command(const std::string& cmd); |
| 105 | 107 | ||
| 106 | /** | 108 | /** |
| 107 | * Synchronously runs a command, returning the Command object only once | 109 | * Synchronously runs a command, returning the Command object only once |
| @@ -109,150 +111,62 @@ public: | @@ -109,150 +111,62 @@ public: | ||
| 109 | * calling the Command object's .free() method when done with it. | 111 | * calling the Command object's .free() method when done with it. |
| 110 | */ | 112 | */ |
| 111 | template<class ReplyT> | 113 | template<class ReplyT> |
| 112 | - Command<ReplyT>& command_blocking(const std::string& cmd); | 114 | + Command<ReplyT>& commandSync(const std::string& cmd); |
| 113 | 115 | ||
| 114 | /** | 116 | /** |
| 115 | * Synchronously runs a command, returning only once a reply is received | 117 | * Synchronously runs a command, returning only once a reply is received |
| 116 | - * or there's an error. The return value is true if the command got a | ||
| 117 | - * successful reply, and false if something went wrong. | 118 | + * or there's an error. Returns true on successful reply, false on error. |
| 118 | */ | 119 | */ |
| 119 | - bool command_blocking(const std::string& cmd); | 120 | + bool commandSync(const std::string& cmd); |
| 120 | 121 | ||
| 122 | + /** | ||
| 123 | + * Creates an asynchronous command that is run every [repeat] seconds, | ||
| 124 | + * with the first one run in [after] seconds. If [repeat] is 0, the | ||
| 125 | + * command is run only once. | ||
| 126 | + */ | ||
| 121 | template<class ReplyT> | 127 | template<class ReplyT> |
| 122 | - Command<ReplyT>& command_looping( | 128 | + Command<ReplyT>& commandLoop( |
| 123 | const std::string& cmd, | 129 | const std::string& cmd, |
| 124 | const std::function<void(Command<ReplyT>&)>& callback, | 130 | const std::function<void(Command<ReplyT>&)>& callback, |
| 125 | double repeat, | 131 | double repeat, |
| 126 | double after = 0.0 | 132 | double after = 0.0 |
| 127 | ); | 133 | ); |
| 128 | 134 | ||
| 129 | - /** | ||
| 130 | - * A wrapper around command() for synchronous use. Waits for a reply, populates it | ||
| 131 | - * into the Command object, and returns when complete. The user can retrieve the | ||
| 132 | - * results from the Command object - ok() will tell you if the call succeeded, | ||
| 133 | - * status() will give the error code, and reply() will return the reply data if | ||
| 134 | - * the call succeeded. | ||
| 135 | - */ | ||
| 136 | -// template<class ReplyT> | ||
| 137 | -// Command<ReplyT>& command_blocking(const std::string& cmd); | ||
| 138 | - | ||
| 139 | - /** | ||
| 140 | - * Return the total number of successful commands processed by this Redox instance. | ||
| 141 | - */ | ||
| 142 | - long num_commands_processed() { return cmd_count; } | ||
| 143 | - | ||
| 144 | - // Hiredis context, left public to allow low-level access | ||
| 145 | - redisAsyncContext *ctx; | ||
| 146 | - | ||
| 147 | - /** | ||
| 148 | - * If connected, disconnect from the Redis server. Usually not necessary to invoke | ||
| 149 | - * manually, as it is called in the destructor. | ||
| 150 | - */ | ||
| 151 | - void disconnect(); | ||
| 152 | - | ||
| 153 | // ------------------------------------------------ | 135 | // ------------------------------------------------ |
| 154 | // Wrapper methods for convenience only | 136 | // Wrapper methods for convenience only |
| 155 | // ------------------------------------------------ | 137 | // ------------------------------------------------ |
| 156 | 138 | ||
| 157 | /** | 139 | /** |
| 158 | - * Non-templated version of command in case you really don't care | ||
| 159 | - * about the reply and just want to send something off. | ||
| 160 | - */ | ||
| 161 | -// void command(const std::string& command); | ||
| 162 | - | ||
| 163 | - /** | ||
| 164 | - * Non-templated version of command_blocking in case you really don't | ||
| 165 | - * care about the reply. Returns true if succeeded, false if error. | ||
| 166 | - */ | ||
| 167 | -// bool command_blocking(const std::string& command); | ||
| 168 | - | ||
| 169 | - /** | ||
| 170 | * Redis GET command wrapper - return the value for the given key, or throw | 140 | * Redis GET command wrapper - return the value for the given key, or throw |
| 171 | - * an exception if there is an error. Blocking call, of course. | 141 | + * an exception if there is an error. Blocking call. |
| 172 | */ | 142 | */ |
| 173 | std::string get(const std::string& key); | 143 | std::string get(const std::string& key); |
| 174 | 144 | ||
| 175 | /** | 145 | /** |
| 176 | * Redis SET command wrapper - set the value for the given key. Return | 146 | * Redis SET command wrapper - set the value for the given key. Return |
| 177 | - * true if succeeded, false if error. | 147 | + * true if succeeded, false if error. Blocking call. |
| 178 | */ | 148 | */ |
| 179 | bool set(const std::string& key, const std::string& value); | 149 | bool set(const std::string& key, const std::string& value); |
| 180 | 150 | ||
| 181 | /** | 151 | /** |
| 182 | * Redis DEL command wrapper - delete the given key. Return true if succeeded, | 152 | * Redis DEL command wrapper - delete the given key. Return true if succeeded, |
| 183 | - * false if error. | 153 | + * false if error. Blocking call. |
| 184 | */ | 154 | */ |
| 185 | bool del(const std::string& key); | 155 | bool del(const std::string& key); |
| 186 | 156 | ||
| 187 | - // ------------------------------------------------ | ||
| 188 | - // Publish/subscribe | ||
| 189 | - // ------------------------------------------------ | ||
| 190 | - | ||
| 191 | - // This is activated when subscribe is called. When active, | ||
| 192 | - // all commands other than [P]SUBSCRIBE, [P]UNSUBSCRIBE | ||
| 193 | - // throw exceptions | ||
| 194 | - std::atomic_bool pubsub_mode = {false}; | ||
| 195 | - | ||
| 196 | - /** | ||
| 197 | - * Subscribe to a topic. | ||
| 198 | - * | ||
| 199 | - * msg_callback: invoked whenever a message is received. | ||
| 200 | - * sub_callback: invoked when successfully subscribed | ||
| 201 | - * err_callback: invoked on some error state | ||
| 202 | - */ | ||
| 203 | - void subscribe(const std::string topic, | ||
| 204 | - std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 205 | - std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 206 | - std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 207 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 208 | - ); | ||
| 209 | - | ||
| 210 | - /** | ||
| 211 | - * Subscribe to a topic with a pattern. | ||
| 212 | - * | ||
| 213 | - * msg_callback: invoked whenever a message is received. | ||
| 214 | - * sub_callback: invoked when successfully subscribed | ||
| 215 | - * err_callback: invoked on some error state | ||
| 216 | - */ | ||
| 217 | - void psubscribe(const std::string topic, | ||
| 218 | - std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 219 | - std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 220 | - std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 221 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 222 | - ); | ||
| 223 | - | ||
| 224 | /** | 157 | /** |
| 225 | * Publish to a topic. All subscribers will be notified. | 158 | * Publish to a topic. All subscribers will be notified. |
| 226 | * | 159 | * |
| 227 | * pub_callback: invoked when successfully published | 160 | * pub_callback: invoked when successfully published |
| 228 | * err_callback: invoked on some error state | 161 | * err_callback: invoked on some error state |
| 229 | - */ | ||
| 230 | - void publish(const std::string topic, const std::string msg, | ||
| 231 | - std::function<void(const std::string&, const std::string&)> pub_callback = nullptr, | ||
| 232 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 233 | - ); | ||
| 234 | - | ||
| 235 | - /** | ||
| 236 | - * Unsubscribe from a topic. | ||
| 237 | * | 162 | * |
| 238 | - * err_callback: invoked on some error state | 163 | + * // TODO |
| 239 | */ | 164 | */ |
| 240 | - void unsubscribe(const std::string topic, | ||
| 241 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 242 | - ); | ||
| 243 | - | ||
| 244 | - /** | ||
| 245 | - * Unsubscribe from a topic with a pattern. | ||
| 246 | - * | ||
| 247 | - * err_callback: invoked on some error state | ||
| 248 | - */ | ||
| 249 | - void punsubscribe(const std::string topic, | ||
| 250 | - std::function<void(const std::string&, int)> err_callback = nullptr | 165 | + void publish(const std::string topic, const std::string msg, |
| 166 | + std::function<void(const std::string&, const std::string&)> pub_callback = nullptr, | ||
| 167 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 251 | ); | 168 | ); |
| 252 | 169 | ||
| 253 | - const std::set<std::string>& subscribed_topics() { return subscribed_topics_; } | ||
| 254 | - const std::set<std::string>& psubscribed_topics() { return psubscribed_topics_; } | ||
| 255 | - | ||
| 256 | // ------------------------------------------------ | 170 | // ------------------------------------------------ |
| 257 | // Public only for Command class | 171 | // Public only for Command class |
| 258 | // ------------------------------------------------ | 172 | // ------------------------------------------------ |
| @@ -260,20 +174,23 @@ public: | @@ -260,20 +174,23 @@ public: | ||
| 260 | // Invoked by Command objects when they are completed | 174 | // Invoked by Command objects when they are completed |
| 261 | template<class ReplyT> | 175 | template<class ReplyT> |
| 262 | void remove_active_command(const long id) { | 176 | void remove_active_command(const long id) { |
| 263 | - std::lock_guard<std::mutex> lg1(command_map_guard); | ||
| 264 | - get_command_map<ReplyT>().erase(id); | ||
| 265 | - commands_deleted += 1; | 177 | + std::lock_guard<std::mutex> lg1(command_map_guard_); |
| 178 | + getCommandMap<ReplyT>().erase(id); | ||
| 179 | + commands_deleted_ += 1; | ||
| 266 | } | 180 | } |
| 267 | 181 | ||
| 182 | + // Hiredis context, left public to allow low-level access | ||
| 183 | + redisAsyncContext * ctx_; | ||
| 184 | + | ||
| 268 | // Redox server over TCP | 185 | // Redox server over TCP |
| 269 | - const std::string host; | ||
| 270 | - const int port; | 186 | + const std::string host_; |
| 187 | + const int port_; | ||
| 271 | 188 | ||
| 272 | // Redox server over unix | 189 | // Redox server over unix |
| 273 | - const std::string path; | 190 | + const std::string path_; |
| 274 | 191 | ||
| 275 | // Logger | 192 | // Logger |
| 276 | - log::Logger logger; | 193 | + log::Logger logger_; |
| 277 | 194 | ||
| 278 | private: | 195 | private: |
| 279 | 196 | ||
| @@ -291,108 +208,90 @@ private: | @@ -291,108 +208,90 @@ private: | ||
| 291 | void init_hiredis(); | 208 | void init_hiredis(); |
| 292 | 209 | ||
| 293 | // Manage connection state | 210 | // Manage connection state |
| 294 | - std::atomic_int connect_state = {REDOX_NOT_YET_CONNECTED}; | ||
| 295 | - std::mutex connect_lock; | ||
| 296 | - std::condition_variable connect_waiter; | 211 | + std::atomic_int connect_state_ = {NOT_YET_CONNECTED}; |
| 212 | + std::mutex connect_lock_; | ||
| 213 | + std::condition_variable connect_waiter_; | ||
| 297 | 214 | ||
| 298 | // User connect/disconnect callbacks | 215 | // User connect/disconnect callbacks |
| 299 | - std::function<void(int)> user_connection_callback; | 216 | + std::function<void(int)> user_connection_callback_; |
| 300 | 217 | ||
| 301 | // Dynamically allocated libev event loop | 218 | // Dynamically allocated libev event loop |
| 302 | - struct ev_loop* evloop; | 219 | + struct ev_loop* evloop_; |
| 303 | 220 | ||
| 304 | // Asynchronous watchers | 221 | // Asynchronous watchers |
| 305 | - ev_async async_w; // For processing commands | ||
| 306 | - ev_async async_stop; // For breaking the loop | ||
| 307 | - | ||
| 308 | - // Number of commands processed | ||
| 309 | - std::atomic_long cmd_count = {0}; | 222 | + ev_async watcher_command_; // For processing commands |
| 223 | + ev_async watcher_stop_; // For breaking the loop | ||
| 310 | 224 | ||
| 311 | // Track of Command objects allocated. Also provides unique Command IDs. | 225 | // Track of Command objects allocated. Also provides unique Command IDs. |
| 312 | - std::atomic_long commands_created = {0}; | ||
| 313 | - std::atomic_long commands_deleted = {0}; | 226 | + std::atomic_long commands_created_ = {0}; |
| 227 | + std::atomic_long commands_deleted_ = {0}; | ||
| 314 | 228 | ||
| 315 | // Separate thread to have a non-blocking event loop | 229 | // Separate thread to have a non-blocking event loop |
| 316 | - std::thread event_loop_thread; | 230 | + std::thread event_loop_thread_; |
| 317 | 231 | ||
| 318 | // Variable and CV to know when the event loop starts running | 232 | // Variable and CV to know when the event loop starts running |
| 319 | - std::atomic_bool running = {false}; | ||
| 320 | - std::mutex running_waiter_lock; | ||
| 321 | - std::condition_variable running_waiter; | 233 | + std::atomic_bool running_ = {false}; |
| 234 | + std::mutex running_waiter_lock_; | ||
| 235 | + std::condition_variable running_waiter_; | ||
| 322 | 236 | ||
| 323 | // Variable and CV to know when the event loop stops running | 237 | // Variable and CV to know when the event loop stops running |
| 324 | - std::atomic_bool to_exit = {false}; // Signal to exit | ||
| 325 | - std::atomic_bool exited = {false}; // Event thread exited | ||
| 326 | - std::mutex exit_waiter_lock; | ||
| 327 | - std::condition_variable exit_waiter; | 238 | + std::atomic_bool to_exit_ = {false}; // Signal to exit |
| 239 | + std::atomic_bool exited_ = {false}; // Event thread exited | ||
| 240 | + std::mutex exit_waiter_lock_; | ||
| 241 | + std::condition_variable exit_waiter_; | ||
| 328 | 242 | ||
| 329 | // Maps of each Command, fetchable by the unique ID number | 243 | // Maps of each Command, fetchable by the unique ID number |
| 330 | - std::unordered_map<long, Command<redisReply*>*> commands_redis_reply; | ||
| 331 | - std::unordered_map<long, Command<std::string>*> commands_string_r; | ||
| 332 | - std::unordered_map<long, Command<char*>*> commands_char_p; | ||
| 333 | - std::unordered_map<long, Command<int>*> commands_int; | ||
| 334 | - std::unordered_map<long, Command<long long int>*> commands_long_long_int; | ||
| 335 | - std::unordered_map<long, Command<std::nullptr_t>*> commands_null; | ||
| 336 | - std::unordered_map<long, Command<std::vector<std::string>>*> commands_vector_string; | ||
| 337 | - std::unordered_map<long, Command<std::set<std::string>>*> commands_set_string; | ||
| 338 | - std::unordered_map<long, Command<std::unordered_set<std::string>>*> commands_unordered_set_string; | ||
| 339 | - std::mutex command_map_guard; // Guards access to all of the above | 244 | + // In C++14, member variable templates will replace all of these types |
| 245 | + // with a single templated declaration | ||
| 246 | + // --------- | ||
| 247 | + // template<class ReplyT> | ||
| 248 | + // std::unordered_map<long, Command<ReplyT>*> commands_; | ||
| 249 | + // --------- | ||
| 250 | + std::unordered_map<long, Command<redisReply*>*> commands_redis_reply_; | ||
| 251 | + std::unordered_map<long, Command<std::string>*> commands_string_; | ||
| 252 | + std::unordered_map<long, Command<char*>*> commands_char_p_; | ||
| 253 | + std::unordered_map<long, Command<int>*> commands_int_; | ||
| 254 | + std::unordered_map<long, Command<long long int>*> commands_long_long_int_; | ||
| 255 | + std::unordered_map<long, Command<std::nullptr_t>*> commands_null_; | ||
| 256 | + std::unordered_map<long, Command<std::vector<std::string>>*> commands_vector_string_; | ||
| 257 | + std::unordered_map<long, Command<std::set<std::string>>*> commands_set_string_; | ||
| 258 | + std::unordered_map<long, Command<std::unordered_set<std::string>>*> commands_unordered_set_string_; | ||
| 259 | + std::mutex command_map_guard_; // Guards access to all of the above | ||
| 340 | 260 | ||
| 341 | // Return the correct map from the above, based on the template specialization | 261 | // Return the correct map from the above, based on the template specialization |
| 342 | template<class ReplyT> | 262 | template<class ReplyT> |
| 343 | - std::unordered_map<long, Command<ReplyT>*>& get_command_map(); | 263 | + std::unordered_map<long, Command<ReplyT>*>& getCommandMap(); |
| 344 | 264 | ||
| 345 | // Return the given Command from the relevant command map, or nullptr if not there | 265 | // Return the given Command from the relevant command map, or nullptr if not there |
| 346 | template<class ReplyT> | 266 | template<class ReplyT> |
| 347 | - Command<ReplyT>* find_command(long id); | 267 | + Command<ReplyT>* findCommand(long id); |
| 348 | 268 | ||
| 349 | std::queue<long> command_queue; | 269 | std::queue<long> command_queue; |
| 350 | std::mutex queue_guard; | 270 | std::mutex queue_guard; |
| 351 | - static void process_queued_commands(struct ev_loop* loop, ev_async* async, int revents); | 271 | + static void proccessQueuedCommands(struct ev_loop* loop, ev_async* async, int revents); |
| 352 | 272 | ||
| 353 | template<class ReplyT> | 273 | template<class ReplyT> |
| 354 | - bool process_queued_command(long id); | 274 | + bool proccessQueuedCommand(long id); |
| 355 | 275 | ||
| 356 | - void run_event_loop(); | 276 | + void runEventLoop(); |
| 357 | 277 | ||
| 358 | // Callbacks invoked on server connection/disconnection | 278 | // Callbacks invoked on server connection/disconnection |
| 359 | - static void connected_callback(const redisAsyncContext *c, int status); | ||
| 360 | - static void disconnected_callback(const redisAsyncContext *c, int status); | 279 | + static void connectedCallback(const redisAsyncContext* c, int status); |
| 280 | + static void disconnectedCallback(const redisAsyncContext* c, int status); | ||
| 361 | 281 | ||
| 362 | template<class ReplyT> | 282 | template<class ReplyT> |
| 363 | - static void command_callback(redisAsyncContext *ctx, void *r, void *privdata); | 283 | + static void commandCallback(redisAsyncContext* ctx, void* r, void* privdata); |
| 364 | 284 | ||
| 365 | template<class ReplyT> | 285 | template<class ReplyT> |
| 366 | - static bool submit_to_server(Command<ReplyT>* c); | 286 | + static bool submitToServer(Command<ReplyT>* c); |
| 367 | 287 | ||
| 368 | template<class ReplyT> | 288 | template<class ReplyT> |
| 369 | - static void submit_command_callback(struct ev_loop* loop, ev_timer* timer, int revents); | 289 | + static void submitCommandCallback(struct ev_loop* loop, ev_timer* timer, int revents); |
| 370 | 290 | ||
| 371 | - void deny_non_pubsub(const std::string& cmd); | ||
| 372 | - | ||
| 373 | - // Base for subscribe and psubscribe | ||
| 374 | - void subscribe_raw(const std::string cmd_name, const std::string topic, | ||
| 375 | - std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 376 | - std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 377 | - std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 378 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 379 | - ); | ||
| 380 | - | ||
| 381 | - // Base for unsubscribe and punsubscribe | ||
| 382 | - void unsubscribe_raw(const std::string cmd_name, const std::string topic, | ||
| 383 | - std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 384 | - ); | ||
| 385 | - | ||
| 386 | - // Keep track of topics because we can only unsubscribe | ||
| 387 | - // from subscribed topics and punsubscribe from | ||
| 388 | - // psubscribed topics, or hiredis leads to segfaults | ||
| 389 | - std::set<std::string> subscribed_topics_; | ||
| 390 | - std::set<std::string> psubscribed_topics_; | ||
| 391 | }; | 291 | }; |
| 392 | 292 | ||
| 393 | // --------------------------- | 293 | // --------------------------- |
| 394 | 294 | ||
| 395 | - | ||
| 396 | template<class ReplyT> | 295 | template<class ReplyT> |
| 397 | Command<ReplyT>& Redox::createCommand( | 296 | Command<ReplyT>& Redox::createCommand( |
| 398 | const std::string& cmd, | 297 | const std::string& cmd, |
| @@ -402,27 +301,22 @@ Command<ReplyT>& Redox::createCommand( | @@ -402,27 +301,22 @@ Command<ReplyT>& Redox::createCommand( | ||
| 402 | bool free_memory | 301 | bool free_memory |
| 403 | ) { | 302 | ) { |
| 404 | 303 | ||
| 405 | - if(!running) { | ||
| 406 | - throw std::runtime_error("[ERROR] Need to start Redox before running commands!"); | ||
| 407 | - } | ||
| 408 | - | ||
| 409 | - // Block if pubsub mode | ||
| 410 | - if(pubsub_mode) { | ||
| 411 | - deny_non_pubsub(cmd); | 304 | + if(!running_) { |
| 305 | + throw std::runtime_error("[ERROR] Need to connect Redox before running commands!"); | ||
| 412 | } | 306 | } |
| 413 | 307 | ||
| 414 | - commands_created += 1; | ||
| 415 | - auto* c = new Command<ReplyT>(this, commands_created, cmd, | ||
| 416 | - callback, repeat, after, free_memory, logger); | 308 | + commands_created_ += 1; |
| 309 | + auto* c = new Command<ReplyT>(this, commands_created_, cmd, | ||
| 310 | + callback, repeat, after, free_memory, logger_); | ||
| 417 | 311 | ||
| 418 | std::lock_guard<std::mutex> lg(queue_guard); | 312 | std::lock_guard<std::mutex> lg(queue_guard); |
| 419 | - std::lock_guard<std::mutex> lg2(command_map_guard); | 313 | + std::lock_guard<std::mutex> lg2(command_map_guard_); |
| 420 | 314 | ||
| 421 | - get_command_map<ReplyT>()[c->id_] = c; | 315 | + getCommandMap<ReplyT>()[c->id_] = c; |
| 422 | command_queue.push(c->id_); | 316 | command_queue.push(c->id_); |
| 423 | 317 | ||
| 424 | // Signal the event loop to process this command | 318 | // Signal the event loop to process this command |
| 425 | - ev_async_send(evloop, &async_w); | 319 | + ev_async_send(evloop_, &watcher_command_); |
| 426 | 320 | ||
| 427 | // logger.debug() << "Created Command " << c->id << " at " << c; | 321 | // logger.debug() << "Created Command " << c->id << " at " << c; |
| 428 | 322 | ||
| @@ -438,7 +332,7 @@ void Redox::command( | @@ -438,7 +332,7 @@ void Redox::command( | ||
| 438 | } | 332 | } |
| 439 | 333 | ||
| 440 | template<class ReplyT> | 334 | template<class ReplyT> |
| 441 | -Command<ReplyT>& Redox::command_looping( | 335 | +Command<ReplyT>& Redox::commandLoop( |
| 442 | const std::string& cmd, | 336 | const std::string& cmd, |
| 443 | const std::function<void(Command<ReplyT>&)>& callback, | 337 | const std::function<void(Command<ReplyT>&)>& callback, |
| 444 | double repeat, | 338 | double repeat, |
| @@ -448,7 +342,7 @@ Command<ReplyT>& Redox::command_looping( | @@ -448,7 +342,7 @@ Command<ReplyT>& Redox::command_looping( | ||
| 448 | } | 342 | } |
| 449 | 343 | ||
| 450 | template<class ReplyT> | 344 | template<class ReplyT> |
| 451 | -Command<ReplyT>& Redox::command_blocking(const std::string& cmd) { | 345 | +Command<ReplyT>& Redox::commandSync(const std::string& cmd) { |
| 452 | auto& c = createCommand<ReplyT>(cmd, nullptr, 0, 0, false); | 346 | auto& c = createCommand<ReplyT>(cmd, nullptr, 0, 0, false); |
| 453 | c.wait(); | 347 | c.wait(); |
| 454 | return c; | 348 | return c; |
src/subscriber.cpp
0 โ 100644
| 1 | +/** | ||
| 2 | +* Redis C++11 wrapper. | ||
| 3 | +*/ | ||
| 4 | + | ||
| 5 | +#include <string.h> | ||
| 6 | +#include "subscriber.hpp" | ||
| 7 | + | ||
| 8 | +using namespace std; | ||
| 9 | + | ||
| 10 | +namespace redox { | ||
| 11 | + | ||
| 12 | +Subscriber::Subscriber( | ||
| 13 | + const std::string& host, const int port, | ||
| 14 | + std::function<void(int)> connection_callback, | ||
| 15 | + std::ostream& log_stream, log::Level log_level | ||
| 16 | +) : rdx_(host, port, connection_callback, log_stream, log_level), | ||
| 17 | + logger_(rdx_.logger_) {} | ||
| 18 | + | ||
| 19 | +Subscriber::Subscriber( | ||
| 20 | + const std::string& path, | ||
| 21 | + std::function<void(int)> connection_callback, | ||
| 22 | + std::ostream& log_stream, log::Level log_level | ||
| 23 | +) : rdx_(path, connection_callback, log_stream, log_level), | ||
| 24 | + logger_(rdx_.logger_) {} | ||
| 25 | + | ||
| 26 | + | ||
| 27 | +// For debugging only | ||
| 28 | +void debugReply(Command<redisReply*> c) { | ||
| 29 | + | ||
| 30 | + redisReply* reply = c.reply(); | ||
| 31 | + | ||
| 32 | + cout << "------" << endl; | ||
| 33 | + cout << c.cmd() << " " << (reply->type == REDIS_REPLY_ARRAY) << " " << (reply->elements) << endl; | ||
| 34 | + for(size_t i = 0; i < reply->elements; i++) { | ||
| 35 | + redisReply* r = reply->element[i]; | ||
| 36 | + cout << "element " << i << ", reply type = " << r->type << " "; | ||
| 37 | + if(r->type == REDIS_REPLY_STRING) cout << r->str << endl; | ||
| 38 | + else if(r->type == REDIS_REPLY_INTEGER) cout << r->integer << endl; | ||
| 39 | + else cout << "some other type" << endl; | ||
| 40 | + } | ||
| 41 | + cout << "------" << endl; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +void Subscriber::subscribeBase(const string cmd_name, const string topic, | ||
| 45 | + function<void(const string&, const string&)> msg_callback, | ||
| 46 | + function<void(const string&)> sub_callback, | ||
| 47 | + function<void(const string&)> unsub_callback, | ||
| 48 | + function<void(const string&, int)> err_callback | ||
| 49 | +) { | ||
| 50 | + | ||
| 51 | + rdx_.commandLoop<redisReply*>(cmd_name + " " + topic, | ||
| 52 | + [this, topic, msg_callback, err_callback, sub_callback, unsub_callback](Command<redisReply*>& c) { | ||
| 53 | + | ||
| 54 | + if (!c.ok()) { | ||
| 55 | + if (err_callback) err_callback(topic, c.status()); | ||
| 56 | + return; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + redisReply* reply = c.reply(); | ||
| 60 | + | ||
| 61 | + // TODO cancel this command on unsubscription? | ||
| 62 | + | ||
| 63 | + // If the last entry is an integer, then it is a [p]sub/[p]unsub command | ||
| 64 | + if ((reply->type == REDIS_REPLY_ARRAY) && | ||
| 65 | + (reply->element[reply->elements - 1]->type == REDIS_REPLY_INTEGER)) { | ||
| 66 | + | ||
| 67 | + if (!strncmp(reply->element[0]->str, "sub", 3)) { | ||
| 68 | + subscribed_topics_.insert(topic); | ||
| 69 | + if (sub_callback) sub_callback(topic); | ||
| 70 | + | ||
| 71 | + } else if (!strncmp(reply->element[0]->str, "psub", 4)) { | ||
| 72 | + psubscribed_topics_.insert(topic); | ||
| 73 | + if (sub_callback) sub_callback(topic); | ||
| 74 | + | ||
| 75 | + } else if (!strncmp(reply->element[0]->str, "uns", 3)) { | ||
| 76 | + subscribed_topics_.erase(topic); | ||
| 77 | + if (unsub_callback) unsub_callback(topic); | ||
| 78 | + | ||
| 79 | + } else if (!strncmp(reply->element[0]->str, "puns", 4)) { | ||
| 80 | + psubscribed_topics_.erase(topic); | ||
| 81 | + if (unsub_callback) unsub_callback(topic); | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + else logger_.error() << "Unknown pubsub message: " << reply->element[0]->str; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + // Message for subscribe | ||
| 88 | + else if ((reply->type == REDIS_REPLY_ARRAY) && (reply->elements == 3)) { | ||
| 89 | + char* msg = reply->element[2]->str; | ||
| 90 | + if (msg && msg_callback) msg_callback(topic, reply->element[2]->str); | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + // Message for psubscribe | ||
| 94 | + else if ((reply->type == REDIS_REPLY_ARRAY) && (reply->elements == 4)) { | ||
| 95 | + char* msg = reply->element[2]->str; | ||
| 96 | + if (msg && msg_callback) msg_callback(reply->element[2]->str, reply->element[3]->str); | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + else logger_.error() << "Unknown pubsub message of type " << reply->type; | ||
| 100 | + }, | ||
| 101 | + 1e10 // To keep the command around for a few hundred years | ||
| 102 | + ); | ||
| 103 | +} | ||
| 104 | + | ||
| 105 | +void Subscriber::subscribe(const string topic, | ||
| 106 | + function<void(const string&, const string&)> msg_callback, | ||
| 107 | + function<void(const string&)> sub_callback, | ||
| 108 | + function<void(const string&)> unsub_callback, | ||
| 109 | + function<void(const string&, int)> err_callback | ||
| 110 | +) { | ||
| 111 | + if(subscribed_topics_.find(topic) != subscribed_topics_.end()) { | ||
| 112 | + logger_.warning() << "Already subscribed to " << topic << "!"; | ||
| 113 | + return; | ||
| 114 | + } | ||
| 115 | + subscribeBase("SUBSCRIBE", topic, msg_callback, sub_callback, unsub_callback, err_callback); | ||
| 116 | +} | ||
| 117 | + | ||
| 118 | +void Subscriber::psubscribe(const string topic, | ||
| 119 | + function<void(const string&, const string&)> msg_callback, | ||
| 120 | + function<void(const string&)> sub_callback, | ||
| 121 | + function<void(const string&)> unsub_callback, | ||
| 122 | + function<void(const string&, int)> err_callback | ||
| 123 | +) { | ||
| 124 | + if(psubscribed_topics_.find(topic) != psubscribed_topics_.end()) { | ||
| 125 | + logger_.warning() << "Already psubscribed to " << topic << "!"; | ||
| 126 | + return; | ||
| 127 | + } | ||
| 128 | + subscribeBase("PSUBSCRIBE", topic, msg_callback, sub_callback, unsub_callback, err_callback); | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +void Subscriber::unsubscribeBase(const string cmd_name, const string topic, | ||
| 132 | + function<void(const string&, int)> err_callback | ||
| 133 | +) { | ||
| 134 | + rdx_.command<redisReply*>(cmd_name + " " + topic, | ||
| 135 | + [topic, err_callback](Command<redisReply*>& c) { | ||
| 136 | + if(!c.ok()) { | ||
| 137 | + if (err_callback) err_callback(topic, c.status()); | ||
| 138 | + } | ||
| 139 | + } | ||
| 140 | + ); | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +void Subscriber::unsubscribe(const string topic, | ||
| 144 | + function<void(const string&, int)> err_callback | ||
| 145 | +) { | ||
| 146 | + if(subscribed_topics_.find(topic) == subscribed_topics_.end()) { | ||
| 147 | + logger_.warning() << "Cannot unsubscribe from " << topic << ", not subscribed!"; | ||
| 148 | + return; | ||
| 149 | + } | ||
| 150 | + unsubscribeBase("UNSUBSCRIBE", topic, err_callback); | ||
| 151 | +} | ||
| 152 | + | ||
| 153 | +void Subscriber::punsubscribe(const string topic, | ||
| 154 | + function<void(const string&, int)> err_callback | ||
| 155 | +) { | ||
| 156 | + if(psubscribed_topics_.find(topic) == psubscribed_topics_.end()) { | ||
| 157 | + logger_.warning() << "Cannot punsubscribe from " << topic << ", not psubscribed!"; | ||
| 158 | + return; | ||
| 159 | + } | ||
| 160 | + unsubscribeBase("PUNSUBSCRIBE", topic, err_callback); | ||
| 161 | +} | ||
| 162 | + | ||
| 163 | +} // End namespace |
src/subscriber.hpp
0 โ 100644
| 1 | +/** | ||
| 2 | +* Redis C++11 wrapper. | ||
| 3 | +*/ | ||
| 4 | + | ||
| 5 | +#pragma once | ||
| 6 | + | ||
| 7 | +#include "redox.hpp" | ||
| 8 | + | ||
| 9 | +namespace redox { | ||
| 10 | + | ||
| 11 | +class Subscriber { | ||
| 12 | + | ||
| 13 | +public: | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * Initializes everything, connects over TCP to a Redis server. | ||
| 17 | + */ | ||
| 18 | + Subscriber( | ||
| 19 | + const std::string& host = REDIS_DEFAULT_HOST, | ||
| 20 | + const int port = REDIS_DEFAULT_PORT, | ||
| 21 | + std::function<void(int)> connection_callback = nullptr, | ||
| 22 | + std::ostream& log_stream = std::cout, | ||
| 23 | + log::Level log_level = log::Info | ||
| 24 | + ); | ||
| 25 | + | ||
| 26 | + /** | ||
| 27 | + * Initializes everything, connects over unix sockets to a Redis server. | ||
| 28 | + */ | ||
| 29 | + Subscriber( | ||
| 30 | + const std::string& path, | ||
| 31 | + std::function<void(int)> connection_callback, | ||
| 32 | + std::ostream& log_stream = std::cout, | ||
| 33 | + log::Level log_level = log::Info | ||
| 34 | + ); | ||
| 35 | + | ||
| 36 | + /** | ||
| 37 | + * Same as .connect() on a Redox instance. | ||
| 38 | + */ | ||
| 39 | + bool connect() { return rdx_.connect(); } | ||
| 40 | + | ||
| 41 | + /** | ||
| 42 | + * Same as .disconnect() on a Redox instance. | ||
| 43 | + */ | ||
| 44 | + void disconnect() { return rdx_.disconnect(); } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * Same as .wait() on a Redox instance. | ||
| 48 | + */ | ||
| 49 | + void wait() { return rdx_.wait(); } | ||
| 50 | + | ||
| 51 | + /** | ||
| 52 | + * Subscribe to a topic. | ||
| 53 | + * | ||
| 54 | + * msg_callback: invoked whenever a message is received. | ||
| 55 | + * sub_callback: invoked when successfully subscribed | ||
| 56 | + * err_callback: invoked on some error state | ||
| 57 | + */ | ||
| 58 | + void subscribe(const std::string topic, | ||
| 59 | + std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 60 | + std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 61 | + std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 62 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 63 | + ); | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Subscribe to a topic with a pattern. | ||
| 67 | + * | ||
| 68 | + * msg_callback: invoked whenever a message is received. | ||
| 69 | + * sub_callback: invoked when successfully subscribed | ||
| 70 | + * err_callback: invoked on some error state | ||
| 71 | + */ | ||
| 72 | + void psubscribe(const std::string topic, | ||
| 73 | + std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 74 | + std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 75 | + std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 76 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 77 | + ); | ||
| 78 | + | ||
| 79 | + /** | ||
| 80 | + * Unsubscribe from a topic. | ||
| 81 | + * | ||
| 82 | + * err_callback: invoked on some error state | ||
| 83 | + */ | ||
| 84 | + void unsubscribe(const std::string topic, | ||
| 85 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 86 | + ); | ||
| 87 | + | ||
| 88 | + /** | ||
| 89 | + * Unsubscribe from a topic with a pattern. | ||
| 90 | + * | ||
| 91 | + * err_callback: invoked on some error state | ||
| 92 | + */ | ||
| 93 | + void punsubscribe(const std::string topic, | ||
| 94 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 95 | + ); | ||
| 96 | + | ||
| 97 | + /** | ||
| 98 | + * Return the topics that were subscribed() to. | ||
| 99 | + */ | ||
| 100 | + const std::set<std::string>& subscribedTopics() { return subscribed_topics_; } | ||
| 101 | + | ||
| 102 | + /** | ||
| 103 | + * Return the topic patterns that were psubscribed() to. | ||
| 104 | + */ | ||
| 105 | + const std::set<std::string>& psubscribedTopics() { return psubscribed_topics_; } | ||
| 106 | + | ||
| 107 | +private: | ||
| 108 | + | ||
| 109 | + // Base for subscribe and psubscribe | ||
| 110 | + void subscribeBase(const std::string cmd_name, const std::string topic, | ||
| 111 | + std::function<void(const std::string&, const std::string&)> msg_callback, | ||
| 112 | + std::function<void(const std::string&)> sub_callback = nullptr, | ||
| 113 | + std::function<void(const std::string&)> unsub_callback = nullptr, | ||
| 114 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 115 | + ); | ||
| 116 | + | ||
| 117 | + // Base for unsubscribe and punsubscribe | ||
| 118 | + void unsubscribeBase(const std::string cmd_name, const std::string topic, | ||
| 119 | + std::function<void(const std::string&, int)> err_callback = nullptr | ||
| 120 | + ); | ||
| 121 | + | ||
| 122 | + // Underlying Redis client | ||
| 123 | + Redox rdx_; | ||
| 124 | + | ||
| 125 | + // Keep track of topics because we can only unsubscribe | ||
| 126 | + // from subscribed topics and punsubscribe from | ||
| 127 | + // psubscribed topics, or hiredis leads to segfaults | ||
| 128 | + std::set<std::string> subscribed_topics_; | ||
| 129 | + std::set<std::string> psubscribed_topics_; | ||
| 130 | + | ||
| 131 | + // Reference to rdx_.logger_ for convenience | ||
| 132 | + log::Logger& logger_; | ||
| 133 | +}; | ||
| 134 | + | ||
| 135 | +} // End namespace |
test/test.cpp
| @@ -25,18 +25,13 @@ protected: | @@ -25,18 +25,13 @@ protected: | ||
| 25 | RedoxTest() { | 25 | RedoxTest() { |
| 26 | 26 | ||
| 27 | // Connect to the server | 27 | // Connect to the server |
| 28 | - rdx.start(); | 28 | + rdx.connect(); |
| 29 | 29 | ||
| 30 | // Clear all keys used by the tests here | 30 | // Clear all keys used by the tests here |
| 31 | rdx.command("DEL redox_test:a"); | 31 | rdx.command("DEL redox_test:a"); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | - virtual ~RedoxTest() { | ||
| 35 | - | ||
| 36 | - // Block until the event loop exits. | ||
| 37 | - // Each test is responsible for calling the stop_signal() | ||
| 38 | - rdx.block(); | ||
| 39 | - } | 34 | + virtual ~RedoxTest() { } |
| 40 | 35 | ||
| 41 | // CV and counter to wait for async commands to complete | 36 | // CV and counter to wait for async commands to complete |
| 42 | atomic_int cmd_count = {0}; | 37 | atomic_int cmd_count = {0}; |
| @@ -85,10 +80,9 @@ protected: | @@ -85,10 +80,9 @@ protected: | ||
| 85 | * Wait until all async commands that used check() as a callback | 80 | * Wait until all async commands that used check() as a callback |
| 86 | * complete. | 81 | * complete. |
| 87 | */ | 82 | */ |
| 88 | - void wait_and_stop() { | 83 | + void wait_for_replies() { |
| 89 | unique_lock<mutex> ul(cmd_waiter_lock); | 84 | unique_lock<mutex> ul(cmd_waiter_lock); |
| 90 | cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); | 85 | cmd_waiter.wait(ul, [this] { return (cmd_count == 0); }); |
| 91 | - rdx.stop_signal(); | ||
| 92 | }; | 86 | }; |
| 93 | 87 | ||
| 94 | template<class ReplyT> | 88 | template<class ReplyT> |
| @@ -114,14 +108,14 @@ protected: | @@ -114,14 +108,14 @@ protected: | ||
| 114 | TEST_F(RedoxTest, GetSet) { | 108 | TEST_F(RedoxTest, GetSet) { |
| 115 | rdx.command<string>("SET redox_test:a apple", print_and_check<string>("OK")); | 109 | rdx.command<string>("SET redox_test:a apple", print_and_check<string>("OK")); |
| 116 | rdx.command<string>("GET redox_test:a", print_and_check<string>("apple")); | 110 | rdx.command<string>("GET redox_test:a", print_and_check<string>("apple")); |
| 117 | - wait_and_stop(); | 111 | + wait_for_replies(); |
| 118 | } | 112 | } |
| 119 | 113 | ||
| 120 | TEST_F(RedoxTest, Delete) { | 114 | TEST_F(RedoxTest, Delete) { |
| 121 | rdx.command<string>("SET redox_test:a apple", print_and_check<string>("OK")); | 115 | rdx.command<string>("SET redox_test:a apple", print_and_check<string>("OK")); |
| 122 | rdx.command<int>("DEL redox_test:a", print_and_check(1)); | 116 | rdx.command<int>("DEL redox_test:a", print_and_check(1)); |
| 123 | rdx.command<nullptr_t>("GET redox_test:a", check(nullptr)); | 117 | rdx.command<nullptr_t>("GET redox_test:a", check(nullptr)); |
| 124 | - wait_and_stop(); | 118 | + wait_for_replies(); |
| 125 | } | 119 | } |
| 126 | 120 | ||
| 127 | TEST_F(RedoxTest, Incr) { | 121 | TEST_F(RedoxTest, Incr) { |
| @@ -130,22 +124,22 @@ TEST_F(RedoxTest, Incr) { | @@ -130,22 +124,22 @@ TEST_F(RedoxTest, Incr) { | ||
| 130 | rdx.command<int>("INCR redox_test:a", check(i+1)); | 124 | rdx.command<int>("INCR redox_test:a", check(i+1)); |
| 131 | } | 125 | } |
| 132 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(count))); | 126 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(count))); |
| 133 | - wait_and_stop(); | 127 | + wait_for_replies(); |
| 134 | } | 128 | } |
| 135 | 129 | ||
| 136 | TEST_F(RedoxTest, Delayed) { | 130 | TEST_F(RedoxTest, Delayed) { |
| 137 | - Command<int>& c = rdx.command_looping<int>("INCR redox_test:a", check(1), 0, 0.1); | 131 | + Command<int>& c = rdx.commandLoop<int>("INCR redox_test:a", check(1), 0, 0.1); |
| 138 | this_thread::sleep_for(chrono::milliseconds(150)); | 132 | this_thread::sleep_for(chrono::milliseconds(150)); |
| 139 | c.cancel(); | 133 | c.cancel(); |
| 140 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(1))); | 134 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(1))); |
| 141 | - wait_and_stop(); | 135 | + wait_for_replies(); |
| 142 | } | 136 | } |
| 143 | 137 | ||
| 144 | TEST_F(RedoxTest, Loop) { | 138 | TEST_F(RedoxTest, Loop) { |
| 145 | int count = 0; | 139 | int count = 0; |
| 146 | int target_count = 100; | 140 | int target_count = 100; |
| 147 | double dt = 0.001; | 141 | double dt = 0.001; |
| 148 | - Command<int>& cmd = rdx.command_looping<int>("INCR redox_test:a", | 142 | + Command<int>& cmd = rdx.commandLoop<int>("INCR redox_test:a", |
| 149 | [this, &count](Command<int>& c) { | 143 | [this, &count](Command<int>& c) { |
| 150 | check(++count)(c); | 144 | check(++count)(c); |
| 151 | }, | 145 | }, |
| @@ -157,7 +151,7 @@ TEST_F(RedoxTest, Loop) { | @@ -157,7 +151,7 @@ TEST_F(RedoxTest, Loop) { | ||
| 157 | cmd.cancel(); | 151 | cmd.cancel(); |
| 158 | 152 | ||
| 159 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(target_count))); | 153 | rdx.command<string>("GET redox_test:a", print_and_check(to_string(target_count))); |
| 160 | - wait_and_stop(); | 154 | + wait_for_replies(); |
| 161 | } | 155 | } |
| 162 | 156 | ||
| 163 | // ------------------------------------------- | 157 | // ------------------------------------------- |
| @@ -165,25 +159,22 @@ TEST_F(RedoxTest, Loop) { | @@ -165,25 +159,22 @@ TEST_F(RedoxTest, Loop) { | ||
| 165 | // ------------------------------------------- | 159 | // ------------------------------------------- |
| 166 | 160 | ||
| 167 | TEST_F(RedoxTest, GetSetSync) { | 161 | TEST_F(RedoxTest, GetSetSync) { |
| 168 | - print_and_check_sync<string>(rdx.command_blocking<string>("SET redox_test:a apple"), "OK"); | ||
| 169 | - print_and_check_sync<string>(rdx.command_blocking<string>("GET redox_test:a"), "apple"); | ||
| 170 | - rdx.stop_signal(); | 162 | + print_and_check_sync<string>(rdx.commandSync<string>("SET redox_test:a apple"), "OK"); |
| 163 | + print_and_check_sync<string>(rdx.commandSync<string>("GET redox_test:a"), "apple"); | ||
| 171 | } | 164 | } |
| 172 | 165 | ||
| 173 | TEST_F(RedoxTest, DeleteSync) { | 166 | TEST_F(RedoxTest, DeleteSync) { |
| 174 | - print_and_check_sync<string>(rdx.command_blocking<string>("SET redox_test:a apple"), "OK"); | ||
| 175 | - print_and_check_sync(rdx.command_blocking<int>("DEL redox_test:a"), 1); | ||
| 176 | - check_sync(rdx.command_blocking<nullptr_t>("GET redox_test:a"), nullptr); | ||
| 177 | - rdx.stop_signal(); | 167 | + print_and_check_sync<string>(rdx.commandSync<string>("SET redox_test:a apple"), "OK"); |
| 168 | + print_and_check_sync(rdx.commandSync<int>("DEL redox_test:a"), 1); | ||
| 169 | + check_sync(rdx.commandSync<nullptr_t>("GET redox_test:a"), nullptr); | ||
| 178 | } | 170 | } |
| 179 | 171 | ||
| 180 | TEST_F(RedoxTest, IncrSync) { | 172 | TEST_F(RedoxTest, IncrSync) { |
| 181 | int count = 100; | 173 | int count = 100; |
| 182 | for(int i = 0; i < count; i++) { | 174 | for(int i = 0; i < count; i++) { |
| 183 | - check_sync(rdx.command_blocking<int>("INCR redox_test:a"), i+1); | 175 | + check_sync(rdx.commandSync<int>("INCR redox_test:a"), i+1); |
| 184 | } | 176 | } |
| 185 | - print_and_check_sync(rdx.command_blocking<string>("GET redox_test:a"), to_string(count)); | ||
| 186 | - rdx.stop_signal(); | 177 | + print_and_check_sync(rdx.commandSync<string>("GET redox_test:a"), to_string(count)); |
| 187 | } | 178 | } |
| 188 | 179 | ||
| 189 | // ------------------------------------------- | 180 | // ------------------------------------------- |