Skip to content

Commit 0c3544d

Browse files
committed
enhance error handling for redis
Signed-off-by: liulanzheng <lanzheng.liulz@alibaba-inc.com>
1 parent eae4779 commit 0c3544d

3 files changed

Lines changed: 40 additions & 25 deletions

File tree

ecosystem/redis.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ any _RedisClient::parse_response_item() {
3939
auto x = get_integer();
4040
return array_header{x};}
4141
default:
42-
LOG_ERROR("uncognized mark: ", mark);
43-
return {};
42+
LOG_ERROR("unrecognized mark: ", mark);
43+
return error_message("unrecognized mark");
4444
}
4545
}
4646

47-
void _RedisClient::__refill(size_t atleast) {
47+
ssize_t _RedisClient::__refill(size_t atleast) {
4848
size_t room = _bufsize - _j;
4949
if (!room || room < atleast) { if (_refcnt > 0) {
50-
LOG_ERROR_RETURN(0, , "no enough buffer space");
50+
LOG_ERROR_RETURN(0, -1 , "no enough buffer space");
5151
} else {
5252
size_t available = _j - _i;
5353
memmove(ibuf(), ibuf() + _i, available);
@@ -56,8 +56,9 @@ void _RedisClient::__refill(size_t atleast) {
5656
} }
5757
ssize_t ret = _s->recv_at_least(ibuf() + _j, room, atleast);
5858
if (ret < (ssize_t)atleast)
59-
LOG_ERRNO_RETURN(0,, "failed to recv at least ` bytes", atleast);
59+
LOG_ERRNO_RETURN(0, -1, "failed to recv at least ` bytes", atleast);
6060
_j += ret;
61+
return ret;
6162
}
6263

6364
std::string_view _RedisClient::__getline() {
@@ -66,7 +67,9 @@ std::string_view _RedisClient::__getline() {
6667
estring_view sv(ibuf() + _i, _j - _i);
6768
while ((pos = sv.find('\n')) == sv.npos) {
6869
size_t j = _j;
69-
__refill(0);
70+
if (__refill(0) < 0) {
71+
return {};
72+
}
7073
assert(_j > j);
7174
sv = {ibuf() + j, (uint32_t)(_j - j)};
7275
}
@@ -88,8 +91,9 @@ std::string_view _RedisClient::__getline() {
8891
std::string_view _RedisClient::__getstring(size_t length) {
8992
assert(_i <= _j);
9093
size_t available = _j - _i;
91-
if (available < length + 2)
92-
__refill(length + 2 - available);
94+
if (available < length + 2 && __refill(length + 2 - available) < 0) {
95+
return {};
96+
}
9397
auto begin = ibuf() + _i;
9498
_i += length;
9599
assert(_i + 2 <= _j);
@@ -101,7 +105,7 @@ std::string_view _RedisClient::__getstring(size_t length) {
101105
return {begin, length};
102106
}
103107

104-
void _RedisClient::flush(const void* extra_buffer, size_t size) {
108+
ssize_t _RedisClient::flush(const void* extra_buffer, size_t size) {
105109
iovec iov[2];
106110
iov[0] = {obuf(), _o};
107111
int iovcnt = 1;
@@ -112,8 +116,9 @@ void _RedisClient::flush(const void* extra_buffer, size_t size) {
112116
}
113117
ssize_t ret = _s->writev_mutable(iov, iovcnt);
114118
if (ret < sum)
115-
LOG_ERRNO_RETURN(0,, "failed to write to socket stream");
119+
LOG_ERRNO_RETURN(0, -1, "failed to write to socket stream");
116120
_o = 0;
121+
return ret;
117122
}
118123

119124
}

ecosystem/redis.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ using net::ISocketStream;
172172
class _RedisClient {
173173
protected:
174174
ISocketStream* _s = nullptr;
175+
bool _s_ownership = false;
175176
uint32_t _i = 0, _j = 0, _o = 0, _bufsize = 0, _refcnt = 0;
176177
char _xbuf[0];
177178

@@ -196,11 +197,15 @@ class _RedisClient {
196197
size_t __MAX_SIZE(_array_header x) { return 32; }
197198
size_t __MAX_SIZE(_char x) { return 1; }
198199

199-
explicit _RedisClient(ISocketStream* s, uint32_t bufsize) :
200-
_s(s), _bufsize(bufsize) { }
200+
explicit _RedisClient(ISocketStream* s, bool s_ownership, uint32_t bufsize) :
201+
_s(s), _s_ownership(s_ownership), _bufsize(bufsize) { }
202+
~_RedisClient() {
203+
if (_s_ownership)
204+
delete _s;
205+
}
201206

202207
public:
203-
void flush(const void* extra_buffer = 0, size_t size = 0);
208+
ssize_t flush(const void* extra_buffer = 0, size_t size = 0);
204209
bool flush_if_low_space(size_t threshold, const void* ebuf = 0, size_t size = 0) {
205210
return (_o + threshold < _bufsize) ? false :
206211
(flush(ebuf, size), true);
@@ -272,7 +277,9 @@ class _RedisClient {
272277
}
273278

274279
char get_char() {
275-
ensure_input_data(__MAX_SIZE(_char{'c'}));
280+
if (ensure_input_data(__MAX_SIZE(_char{'c'})) < 0) {
281+
return '\0';
282+
}
276283
return ibuf()[_i++];
277284
}
278285
refstring getline() {
@@ -290,12 +297,14 @@ class _RedisClient {
290297
return getstring((size_t)length);
291298
return {};
292299
}
293-
void __refill(size_t atleast); // refill input buffer
294-
void ensure_input_data(size_t min_available) {
300+
ssize_t __refill(size_t atleast); // refill input buffer
301+
int ensure_input_data(size_t min_available) {
295302
assert(_j >= _i);
296303
size_t available = _j - _i;
297-
if (available < min_available)
298-
__refill(min_available - available);
304+
if (available < min_available && __refill(min_available - available) < 0) {
305+
return -1;
306+
}
307+
return 0;
299308
}
300309

301310
void write_items() { }
@@ -318,7 +327,9 @@ class _RedisClient {
318327
template<typename...Args>
319328
any execute(bulk_string cmd, const Args&...args) {
320329
send_cmd_no_flush(cmd, args...);
321-
flush();
330+
if (flush() < 0) {
331+
return error_message("flush failed");
332+
}
322333
return parse_response_item();
323334
}
324335

@@ -703,7 +714,7 @@ template<uint32_t BUF_SIZE = 16*1024UL>
703714
class __RedisClient : public _RedisClient {
704715
char _buf[BUF_SIZE * 2];
705716
public:
706-
__RedisClient(ISocketStream* s) : _RedisClient(s, BUF_SIZE) { }
717+
__RedisClient(ISocketStream* s, bool s_ownership) : _RedisClient(s, s_ownership, BUF_SIZE) { }
707718
};
708719

709720
using RedisClient = __RedisClient<16*1024UL>;
@@ -713,4 +724,3 @@ using RedisClient = __RedisClient<16*1024UL>;
713724

714725
}
715726
}
716-

ecosystem/test/test_redis.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct __RC : public RedisClient {
4646
TEST(redis, serialization) {
4747
auto s = new_string_socket_stream();
4848
DEFER(delete s);
49-
RedisClient rc(s);
49+
RedisClient rc(s, false);
5050
rc << "asldkfjasfkd"
5151
<< __RC::_strint{234}
5252
<< "this-is-another-string"
@@ -75,7 +75,7 @@ TEST(redis, deserialization) {
7575
ARRAY_HEADER(3) SSTR(asdf) INTEGER(75) BSTR(3,jkl) INTEGER(-1234234);
7676
s->set_input(RESP, false);
7777
print_resp(s->input());
78-
RedisClient rc(s);
78+
RedisClient rc(s, false);
7979
auto a = rc.parse_response_item();
8080
EXPECT_EQ(a.mark, simple_string::mark());
8181
EXPECT_EQ(a.get<simple_string>(), "asldkfjasfkd");
@@ -118,7 +118,7 @@ void asdfjkl(RedisClient& bs) {
118118
TEST(redis, cmd_serialization) {
119119
auto s = new_string_socket_stream();
120120
DEFER(delete s);
121-
RedisClient rc(s);
121+
RedisClient rc(s, false);
122122
#define ERRMSG "ERR unknown command 'asdf'"
123123
#define TEST_CMD(cmd, truth) { \
124124
s->set_input("-" ERRMSG CRLF, false); \
@@ -191,7 +191,7 @@ TEST(redis, cmd) {
191191
#endif
192192
}
193193
DEFER(delete s);
194-
RedisClient rc(s);
194+
RedisClient rc(s, false);
195195
const char key[] = "zvxbhm";
196196
rc.DEL(key);
197197
DEFER(rc.DEL(key));

0 commit comments

Comments
 (0)