Commit 6ce98ba1 authored by zhujiashun's avatar zhujiashun

redis_server_protocol: optimize RedisReply::SerializeTo

parent d97bab49
......@@ -18,29 +18,14 @@
// Authors: Ge,Jun (gejun@baidu.com)
#include "butil/logging.h"
#include "butil/string_printf.h"
#include "brpc/log.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 {
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
// short or does not have many %. In a 100K-time call to formating of
// "GET key1", the time spent on RedisRequest.AddCommand() are ~700ns
......@@ -48,7 +33,7 @@ inline size_t AppendDecimal(char* outbuf, unsigned long d) {
inline void AppendHeader(std::string& buf, char fc, unsigned long value) {
char header[32];
header[0] = fc;
size_t len = AppendDecimal(header + 1, value);
size_t len = butil::AppendDecimal(header + 1, value);
header[len + 1] = '\r';
header[len + 2] = '\n';
buf.append(header, len + 3);
......@@ -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) {
char header[32];
header[0] = fc;
size_t len = AppendDecimal(header + 1, value);
size_t len = butil::AppendDecimal(header + 1, value);
header[len + 1] = '\r';
header[len + 2] = '\n';
buf.append(header, len + 3);
......
......@@ -19,6 +19,7 @@
#include <limits>
#include "butil/logging.h"
#include "butil/string_printf.h"
#include "brpc/redis_reply.h"
namespace brpc {
......@@ -39,7 +40,8 @@ const char* RedisReplyTypeToString(RedisReplyType type) {
}
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) {
case REDIS_REPLY_ERROR:
// fall through
......@@ -53,14 +55,20 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) {
buf->append("\r\n");
break;
case REDIS_REPLY_INTEGER:
builder << ':' << _data.integer << "\r\n";
buf->append(builder.buf());
prefix_buf[0] = ':';
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;
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());
// Since _length is unsigned, we have to casting _length to signed
// 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) {
break;
}
......@@ -72,8 +80,13 @@ bool RedisReply::SerializeTo(butil::IOBuf* buf) {
buf->append("\r\n");
break;
case REDIS_REPLY_ARRAY:
builder << '*' << (int)_length << "\r\n";
buf->append(builder.buf());
// Since _length is unsigned, we have to casting _length to signed
// 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) {
break;
}
......
......@@ -137,5 +137,4 @@ int string_vprintf(std::string* output, const char* format, va_list args) {
return rc;
};
} // namespace butil
......@@ -20,6 +20,7 @@
#include <string> // std::string
#include <stdarg.h> // va_list
#include <string.h> // memcpy
namespace butil {
......@@ -45,6 +46,27 @@ int string_appendf(std::string* output, const char* format, ...)
// Returns 0 on success, -1 otherwise.
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
......
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