Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #ifndef __REDIS_CONNECTION__H__ 6 : #define __REDIS_CONNECTION__H__ 7 : 8 : #include <mutex> 9 : #include <string> 10 : 11 : #include <boost/asio.hpp> 12 : #include <boost/scoped_ptr.hpp> 13 : #include <boost/ptr_container/ptr_map.hpp> 14 : #include "hiredis/hiredis.h" 15 : #include "hiredis/async.h" 16 : #include "hiredis/boostasio.hpp" 17 : #include "io/event_manager.h" 18 : 19 : /* 20 : * Class for maintaining an async connection to Redis, aka RAC - redis async connection 21 : */ 22 : class RedisAsyncConnection { 23 : public: 24 : static const int RedisReconnectTime = 5; 25 : 26 : typedef boost::function<void (void)> ClientConnectCbFn; 27 : typedef boost::function<void (void)> ClientDisconnectCbFn; 28 : typedef boost::function<void (const redisAsyncContext *c, void *r, void *privdata)> ClientAsyncCmdCbFn; 29 : typedef boost::function<void (const redisReply *reply)> RAC_StatCbFn; 30 : typedef boost::function<void (const struct redisAsyncContext*, int)> RAC_ConnectCbFn; 31 : typedef boost::function<void (const struct redisAsyncContext*, int)> RAC_DisconnectCbFn; 32 : 33 : struct RAC_CbFns { 34 270 : RAC_CbFns() : 35 270 : stat_cbfn_(NULL), 36 270 : connect_cbfn_(NULL), 37 270 : disconnect_cbfn_(NULL), 38 270 : client_async_cmd_cbfn_(NULL) { } 39 : RAC_StatCbFn stat_cbfn_; 40 : RAC_ConnectCbFn connect_cbfn_; 41 : RAC_DisconnectCbFn disconnect_cbfn_; 42 : ClientAsyncCmdCbFn client_async_cmd_cbfn_; 43 : }; 44 : 45 : typedef boost::ptr_map<const redisAsyncContext *, RAC_CbFns> RAC_CbFnsMap; 46 : 47 : RedisAsyncConnection(EventManager *evm, const std::string & redis_ip, 48 : unsigned short redis_port, ClientConnectCbFn client_connect_cb = NULL, 49 : ClientDisconnectCbFn client_disconnect_cb = NULL, 50 : const bool redis_ssl_enable = false, 51 : const std::string & redis_keyfile = std::string(), 52 : const std::string & redis_certfile = std::string(), 53 : const std::string & redis_ca_cert = std::string()); 54 : virtual ~RedisAsyncConnection(); 55 : 56 : bool RAC_Connect(void); 57 : 58 : bool IsConnUp() { 59 : return (state_ == REDIS_ASYNC_CONNECTION_CONNECTED); 60 : } 61 : bool SetClientAsyncCmdCb(ClientAsyncCmdCbFn cb_fn); 62 : bool RedisAsyncCommand(void *rpi, const char *format, ...); 63 : bool RedisAsyncArgCmd(void *rpi, const std::vector<std::string> &args); 64 : void RAC_StatUpdate(const redisReply *reply); 65 : 66 4678 : static RAC_CbFnsMap& rac_cb_fns_map() { 67 4678 : return rac_cb_fns_map_; 68 : } 69 : EventManager * GetEVM() { return evm_; } 70 : 71 : uint64_t CallDisconnected() { return callDisconnected_; } 72 : uint64_t CallFailed() { return callFailed_; } 73 : uint64_t CallSucceeded() { return callSucceeded_; } 74 : uint64_t CallbackNull() { return callbackNull_; } 75 : uint64_t CallbackFailed() { return callbackFailed_; } 76 : uint64_t CallbackSucceeded() { return callbackSucceeded_; } 77 : 78 760 : boost::asio::ip::tcp::endpoint Endpoint() const { return endpoint_; } 79 : private: 80 : enum RedisState { 81 : REDIS_ASYNC_CONNECTION_INIT = 0, 82 : REDIS_ASYNC_CONNECTION_PENDING = 1, 83 : REDIS_ASYNC_CONNECTION_CONNECTED = 2, 84 : REDIS_ASYNC_CONNECTION_DISCONNECTED = 3, 85 : }; 86 : 87 : EventManager *evm_; 88 : const std::string hostname_; 89 : const unsigned short port_; 90 : const bool redis_ssl_enable_; 91 : const std::string redis_keyfile_; 92 : const std::string redis_certfile_; 93 : const std::string redis_ca_cert_; 94 : 95 : uint64_t callDisconnected_; 96 : uint64_t callFailed_; 97 : uint64_t callSucceeded_; 98 : uint64_t callbackNull_; 99 : uint64_t callbackFailed_; 100 : uint64_t callbackSucceeded_; 101 : 102 : redisAsyncContext *context_; 103 : //boost::scoped_ptr<redisBoostClient> client_; 104 : boost::shared_ptr<redisBoostClient> client_; 105 : std::mutex mutex_; 106 : RedisState state_; 107 : boost::asio::deadline_timer reconnect_timer_; 108 : 109 : void RAC_Reconnect(const boost::system::error_code &error); 110 : 111 : /* the flow for connect callback is 112 : * 1. RAC_ConnectCallback gets called from hiredis lib 113 : * 2. A lookup against redisAsyncContext in rac_cb_fns_map_ yields 114 : * RAC_ConnectCallbackProcess_ptr, which is same as 115 : * RAC_ConnectCallbackProcess 116 : * 3. From RAC_ConnectCallbackProcess client's client_connect_cb_ gets called 117 : * 118 : * Flow for other callbacks is similar... 119 : */ 120 : 121 : /* connect callback related fields */ 122 : void RAC_ConnectCallbackProcess(const struct redisAsyncContext *c, int status); 123 : static void RAC_ConnectCallback(const struct redisAsyncContext *c, int status); 124 : //RAC_ConnectCbFn RAC_ConnectCallbackProcess_ptr; 125 : ClientConnectCbFn client_connect_cb_; 126 : 127 : /* disconnect callback related fields */ 128 : void RAC_DisconnectCallbackProcess(const struct redisAsyncContext *c, int status); 129 : static void RAC_DisconnectCallback(const struct redisAsyncContext *c, int status); 130 : //RAC_DisconnectCbFn RAC_DisconnectCallbackProcess_ptr; 131 : ClientDisconnectCbFn client_disconnect_cb_; 132 : 133 : /* async command callback related fields */ 134 : static void RAC_AsyncCmdCallback(redisAsyncContext *c, void *r, void *privdata); 135 : 136 : static RAC_CbFnsMap rac_cb_fns_map_; 137 : static std::mutex rac_cb_fns_map_mutex_; 138 : 139 : boost::asio::ip::tcp::endpoint endpoint_; 140 : }; 141 : #endif