Commit 6ce98ba1 authored by zhujiashun's avatar zhujiashun

redis_server_protocol: optimize RedisReply::SerializeTo

parent d97bab49
...@@ -18,29 +18,14 @@ ...@@ -18,29 +18,14 @@
// Authors: Ge,Jun (gejun@baidu.com) // Authors: Ge,Jun (gejun@baidu.com)
#include "butil/logging.h" #include "butil/logging.h"
#include "butil/string_printf.h"
#include "brpc/log.h" #include "brpc/log.h"
#include "brpc/redis_command.h" #include "brpc/redis_command.h"
// Defined in src/butil/iobuf.cpp
void* fast_memcpy(void *__restrict dest, const void *__restrict src, size_t n);
namespace brpc { namespace brpc {
const size_t CTX_WIDTH = 5; const size_t CTX_WIDTH = 5;
// Much faster than snprintf(..., "%lu", d);
inline size_t AppendDecimal(char* outbuf, unsigned long d) {
char buf[24]; // enough for decimal 64-bit integers
size_t n = sizeof(buf);
do {
const unsigned long q = d / 10;
buf[--n] = d - q * 10 + '0';
d = q;
} while (d);
fast_memcpy(outbuf, buf + n, sizeof(buf) - n);
return sizeof(buf) - n;
}
// This function is the hotspot of RedisCommandFormatV() when format is // This function is the hotspot of RedisCommandFormatV() when format is
// short or does not have many %. In a 100K-time call to formating of // short or does not have many %. In a 100K-time call to formating of
// "GET key1", the time spent on RedisRequest.AddCommand() are ~700ns // "GET key1", the time spent on RedisRequest.AddCommand() are ~700ns
...@@ -48,7 +33,7 @@ inline size_t AppendDecimal(char* outbuf, unsigned long d) { ...@@ -48,7 +33,7 @@ inline size_t AppendDecimal(char* outbuf, unsigned long d) {
inline void AppendHeader(std::string& buf, char fc, unsigned long value) { inline void AppendHeader(std::string& buf, char fc, unsigned long value) {
char header[32]; char header[32];
header[0] = fc; header[0] = fc;
size_t len = AppendDecimal(header + 1, value); size_t len = butil::AppendDecimal(header + 1, value);
header[len + 1] = '\r'; header[len + 1] = '\r';
header[len + 2] = '\n'; header[len + 2] = '\n';
buf.append(header, len + 3); buf.append(header, len + 3);
...@@ -56,7 +41,7 @@ inline void AppendHeader(std::string& buf, char fc, unsigned long value) { ...@@ -56,7 +41,7 @@ inline void AppendHeader(std::string& buf, char fc, unsigned long value) {
inline void AppendHeader(butil::IOBuf& buf, char fc, unsigned long value) { inline void AppendHeader(butil::IOBuf& buf, char fc, unsigned long value) {
char header[32]; char header[32];
header[0] = fc; header[0] = fc;
size_t len = AppendDecimal(header + 1, value); size_t len = butil::AppendDecimal(header + 1, value);
header[len + 1] = '\r'; header[len + 1] = '\r';
header[len + 2] = '\n'; header[len + 2] = '\n';
buf.append(header, len + 3); buf.append(header, len + 3);
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <limits> #include <limits>
#include "butil/logging.h" #include "butil/logging.h"
#include "butil/string_printf.h"
#include "brpc/redis_reply.h" #include "brpc/redis_reply.h"
namespace brpc { namespace brpc {
...@@ -39,7 +40,8 @@ const char* RedisReplyTypeToString(RedisReplyType type) { ...@@ -39,7 +40,8 @@ const char* RedisReplyTypeToString(RedisReplyType type) {
} }
bool RedisReply::SerializeTo(butil::IOBuf* buf) { bool RedisReply::SerializeTo(butil::IOBuf* buf) {
butil::IOBufBuilder builder; char prefix_buf[24]; // should be enouth for '<type><integer>\r\n"
size_t len = 0;
switch (_type) { switch (_type) {
case REDIS_REPLY_ERROR: case REDIS_REPLY_ERROR:
// fall through // fall through
...@@ -53,14 +55,20 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) { ...@@ -53,14 +55,20 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) {
buf->append("\r\n"); buf->append("\r\n");
break; break;
case REDIS_REPLY_INTEGER: case REDIS_REPLY_INTEGER:
builder << ':' << _data.integer << "\r\n"; prefix_buf[0] = ':';
buf->append(builder.buf()); len = butil::AppendDecimal(&prefix_buf[1], _data.integer);
prefix_buf[len + 1] = '\r';
prefix_buf[len + 2] = '\n';
buf->append(prefix_buf, len + 3 /* 1 for ':', 2 for "\r\n" */);
break; break;
case REDIS_REPLY_STRING: case REDIS_REPLY_STRING:
// Since _length is unsigned, we have to int casting _length to // Since _length is unsigned, we have to casting _length to signed
// represent nil string // representing nil string
builder << '$' << (int)_length << "\r\n"; prefix_buf[0] = '$';
buf->append(builder.buf()); len = butil::AppendDecimal(&prefix_buf[1], (int)_length);
prefix_buf[len + 1] = '\r';
prefix_buf[len + 2] = '\n';
buf->append(prefix_buf, len + 3 /* 1 for ':', 2 for "\r\n" */);
if (_length == npos) { if (_length == npos) {
break; break;
} }
...@@ -72,8 +80,13 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) { ...@@ -72,8 +80,13 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) {
buf->append("\r\n"); buf->append("\r\n");
break; break;
case REDIS_REPLY_ARRAY: case REDIS_REPLY_ARRAY:
builder << '*' << (int)_length << "\r\n"; // Since _length is unsigned, we have to casting _length to signed
buf->append(builder.buf()); // representing nil string
prefix_buf[0] = '*';
len = butil::AppendDecimal(&prefix_buf[1], (int)_length);
prefix_buf[len + 1] = '\r';
prefix_buf[len + 2] = '\n';
buf->append(prefix_buf, len + 3 /* 1 for ':', 2 for "\r\n" */);
if (_length == npos) { if (_length == npos) {
break; break;
} }
......
...@@ -137,5 +137,4 @@ int string_vprintf(std::string* output, const char* format, va_list args) { ...@@ -137,5 +137,4 @@ int string_vprintf(std::string* output, const char* format, va_list args) {
return rc; return rc;
}; };
} // namespace butil } // namespace butil
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <string> // std::string #include <string> // std::string
#include <stdarg.h> // va_list #include <stdarg.h> // va_list
#include <string.h> // memcpy
namespace butil { namespace butil {
...@@ -45,6 +46,27 @@ int string_appendf(std::string* output, const char* format, ...) ...@@ -45,6 +46,27 @@ int string_appendf(std::string* output, const char* format, ...)
// Returns 0 on success, -1 otherwise. // Returns 0 on success, -1 otherwise.
int string_vappendf(std::string* output, const char* format, va_list args); int string_vappendf(std::string* output, const char* format, va_list args);
// Format integer |d| to |output|, which is much faster than snprintf(..., "%lu", d);
// Return written length.
inline size_t AppendDecimal(char* outbuf, long d) {
char buf[24]; // enough for decimal 64-bit integers
size_t n = sizeof(buf);
bool negative = false;
if (d < 0) {
negative = true;
d = -d;
}
do {
const long q = d / 10;
buf[--n] = d - q * 10 + '0';
d = q;
} while (d);
if (negative) {
buf[--n] = '-';
}
memcpy(outbuf, buf + n, sizeof(buf) - n);
return sizeof(buf) - n;
}
} // namespace butil } // namespace butil
......
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