Commit 78ae56e8 authored by zhujiashun's avatar zhujiashun

redis_server_protocol: add RedisReply::SerializeToIOBuf and UT

parent 5f4815ab
...@@ -75,10 +75,11 @@ int Consume(void* meta, bthread::TaskIterator<ExecutionQueueContext*>& iter) { ...@@ -75,10 +75,11 @@ int Consume(void* meta, bthread::TaskIterator<ExecutionQueueContext*>& iter) {
RedisReply output; RedisReply output;
conn->OnRedisMessage(ctx->message, &output, &ctx->arena); conn->OnRedisMessage(ctx->message, &output, &ctx->arena);
butil::IOBuf sendbuf; butil::IOBuf sendbuf;
sendbuf.append("+OK\r\n"); output.SerializeToIOBuf(&sendbuf);
Socket::WriteOptions wopt; Socket::WriteOptions wopt;
wopt.ignore_eovercrowded = true; wopt.ignore_eovercrowded = true;
s->Write(&sendbuf, &wopt); LOG_IF(WARNING, s->Write(&sendbuf, &wopt) != 0)
<< "Fail to send redis reply";
} }
return 0; return 0;
} }
...@@ -114,20 +115,21 @@ ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket, ...@@ -114,20 +115,21 @@ ParseResult ParseRedisMessage(butil::IOBuf* source, Socket* socket,
} }
const Server* server = static_cast<const Server*>(arg); const Server* server = static_cast<const Server*>(arg);
if (server) { if (server) {
RedisConnection* conn = server->options().redis_service->NewConnection();
if (!conn) {
LOG(ERROR) << "Fail to new redis connection from redis service";
return MakeParseError(PARSE_ERROR_TRY_OTHERS);
}
ServerContext* ctx = static_cast<ServerContext*>(socket->parsing_context()); ServerContext* ctx = static_cast<ServerContext*>(socket->parsing_context());
if (ctx == NULL) { if (ctx == NULL) {
RedisConnection* conn = server->options().redis_service->NewConnection();
if (!conn) {
LOG(ERROR) << "Fail to new redis connection from redis service";
return MakeParseError(PARSE_ERROR_TRY_OTHERS);
}
ctx = new ServerContext; ctx = new ServerContext;
if (ctx->init(conn) != 0) { if (ctx->init(conn) != 0) {
delete conn;
delete ctx; delete ctx;
LOG(ERROR) << "Fail to init redis ServerContext"; LOG(ERROR) << "Fail to init redis ServerContext";
return MakeParseError(PARSE_ERROR_NO_RESOURCE); return MakeParseError(PARSE_ERROR_NO_RESOURCE);
} }
socket->initialize_parsing_context(&ctx); socket->reset_parsing_context(&ctx);
} }
std::unique_ptr<ExecutionQueueContext> task(new ExecutionQueueContext); std::unique_ptr<ExecutionQueueContext> task(new ExecutionQueueContext);
RedisReply message; RedisReply message;
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
namespace brpc { namespace brpc {
//BAIDU_CASSERT(sizeof(RedisReply) == 24, size_match); //BAIDU_CASSERT(sizeof(RedisReply) == 24, size_match);
const uint32_t RedisReply::npos = (uint32_t)-1;
const char* RedisReplyTypeToString(RedisReplyType type) { const char* RedisReplyTypeToString(RedisReplyType type) {
switch (type) { switch (type) {
...@@ -38,8 +39,56 @@ const char* RedisReplyTypeToString(RedisReplyType type) { ...@@ -38,8 +39,56 @@ const char* RedisReplyTypeToString(RedisReplyType type) {
} }
bool RedisReply::SerializeToIOBuf(butil::IOBuf* buf) { bool RedisReply::SerializeToIOBuf(butil::IOBuf* buf) {
//TODO butil::IOBufBuilder builder;
switch (_type) {
case REDIS_REPLY_ERROR:
case REDIS_REPLY_STATUS:
buf->push_back((_type == REDIS_REPLY_ERROR)? '-' : '+');
if (_length < sizeof(_data.short_str)) {
buf->append(_data.short_str, _length);
} else {
buf->append(_data.long_str, _length);
}
buf->append("\r\n");
break;
case REDIS_REPLY_INTEGER:
builder << ':' << _data.integer << "\r\n";
buf->append(builder.buf());
break;
case REDIS_REPLY_STRING:
// Since _length is unsigned, we have to int casting _length to
// represent nil string
builder << '$' << (int)_length << "\r\n";
buf->append(builder.buf());
if (_length == npos) {
break;
}
if (_length < sizeof(_data.short_str)) {
buf->append(_data.short_str, _length);
} else {
buf->append(_data.long_str, _length);
}
buf->append("\r\n");
break;
case REDIS_REPLY_ARRAY:
builder << '*' << (int)_length << "\r\n";
buf->append(builder.buf());
if (_length == npos) {
break;
}
for (size_t i = 0; i < _length; ++i) {
if (!_data.array.replies[i].SerializeToIOBuf(buf)) {
return false;
}
}
break;
case REDIS_REPLY_NIL:
buf->append("$-1\r\n");
break;
default:
CHECK(false) << "unknown redis type=" << _type;
return false;
}
return true; return true;
} }
......
...@@ -58,7 +58,7 @@ public: ...@@ -58,7 +58,7 @@ public:
bool set_nil_string(); // "$-1\r\n" bool set_nil_string(); // "$-1\r\n"
bool set_array(int size, butil::Arena* arena); // size == -1 means nil array("*-1\r\n") bool set_array(int size, butil::Arena* arena); // size == -1 means nil array("*-1\r\n")
bool set_simple_string(const std::string& str, butil::Arena* arena); bool set_status(const std::string& str, butil::Arena* arena);
bool set_error(const std::string& str, butil::Arena* arena); bool set_error(const std::string& str, butil::Arena* arena);
bool set_integer(int64_t value); bool set_integer(int64_t value);
bool set_bulk_string(const std::string& str, butil::Arena* arena); bool set_bulk_string(const std::string& str, butil::Arena* arena);
...@@ -87,6 +87,7 @@ public: ...@@ -87,6 +87,7 @@ public:
// Get the index-th sub reply. If this reply is not an array, a nil reply // Get the index-th sub reply. If this reply is not an array, a nil reply
// is returned (call stacks are not logged) // is returned (call stacks are not logged)
const RedisReply& operator[](size_t index) const; const RedisReply& operator[](size_t index) const;
RedisReply& operator[](size_t index);
// Parse from `buf' which may be incomplete and allocate needed memory // Parse from `buf' which may be incomplete and allocate needed memory
// on `arena'. // on `arena'.
...@@ -100,6 +101,7 @@ public: ...@@ -100,6 +101,7 @@ public:
// the complexity in worst case may be O(N^2). // the complexity in worst case may be O(N^2).
// Returns PARSE_ERROR_ABSOLUTELY_WRONG if the parsing failed. // Returns PARSE_ERROR_ABSOLUTELY_WRONG if the parsing failed.
ParseError ConsumePartialIOBuf(butil::IOBuf& buf, butil::Arena* arena); ParseError ConsumePartialIOBuf(butil::IOBuf& buf, butil::Arena* arena);
// //
bool SerializeToIOBuf(butil::IOBuf* buf); bool SerializeToIOBuf(butil::IOBuf* buf);
...@@ -121,6 +123,8 @@ public: ...@@ -121,6 +123,8 @@ public:
void CopyFromSameArena(const RedisReply& other); void CopyFromSameArena(const RedisReply& other);
private: private:
static const uint32_t npos;
// RedisReply does not own the memory of fields, copying must be done // RedisReply does not own the memory of fields, copying must be done
// by calling CopyFrom[Different|Same]Arena. // by calling CopyFrom[Different|Same]Arena.
DISALLOW_COPY_AND_ASSIGN(RedisReply); DISALLOW_COPY_AND_ASSIGN(RedisReply);
...@@ -155,7 +159,11 @@ inline RedisReply::RedisReply() ...@@ -155,7 +159,11 @@ inline RedisReply::RedisReply()
_data.array.replies = NULL; _data.array.replies = NULL;
} }
inline bool RedisReply::is_nil() const { return _type == REDIS_REPLY_NIL; } inline bool RedisReply::is_nil() const {
return (_type == REDIS_REPLY_NIL) ||
((_type == REDIS_REPLY_STRING || _type == REDIS_REPLY_ARRAY) &&
_length == uint32_t(-1));
}
inline bool RedisReply::is_error() const { return _type == REDIS_REPLY_ERROR; } inline bool RedisReply::is_error() const { return _type == REDIS_REPLY_ERROR; }
inline bool RedisReply::is_integer() const { return _type == REDIS_REPLY_INTEGER; } inline bool RedisReply::is_integer() const { return _type == REDIS_REPLY_INTEGER; }
inline bool RedisReply::is_string() const inline bool RedisReply::is_string() const
...@@ -173,14 +181,14 @@ inline int64_t RedisReply::integer() const { ...@@ -173,14 +181,14 @@ inline int64_t RedisReply::integer() const {
inline bool RedisReply::set_nil_string() { inline bool RedisReply::set_nil_string() {
_type = REDIS_REPLY_STRING; _type = REDIS_REPLY_STRING;
_length = -1; _length = npos;
return true; return true;
} }
inline bool RedisReply::set_array(int size, butil::Arena* arena) { inline bool RedisReply::set_array(int size, butil::Arena* arena) {
_type = REDIS_REPLY_ARRAY; _type = REDIS_REPLY_ARRAY;
if (size < 0) { if (size < 0) {
_length = -1; _length = npos;
return true; return true;
} else if (size == 0) { } else if (size == 0) {
_length = 0; _length = 0;
...@@ -217,7 +225,7 @@ inline bool RedisReply::set_basic_string(const std::string& str, butil::Arena* a ...@@ -217,7 +225,7 @@ inline bool RedisReply::set_basic_string(const std::string& str, butil::Arena* a
return true; return true;
} }
inline bool RedisReply::set_simple_string(const std::string& str, butil::Arena* arena) { inline bool RedisReply::set_status(const std::string& str, butil::Arena* arena) {
return set_basic_string(str, arena, REDIS_REPLY_STATUS); return set_basic_string(str, arena, REDIS_REPLY_STATUS);
} }
...@@ -279,6 +287,11 @@ inline size_t RedisReply::size() const { ...@@ -279,6 +287,11 @@ inline size_t RedisReply::size() const {
return (is_array() ? _length : 0); return (is_array() ? _length : 0);
} }
inline RedisReply& RedisReply::operator[](size_t index) {
return const_cast<RedisReply&>(
const_cast<const RedisReply*>(this)->operator[](index));
}
inline const RedisReply& RedisReply::operator[](size_t index) const { inline const RedisReply& RedisReply::operator[](size_t index) const {
if (is_array() && index < _length) { if (is_array() && index < _length) {
return _data.array.replies[index]; return _data.array.replies[index];
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment