-
Notifications
You must be signed in to change notification settings - Fork 15
/
RedisClient.h
141 lines (121 loc) · 3.65 KB
/
RedisClient.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/* Author: Huanghao
* Date: 2017-2
* Revision: 0.1
* Function: Thread-safe redis client
* Usage: see test_RedisClient.cpp
*/
#ifndef REDISCLIENT_H
#define REDISCLIENT_H
#include <pthread.h>
#include "hiredispool.h"
#include "hiredis/hiredis.h"
#include <string>
#include <stdexcept>
// PooledSocket is a pooled socket wrapper that provides a convenient
// RAII-style mechanism for owning a socket for the duration of a
// scoped block.
class PooledSocket
{
private:
// non construct copyable and non copyable
PooledSocket(const PooledSocket&);
PooledSocket& operator=(const PooledSocket&);
public:
// Get a pooled socket from a redis instance.
// throw runtime_error if something wrong.
PooledSocket(REDIS_INSTANCE* _inst) : inst(_inst) {
sock = redis_get_socket(inst);
}
// Release the socket to pool
~PooledSocket() {
redis_release_socket(inst, sock);
}
// Implicit convert to REDIS_SOCKET*
operator REDIS_SOCKET*() const { return sock; }
bool notNull() const { return (sock != NULL); }
bool isNull() const { return (sock == NULL); }
private:
REDIS_INSTANCE* inst;
REDIS_SOCKET* sock;
};
// Helper
struct RedisReplyRef
{
redisReply* p;
explicit RedisReplyRef(redisReply* _p): p(_p) {}
};
// RedisReplyPtr is a smart pointer encapsulate redisReply*
class RedisReplyPtr
{
public:
explicit RedisReplyPtr(void* _p = 0) : p((redisReply*)_p) {}
~RedisReplyPtr() {
//printf("freeReplyObject %p\n", (void*)p);
freeReplyObject(p);
}
// release ownership of the managed object
redisReply* release() {
redisReply* temp = p;
p = NULL;
return temp;
}
// transfer ownership
RedisReplyPtr(RedisReplyPtr& other) {
p = other.release();
}
RedisReplyPtr& operator=(RedisReplyPtr& other) {
if (this == &other)
return *this;
RedisReplyPtr temp(release());
p = other.release();
return *this;
}
// automatic conversions
RedisReplyPtr(RedisReplyRef _ref) {
p = _ref.p;
}
RedisReplyPtr& operator=(RedisReplyRef _ref) {
if (p == _ref.p)
return *this;
RedisReplyPtr temp(release());
p = _ref.p;
return *this;
}
operator RedisReplyRef() { return RedisReplyRef(release()); }
bool notNull() const { return (p != 0); }
bool isNull() const { return (p == 0); }
redisReply* get() const { return p; }
redisReply* operator->() const { return p; }
redisReply& operator*() const { return *p; }
private:
redisReply* p;
};
// RedisClient provides a threadsafe redis client
class RedisClient
{
private:
// non construct copyable and non copyable
RedisClient(const RedisClient&);
RedisClient& operator=(const RedisClient&);
public:
RedisClient(const REDIS_CONFIG& conf) {
if (redis_pool_create(&conf, &inst) < 0)
throw std::runtime_error("Can't create pool");
}
~RedisClient() {
redis_pool_destroy(inst);
}
// ----------------------------------------------------
// Thread-safe command
// ----------------------------------------------------
// redisCommand is a thread-safe wrapper of that function in hiredis
// It first get a connection from pool, execute the command on that
// connection and then release the connection to pool.
// the command's reply is returned as a smart pointer,
// which can be used just like raw redisReply pointer.
RedisReplyPtr redisCommand(const char *format, ...);
RedisReplyPtr redisvCommand(const char *format, va_list ap);
private:
REDIS_INSTANCE* inst;
};
#endif // REDISCLIENT_H