diff --git a/README.md b/README.md index 9530ef4..c8cfdf6 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ 1. 基于boost.asio 1. 支持string、list、set、hash、zset五种数据结构 1. 支持事务提交 +1. 新增实现redis锁 ## 说明 1. 使用c++11以及以上编译(若c++11编译不过,请用c++14) diff --git a/include/cppredis/client.hpp b/include/cppredis/client.hpp index dc8d4d7..9db8d53 100644 --- a/include/cppredis/client.hpp +++ b/include/cppredis/client.hpp @@ -228,14 +228,14 @@ namespace cpp_redis { int remainder_ttl(T&& key) { if (client_ == nullptr) { - return -1; + return 0; } reset(); any_type_to_string(key); if (keys_.empty()) { - return -1; + return 0; } return client_->remainder_ttl(std::move(keys_[0])); @@ -361,9 +361,29 @@ namespace cpp_redis { return client_->psetex(std::move(keys_[0]), std::move(keys_[1]),unit::int_to_string(milliseconds)); } - //ĸӿڣҪֹЩ汾֧setexĽӿ + //˽ӿ൱setnx 룬is_exist:true(NX) false(XX) + template + int setnx(T1&& key,T2&& value) + { + static_assert(is_sting_, "This API Support String Request"); + + if (client_ == nullptr) { + return 0; + } + + reset(); + any_type_to_string(key); + any_type_to_string(value); + + if (keys_.size() != 2) { + return 0; + } + + return client_->setnx(std::move(keys_[0]), std::move(keys_[1])); + } + template - bool set_has_seconds(T1&& key, T2&& value,std::size_t seconds) + bool setnx(T1&& key, T2&& value,std::size_t seconds) { static_assert(is_sting_, "This API Support String Request"); @@ -379,12 +399,11 @@ namespace cpp_redis { return false; } - return client_->set_has_seconds(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(seconds)); + return client_->setnx_has_seconds(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(seconds)); } - //˽ӿ൱setnx 룬is_exist:true(NX) false(XX) - template - bool set_has_seconds_if(T1&& key,T2&& value, std::size_t seconds,bool is_exist) + template + bool setxx(T1&& key, T2&& value, std::size_t seconds) { static_assert(is_sting_, "This API Support String Request"); @@ -400,11 +419,11 @@ namespace cpp_redis { return false; } - return client_->set_has_seconds_if(std::move(keys_[0]), std::move(keys_[1]),unit::int_to_string(seconds),is_exist); + return client_->setxx(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(seconds)); } - - template - bool set_has_milliseconds(T1&& key,T2&& value, std::size_t milliseconds) + + template + bool setnx_has_milliseconds(T1&& key, T2&& value,std::size_t milliseconds) { static_assert(is_sting_, "This API Support String Request"); @@ -420,12 +439,11 @@ namespace cpp_redis { return false; } - return client_->set_has_milliseconds(std::move(keys_[0]), std::move(keys_[1]),unit::int_to_string(milliseconds)); + return client_->setnx_has_milliseconds(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(milliseconds)); } - //is_exist:true(NX)false(XX) template - bool set_has_milliseconds_if(T1&& key, T2&& value,std::size_t milliseconds,bool is_exist) + bool setxx_has_milliseconds(T1&& key, T2&& value, std::size_t milliseconds) { static_assert(is_sting_, "This API Support String Request"); @@ -441,7 +459,7 @@ namespace cpp_redis { return false; } - return client_->set_has_milliseconds_if(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(milliseconds), is_exist); + return client_->setxx_has_milliseconds(std::move(keys_[0]), std::move(keys_[1]), unit::int_to_string(milliseconds)); } template @@ -537,7 +555,7 @@ namespace cpp_redis { } template - int decr(std::string&& key) + int decr(T&& key) { static_assert(is_sting_, "This API Support String Request"); if (client_ == nullptr) { diff --git a/include/cppredis/client_interface.hpp b/include/cppredis/client_interface.hpp index ddc35a1..afeb792 100644 --- a/include/cppredis/client_interface.hpp +++ b/include/cppredis/client_interface.hpp @@ -395,9 +395,9 @@ namespace cpp_redis { return false; } - virtual bool set_has_seconds(std::string&& key, std::string&& value,std::string&&seconds) + virtual int setnx(std::string&& key, std::string&& value) { - return false; + return 0; } virtual std::vector multi_get_keys(std::vector&& keys) @@ -415,19 +415,22 @@ namespace cpp_redis { return false; } - virtual bool set_has_seconds_if(std::string&& key, std::string&& value, - std::string&& seconds,bool is_exist) + virtual bool setnx_has_seconds(std::string&& key, std::string&& value,std::string&& seconds) + { + return false; + } + + virtual bool setxx(std::string&& key, std::string&& value, std::string&& seconds) { return false; } - virtual bool set_has_milliseconds(std::string&& key, std::string&& value,std::string&&milliseconds) + virtual bool setnx_has_milliseconds(std::string&& key, std::string&& value,std::string&& milliseconds) { return false; } - virtual bool set_has_milliseconds_if(std::string&& key, std::string&& value, - std::string&& milliseconds,bool is_exist) + virtual bool setxx_has_milliseconds(std::string&& key, std::string&& value, std::string&& milliseconds) { return false; } diff --git a/include/cppredis/cpp_define.h b/include/cppredis/cpp_define.h index da1a914..443aafa 100644 --- a/include/cppredis/cpp_define.h +++ b/include/cppredis/cpp_define.h @@ -7,7 +7,6 @@ namespace cpp_redis { const std::string g_crlf = "\r\n"; const std::string g_nil = "nil"; - constexpr std::uint16_t g_send_times = 500; //뵥λ /*****************************************************/ const std::string g_select_cmd = "SELECT"; const std::string g_auth_cmd = "AUTH"; @@ -28,6 +27,7 @@ namespace cpp_redis { /****************ַ***********************************/ const std::string g_setx_cmd = "SETEX"; const std::string g_psetx_cmd = "PSETEX"; + const std::string g_setnx_cmd = "SETNX"; const std::string g_set_cmd = "SET"; const std::string g_strsub_cmd = "GETRANGE";//2.0֮ǰsubstr const std::string g_incrby_cmd = "INCRBY"; @@ -129,98 +129,99 @@ namespace cpp_redis { select = 1, set = 2, setex = 3, - psetex = 4, - strsub = 5, - incr = 6, - incrby = 7, - incr_by_float = 8, - decr = 9, - decyby = 10, - del = 11, - exists = 12, - get = 13, - expire = 14, - pexpire = 15, - expire_at = 16, - pexpire_at = 17, - remove_expire = 18, - ttl = 19, - pttl = 20, - multi = 21, - exec = 22, - discard = 23, - rename = 24, - renamenx = 25, - get_set = 26, - substr = 27, - mget = 28, - mset = 29, - msetnx = 30, - append = 31, - rpush = 32, - lpush = 33, - llen = 34, - lrange = 35, - rpop = 36, - lpop = 37, - brpop = 38, - blpop = 39, - ltrim = 40, - lindex = 41, - lset = 42, - lrem = 43, - rpoplpush = 44, - lpushx = 45, - rpushx = 46, - list_insert = 47, - brpoplpush = 48, - sadd = 49, - srem = 50, - sismember = 51, - spop_elem = 52, - srandmember = 53, - smove = 54, - ssize = 55, - smembers = 56, - sinter = 57, - ssinter_store = 58, - sunion = 59, - ssunion_store = 60, - sdiff = 61, - sdiff_store = 62, - zset_add = 63, - zset_score = 64, - zset_incrby = 65, - zset_card = 66, - zset_count = 67, - zset_range = 68, - zset_rank = 69, - zset_rem = 70, - zset_revrank = 71, - zset_revrange = 72, - zset_lexcount = 73, - zset_rangebylex = 74, - zset_union_store = 75, - zset_inter_store = 76, - zset_range_score = 77, - zset_remrangebylex = 78, - zset_rerange_score = 79, - zset_remrangebyscore = 80, - zset_remrangeby_rank = 81, - hash_set = 82, - hash_setx = 83, - hash_exists = 84, - hash_get = 85, - hash_del = 86, - hash_len = 87, - hash_mset = 88, - hash_mget = 89, - hash_vals = 90, - hash_keys = 91, - hash_strlen = 92, - hash_incrby = 93, - hash_get_all = 94, - hash_incrby_float = 95, + setnx = 4, + psetex = 5, + strsub = 6, + incr = 7, + incrby = 8, + incr_by_float = 9, + decr = 10, + decyby = 11, + del = 12, + exists = 13, + get = 14, + expire = 15, + pexpire = 16, + expire_at = 17, + pexpire_at = 18, + remove_expire = 19, + ttl = 20, + pttl = 21, + multi = 22, + exec = 23, + discard = 24, + rename = 25, + renamenx = 26, + get_set = 27, + substr = 28, + mget = 29, + mset = 30, + msetnx = 31, + append = 32, + rpush = 33, + lpush = 34, + llen = 35, + lrange = 36, + rpop = 37, + lpop = 38, + brpop = 39, + blpop = 40, + ltrim = 41, + lindex = 42, + lset = 43, + lrem = 44, + rpoplpush = 45, + lpushx = 46, + rpushx = 47, + list_insert = 48, + brpoplpush = 49, + sadd = 50, + srem = 51, + sismember = 52, + spop_elem = 53, + srandmember = 54, + smove = 55, + ssize = 56, + smembers = 57, + sinter = 58, + ssinter_store = 59, + sunion = 60, + ssunion_store = 61, + sdiff = 62, + sdiff_store = 63, + zset_add = 64, + zset_score = 65, + zset_incrby = 66, + zset_card = 67, + zset_count = 68, + zset_range = 69, + zset_rank = 70, + zset_rem = 71, + zset_revrank = 72, + zset_revrange = 73, + zset_lexcount = 74, + zset_rangebylex = 75, + zset_union_store = 76, + zset_inter_store = 77, + zset_range_score = 78, + zset_remrangebylex = 79, + zset_rerange_score = 80, + zset_remrangebyscore = 81, + zset_remrangeby_rank = 82, + hash_set = 83, + hash_setx = 84, + hash_exists = 85, + hash_get = 86, + hash_del = 87, + hash_len = 88, + hash_mset = 89, + hash_mget = 90, + hash_vals = 91, + hash_keys = 92, + hash_strlen = 93, + hash_incrby = 94, + hash_get_all = 95, + hash_incrby_float = 96, }; enum request_type diff --git a/include/cppredis/cpp_redis_net.hpp b/include/cppredis/cpp_redis_net.hpp index 590f227..e61a2b0 100644 --- a/include/cppredis/cpp_redis_net.hpp +++ b/include/cppredis/cpp_redis_net.hpp @@ -1,10 +1,10 @@ #include #include #include -#include #include +#include #include "traits.hpp" -#include "unit.hpp" +#include "redis_unit.hpp" #include "cpp_redis_response.hpp" namespace cpp_redis { @@ -15,54 +15,40 @@ namespace cpp_redis { { try { - ios_ = cpp_redis::traits::make_unique(); + ios_ = cpp_redis::traits::make_unique(); socket_ = cpp_redis::traits::make_unique(*ios_); timer_ = cpp_redis::traits::make_unique(*ios_); - response_ =std::make_shared(); - thread_ = cpp_redis::traits::make_unique([this]() { - while (exit_){ - boost::system::error_code ec; - ios_->poll(ec); - if (ec){ - break; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } - }); + response_ = std::make_shared(); } - catch (const std::exception&ex) + catch (const std::exception & ex) { std::cout << ex.what() << std::endl; ios_ = nullptr; socket_ = nullptr; - thread_ = nullptr; response_ = nullptr; } } - + ~cpp_redis_net() { - exit_ = false; close(); - //̻߳Դֹ߳ - thread_->join(); + ios_->stop(); } /********ip,port,password,db_num********************/ template - bool connect_to(std::string&&ip,Args&&...args) + bool connect_to(std::string&& ip, Args&&...args) { - if (socket_ == nullptr || ios_ == nullptr){ + if (socket_ == nullptr || ios_ == nullptr) { return false; } constexpr auto size = sizeof...(args); - if (size >3){ + if (size > 3) { return false; } - if (!cpp_redis::unit::ip_v6_check(ip) && !cpp_redis::unit::ip_addr_check(ip)){ + if (!cpp_redis::unit::ip_v6_check(ip) && !cpp_redis::unit::ip_addr_check(ip)) { return false; } @@ -71,10 +57,12 @@ namespace cpp_redis { #if (_MSC_VER >=1500 && _MSC_VER<=1900) if (constexpr (sizeof...(args) == 1)) { port_ = std::move(std::get<0>(tp)); - }else if (constexpr (sizeof...(args) == 2)) { + } + else if (constexpr (sizeof...(args) == 2)) { port_ = std::move(std::get<0>(tp)); password_ = std::move(std::get<1>(tp)); - }else if (constexpr (sizeof...(args) == 3)) { + } + else if (constexpr (sizeof...(args) == 3)) { port_ = std::move(std::get<0>(tp)); password_ = std::move(std::get<1>(tp)); db_num_ = std::move(std::get<2>(tp)); @@ -83,21 +71,25 @@ namespace cpp_redis { #else if constexpr (sizeof...(args) == 1) { port_ = std::move(std::get<0>(tp)); - }else if constexpr (sizeof...(args) == 2){ + } + else if constexpr (sizeof...(args) == 2) { port_ = std::move(std::get<0>(tp)); password_ = std::move(std::get<1>(tp)); - }else if constexpr (sizeof...(args) == 3) { + } + else if constexpr (sizeof...(args) == 3) { port_ = std::move(std::get<0>(tp)); password_ = std::move(std::get<1>(tp)); db_num_ = std::move(std::get<2>(tp)); } #endif boost::system::error_code ec; - socket_->connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(host_),port_),ec); - if (ec){ + socket_->connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(host_), port_), ec); + if (ec) { return false; } + is_connect_ = true; + init_socket(); if (!password_.empty()) { bool is_sucess = send_auth(); if (!is_sucess) { @@ -105,7 +97,7 @@ namespace cpp_redis { } } - if (db_num_ >=0){ + if (db_num_ >= 0) { return select_db(); } @@ -113,18 +105,22 @@ namespace cpp_redis { } bool send_msg(std::string&& buffer) { + std::unique_locklock(mutex_); + boost::system::error_code ec; std::string msg = std::move(buffer); - boost::asio::write(*socket_,boost::asio::buffer(msg),boost::asio::transfer_exactly(msg.size()),ec); - if (ec){ + boost::asio::write(*socket_, boost::asio::buffer(msg), boost::asio::transfer_exactly(msg.size()), ec); + if (ec) { + is_connect_ = false; return false; } + lock.unlock(); read_msg(); return true; } - const std::shared_ptr&get_responese() const { + const std::shared_ptr& get_responese() const { return response_; } @@ -144,7 +140,9 @@ namespace cpp_redis { data.append(g_crlf); std::string msg = "select "; msg.append(data); - send_msg(std::move(msg)); + if (!send_msg(std::move(msg))){ + return false; + } if (response_->get_result_code() == status::unconnected_ || response_->get_result_code() == status::errors_) { @@ -154,21 +152,6 @@ namespace cpp_redis { return true; } - void set_timer() { - timer_->expires_from_now(std::chrono::milliseconds(g_send_times)); - timer_->async_wait([this](const boost::system::error_code& ec) { - if (ec){ - return; - } - - close(); - }); - } - - void cancle_timer() { - boost::system::error_code ec; - timer_->cancel(ec); - } bool read_msg() { boost::asio::streambuf response; int loop_times = -1; @@ -233,23 +216,26 @@ namespace cpp_redis { void read_bytes(boost::asio::streambuf& response, std::string& data) { - set_timer(); + if (!is_connect_) { + response_->set_result_code(status::unconnected_); + return; + } + boost::system::error_code e; - size_t bytes_transferred = boost::asio::read_until(*socket_, response,g_crlf, e); - if (e.value() != 0){ - cancle_timer(); + size_t bytes_transferred = boost::asio::read_until(*socket_, response, g_crlf, e); + if (e.value() != 0) { response_->set_result_code(status::unconnected_); return; } - cancle_timer(); - if (bytes_transferred >0){ + if (bytes_transferred > 0) { data.assign(boost::asio::buffers_begin(response.data()), boost::asio::buffers_begin(response.data()) + bytes_transferred); auto pos = data.find(g_crlf); - if (pos !=std::string::npos){ + if (pos != std::string::npos) { data = data.substr(0, pos); } - }else { + } + else { data = "-ERR read bytes is error"; } @@ -263,17 +249,19 @@ namespace cpp_redis { void read_bytes(boost::asio::streambuf& response) { - set_timer(); + if (!is_connect_){ + response_->set_result_code(status::unconnected_); + return; + } + boost::system::error_code e; - size_t bytes_transferred = boost::asio::read_until(*socket_, response,g_crlf, e); + size_t bytes_transferred = boost::asio::read_until(*socket_, response, g_crlf, e); - if (e.value() != 0){ - cancle_timer(); + if (e.value() != 0) { response_->set_result_code(status::unconnected_); return; } - - cancle_timer(); + std::string data; if (bytes_transferred > 0) { @@ -310,6 +298,32 @@ namespace cpp_redis { //response_->set_results(std::move(v)); } + + void read_ping_bytes(std::string& data) + { + if (!is_connect_) { + response_->set_result_code(status::unconnected_); + return; + } + + boost::system::error_code e; + size_t bytes_transferred = socket_->read_some(boost::asio::buffer(&data[0], data.size()),e); + if (e.value() != 0) { + response_->set_result_code(status::unconnected_); + return; + } + + if (bytes_transferred > 0) { + auto pos = data.find(g_crlf); + if (pos != std::string::npos) { + data = data.substr(0, pos); + } + } + else { + data = "-ERR read bytes is error"; + } + } + void set_nil() { std::string data = g_nil; @@ -337,26 +351,33 @@ namespace cpp_redis { bool send_auth() { password_.append(g_crlf); - std::string msg= "auth "; + std::string msg = "auth "; msg.append(password_); - send_msg(std::move(msg)); + if (!send_msg(std::move(msg))) { + return false; + } - if (response_->get_result_code() ==status::errors_) + if (response_->get_result_code() == status::errors_) { return false; } return true; } + + void init_socket() { + boost::system::error_code ec; + socket_->set_option(boost::asio::ip::tcp::no_delay(true), ec); + } private: std::string host_; std::uint16_t port_ = 6379; int db_num_ = -1; std::string password_; std::string data_; - std::atomicexit_ = true; + std::atomicis_connect_ = false; + std::mutex mutex_; std::shared_ptr response_; - std::unique_ptrthread_; std::unique_ptrtimer_; std::unique_ptrios_{}; std::unique_ptrsocket_{}; diff --git a/include/cppredis/cpp_redis_request.hpp b/include/cppredis/cpp_redis_request.hpp index 17c6e0c..5f40e63 100644 --- a/include/cppredis/cpp_redis_request.hpp +++ b/include/cppredis/cpp_redis_request.hpp @@ -4,7 +4,7 @@ #include #include #include -#include "unit.hpp" +#include "redis_unit.hpp" #include "cpp_define.h" namespace cpp_redis { @@ -30,6 +30,9 @@ namespace cpp_redis { case cpp_redis::setex: cmd_str = g_setx_cmd; break; + case cpp_redis::setnx: + cmd_str = g_setnx_cmd; + break; case cpp_redis::psetex: cmd_str = g_psetx_cmd; break; diff --git a/include/cppredis/cpp_redis_string.hpp b/include/cppredis/cpp_redis_string.hpp index c0f0a91..f51d5a9 100644 --- a/include/cppredis/cpp_redis_string.hpp +++ b/include/cppredis/cpp_redis_string.hpp @@ -67,10 +67,29 @@ namespace cpp_redis { return true; } - virtual bool set_has_seconds(std::string&& key, std::string&& value, std::string&& seconds) + virtual int setnx(std::string&& key, std::string&& value) + { + std::string msg = request_->req_n_key(request_->get_cmd(redis_cmd::setnx), + std::forward(key), std::forward(value)); + + if (!socket_->send_msg(std::move(msg))) { + return 0; + } + + const auto res = socket_->get_responese(); + if (res->get_result_code() != status::int_result_) { + return 0; + } + + const auto results = res->get_int_results(); + + return ((!results.empty()) ? results[0]:0); + } + + virtual bool setnx_has_seconds(std::string&& key, std::string&& value, std::string&& seconds) { std::string msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value),"EX",std::forward(seconds)); + std::forward(key), std::forward(value), "EX", std::forward(seconds), "NX"); if (!socket_->send_msg(std::move(msg))) { return false; @@ -84,34 +103,28 @@ namespace cpp_redis { return true; } - virtual bool set_has_seconds_if(std::string&& key, std::string&& value, std::string&& seconds, bool is_exist) + virtual bool setxx(std::string&& key, std::string&& value, std::string&& seconds) { - std::string msg; - if (is_exist){ - msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value), "EX", std::forward(seconds),"XX"); - }else { - msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value), "EX", std::forward(seconds), "NX"); - } + std::string msg=request_->req_n_key(request_->get_cmd(redis_cmd::set), + std::forward(key), std::forward(value), "EX", std::forward(seconds), "XX"); if (!socket_->send_msg(std::move(msg))) { return false; } const auto res = socket_->get_responese(); - if (res->get_result_code() != status::status_){ + if (res->get_result_code() != status::status_) { return false; } return true; } - virtual bool set_has_milliseconds(std::string&& key, std::string&& value, std::string&& milliseconds) + virtual bool setnx_has_milliseconds(std::string&& key, std::string&& value,std::string&& milliseconds) { std::string msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value), "PX", std::forward(milliseconds)); - + std::forward(key), std::forward(value), "PX", std::forward(milliseconds), "NX"); + if (!socket_->send_msg(std::move(msg))) { return false; } @@ -124,24 +137,17 @@ namespace cpp_redis { return true; } - virtual bool set_has_milliseconds_if(std::string&& key, std::string&& value, - std::string&& milliseconds, bool is_exist) + virtual bool setxx_has_milliseconds(std::string&& key, std::string&& value, std::string&& milliseconds) { - std::string msg; - if (is_exist){ - msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value), "PX", std::forward(milliseconds),"XX"); - }else { - msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), - std::forward(key), std::forward(value), "PX", std::forward(milliseconds),"NX"); - } + std::string msg = request_->req_n_key(request_->get_cmd(redis_cmd::set), + std::forward(key), std::forward(value), "PX", std::forward(milliseconds),"XX"); if (!socket_->send_msg(std::move(msg))) { return false; } const auto res = socket_->get_responese(); - if (res->get_result_code() != status::status_){ + if (res->get_result_code() != status::status_) { return false; } diff --git a/include/cppredis/redis_lock.hpp b/include/cppredis/redis_lock.hpp new file mode 100644 index 0000000..913d02b --- /dev/null +++ b/include/cppredis/redis_lock.hpp @@ -0,0 +1,125 @@ +#ifndef redis_lock_h__ +#define redis_lock_h__ + +#include +#include +#include +#include "client.hpp" + +namespace cpp_redis { + class redis_lock { + public: + redis_lock(const std::shared_ptr>& client):client_(client) { + try + { + ios_ = traits::make_unique(); + timer_ = traits::make_unique(*ios_); + thread_ = traits::make_unique([this]() { + while (exit_) { + boost::system::error_code ec; + ios_->poll(ec); + if (ec) { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + }); + } + catch (const std::exception & ex) + { + client_ = nullptr; + ios_ = nullptr; + timer_ = nullptr; + thread_ = nullptr; + } + + } + + void lock(size_t seconds = 30) { + if (client_ == nullptr){ + return; + } + + while (1) { + std::string key = key_; + if (client_->setnx(std::move(key), 1, seconds)) { + reset(); + return; + } + + if (!is_start_timer){ + is_start_timer = true; + timer_check_key(); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + } + + void unlock() { + if (client_ ==nullptr){ + return; + } + + reset(); + std::string key = key_; + client_->delete_key(std::move(key)); + } + + ~redis_lock() { + unlock(); + exit_ = false; + + //̻߳Դֹ߳ + thread_->join(); + } + + redis_lock(const redis_lock&) = default; + redis_lock(redis_lock&&) = default; + redis_lock& operator=(const redis_lock&) = default; + redis_lock& operator=(redis_lock&&) = default; + private: + void reset() { + cancle_timer(); + is_start_timer = false; + } + + void cancle_timer() { + boost::system::error_code ec; + timer_->cancel(ec); + } + + void timer_check_key() { + timer_->expires_from_now(std::chrono::milliseconds(1)); + timer_->async_wait([this](const boost::system::error_code& ec) { + if (ec) { + return; + } + + std::string key = key_; + int seconds = client_->remainder_ttl(std::move(key)); + if (seconds <=0){ + return; + } + + if (seconds<10){ + key = key_; + client_->setnx(std::move(key), 1, 30); + } + + timer_check_key(); + }); + } + + private: + std::atomicexit_ = true; + const std::string key_ = "lock"; + std::atomicis_start_timer = false; + std::unique_ptrthread_; + std::unique_ptrtimer_; + std::shared_ptr>client_; + std::unique_ptrios_; + }; +} +#endif // redis_lock_h__ diff --git a/include/cppredis/unit.hpp b/include/cppredis/redis_unit.hpp similarity index 95% rename from include/cppredis/unit.hpp rename to include/cppredis/redis_unit.hpp index 05978e9..aef0bad 100644 --- a/include/cppredis/unit.hpp +++ b/include/cppredis/redis_unit.hpp @@ -1,10 +1,10 @@ -#ifndef unit_h__ -#define unit_h__ +#ifndef redis_unit_h__ +#define redis_unit_h__ #include #include #include #include -#include "traits.hpp" +#include "redis_traits.hpp" namespace cpp_redis { namespace unit { @@ -110,23 +110,23 @@ namespace cpp_redis { return std::move(ostr.str()); } - static int string_to_int(std::string && str) + static int string_to_int(std::string&& str) { - if (str.empty()){ + if (str.empty()) { return INT_MAX; } int value; std::istringstream istr(str); - istr >>value; + istr >> value; return value; } static int64_t get_time_stamp() { - std::chrono::time_point tp = + std::chrono::time_point tp = std::chrono::time_point_cast(std::chrono::system_clock::now()); - + auto tmp = std::chrono::duration_cast(tp.time_since_epoch()); return tmp.count(); } @@ -159,8 +159,8 @@ namespace cpp_redis { } - template - void for_each_args(F&&func,Args...args){ + template + void for_each_args(F&& func, Args...args) { int arr[] = { (std::forward(func)(args),0)... }; } @@ -196,4 +196,5 @@ namespace cpp_redis { } } } -#endif // unit_h__ + +#endif // redis_unit_h__ diff --git a/third_paty/traits.hpp b/third_paty/redis_traits.hpp similarity index 98% rename from third_paty/traits.hpp rename to third_paty/redis_traits.hpp index b7585d6..871a1af 100644 --- a/third_paty/traits.hpp +++ b/third_paty/redis_traits.hpp @@ -1,5 +1,6 @@ -#ifndef traits_h__ -#define traits_h__ +#ifndef redis_traits_h__ +#define redis_traits_h__ + #include #include #include @@ -10,7 +11,7 @@ #include -namespace cpp_redis{ +namespace cpp_redis { namespace traits { template< class T > struct is_signed_intergral_like : std::integral_constant < bool, @@ -212,4 +213,4 @@ namespace cpp_redis{ }//traits }//cpp_redis -#endif // traits_h__ +#endif // redis_traits_h__