client buffer handling refactoring and optimization
This commit is contained in:
parent
3c0602ff41
commit
51669c5ac1
@ -67,11 +67,23 @@ redisClient *createClient(int fd) {
|
|||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the event loop to listen for write events on the client's socket.
|
/* This function is called every time we are going to transmit new data
|
||||||
* Typically gets called every time a reply is built. */
|
* to the client. The behavior is the following:
|
||||||
int _installWriteEvent(redisClient *c) {
|
*
|
||||||
|
* If the client should receive new data (normal clients will) the function
|
||||||
|
* returns REDIS_OK, and make sure to install the write handler in our event
|
||||||
|
* loop so that when the socket is writable new data gets written.
|
||||||
|
*
|
||||||
|
* If the client should not receive new data, because it is a fake client
|
||||||
|
* or a slave, or because the setup of the write handler failed, the function
|
||||||
|
* returns REDIS_ERR.
|
||||||
|
*
|
||||||
|
* Typically gets called every time a reply is built, before adding more
|
||||||
|
* data to the clients output buffers. If the function returns REDIS_ERR no
|
||||||
|
* data should be appended to the output buffers. */
|
||||||
|
int prepareClientToWrite(redisClient *c) {
|
||||||
if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK;
|
if (c->flags & REDIS_LUA_CLIENT) return REDIS_OK;
|
||||||
if (c->fd <= 0) return REDIS_ERR;
|
if (c->fd <= 0) return REDIS_ERR; /* Fake client */
|
||||||
if (c->bufpos == 0 && listLength(c->reply) == 0 &&
|
if (c->bufpos == 0 && listLength(c->reply) == 0 &&
|
||||||
(c->replstate == REDIS_REPL_NONE ||
|
(c->replstate == REDIS_REPL_NONE ||
|
||||||
c->replstate == REDIS_REPL_ONLINE) &&
|
c->replstate == REDIS_REPL_ONLINE) &&
|
||||||
@ -203,7 +215,7 @@ void _addReplyStringToList(redisClient *c, char *s, size_t len) {
|
|||||||
* -------------------------------------------------------------------------- */
|
* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
void addReply(redisClient *c, robj *obj) {
|
void addReply(redisClient *c, robj *obj) {
|
||||||
if (_installWriteEvent(c) != REDIS_OK) return;
|
if (prepareClientToWrite(c) != REDIS_OK) return;
|
||||||
|
|
||||||
/* This is an important place where we can avoid copy-on-write
|
/* This is an important place where we can avoid copy-on-write
|
||||||
* when there is a saving child running, avoiding touching the
|
* when there is a saving child running, avoiding touching the
|
||||||
@ -215,19 +227,31 @@ void addReply(redisClient *c, robj *obj) {
|
|||||||
if (obj->encoding == REDIS_ENCODING_RAW) {
|
if (obj->encoding == REDIS_ENCODING_RAW) {
|
||||||
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
|
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
|
||||||
_addReplyObjectToList(c,obj);
|
_addReplyObjectToList(c,obj);
|
||||||
} else {
|
} else if (obj->encoding == REDIS_ENCODING_INT) {
|
||||||
/* FIXME: convert the long into string and use _addReplyToBuffer()
|
/* Optimization: if there is room in the static buffer for 32 bytes
|
||||||
* instead of calling getDecodedObject. As this place in the
|
* (more than the max chars a 64 bit integer can take as string) we
|
||||||
* code is too performance critical. */
|
* avoid decoding the object and go for the lower level approach. */
|
||||||
|
if (listLength(c->reply) == 0 && (sizeof(c->buf) - c->bufpos) >= 32) {
|
||||||
|
char buf[32];
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = ll2string(buf,sizeof(buf),(long)obj->ptr);
|
||||||
|
if (_addReplyToBuffer(c,buf,len) == REDIS_OK)
|
||||||
|
return;
|
||||||
|
/* else... continue with the normal code path, but should never
|
||||||
|
* happen actually since we verified there is room. */
|
||||||
|
}
|
||||||
obj = getDecodedObject(obj);
|
obj = getDecodedObject(obj);
|
||||||
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
|
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
|
||||||
_addReplyObjectToList(c,obj);
|
_addReplyObjectToList(c,obj);
|
||||||
decrRefCount(obj);
|
decrRefCount(obj);
|
||||||
|
} else {
|
||||||
|
redisPanic("Wrong obj->encoding in addReply()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplySds(redisClient *c, sds s) {
|
void addReplySds(redisClient *c, sds s) {
|
||||||
if (_installWriteEvent(c) != REDIS_OK) {
|
if (prepareClientToWrite(c) != REDIS_OK) {
|
||||||
/* The caller expects the sds to be free'd. */
|
/* The caller expects the sds to be free'd. */
|
||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
return;
|
return;
|
||||||
@ -241,19 +265,19 @@ void addReplySds(redisClient *c, sds s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addReplyString(redisClient *c, char *s, size_t len) {
|
void addReplyString(redisClient *c, char *s, size_t len) {
|
||||||
if (_installWriteEvent(c) != REDIS_OK) return;
|
if (prepareClientToWrite(c) != REDIS_OK) return;
|
||||||
if (_addReplyToBuffer(c,s,len) != REDIS_OK)
|
if (_addReplyToBuffer(c,s,len) != REDIS_OK)
|
||||||
_addReplyStringToList(c,s,len);
|
_addReplyStringToList(c,s,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addReplyError(redisClient *c, char *s, size_t len) {
|
void addReplyErrorLength(redisClient *c, char *s, size_t len) {
|
||||||
addReplyString(c,"-ERR ",5);
|
addReplyString(c,"-ERR ",5);
|
||||||
addReplyString(c,s,len);
|
addReplyString(c,s,len);
|
||||||
addReplyString(c,"\r\n",2);
|
addReplyString(c,"\r\n",2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyError(redisClient *c, char *err) {
|
void addReplyError(redisClient *c, char *err) {
|
||||||
_addReplyError(c,err,strlen(err));
|
addReplyErrorLength(c,err,strlen(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
|
void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
|
||||||
@ -268,18 +292,18 @@ void addReplyErrorFormat(redisClient *c, const char *fmt, ...) {
|
|||||||
for (j = 0; j < l; j++) {
|
for (j = 0; j < l; j++) {
|
||||||
if (s[j] == '\r' || s[j] == '\n') s[j] = ' ';
|
if (s[j] == '\r' || s[j] == '\n') s[j] = ' ';
|
||||||
}
|
}
|
||||||
_addReplyError(c,s,sdslen(s));
|
addReplyErrorLength(c,s,sdslen(s));
|
||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addReplyStatus(redisClient *c, char *s, size_t len) {
|
void addReplyStatusLength(redisClient *c, char *s, size_t len) {
|
||||||
addReplyString(c,"+",1);
|
addReplyString(c,"+",1);
|
||||||
addReplyString(c,s,len);
|
addReplyString(c,s,len);
|
||||||
addReplyString(c,"\r\n",2);
|
addReplyString(c,"\r\n",2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyStatus(redisClient *c, char *status) {
|
void addReplyStatus(redisClient *c, char *status) {
|
||||||
_addReplyStatus(c,status,strlen(status));
|
addReplyStatusLength(c,status,strlen(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyStatusFormat(redisClient *c, const char *fmt, ...) {
|
void addReplyStatusFormat(redisClient *c, const char *fmt, ...) {
|
||||||
@ -287,7 +311,7 @@ void addReplyStatusFormat(redisClient *c, const char *fmt, ...) {
|
|||||||
va_start(ap,fmt);
|
va_start(ap,fmt);
|
||||||
sds s = sdscatvprintf(sdsempty(),fmt,ap);
|
sds s = sdscatvprintf(sdsempty(),fmt,ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
_addReplyStatus(c,s,sdslen(s));
|
addReplyStatusLength(c,s,sdslen(s));
|
||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,7 +321,7 @@ void *addDeferredMultiBulkLength(redisClient *c) {
|
|||||||
/* Note that we install the write event here even if the object is not
|
/* Note that we install the write event here even if the object is not
|
||||||
* ready to be sent, since we are sure that before returning to the
|
* ready to be sent, since we are sure that before returning to the
|
||||||
* event loop setDeferredMultiBulkLength() will be called. */
|
* event loop setDeferredMultiBulkLength() will be called. */
|
||||||
if (_installWriteEvent(c) != REDIS_OK) return NULL;
|
if (prepareClientToWrite(c) != REDIS_OK) return NULL;
|
||||||
listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL));
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL));
|
||||||
return listLast(c->reply);
|
return listLast(c->reply);
|
||||||
}
|
}
|
||||||
@ -336,7 +360,7 @@ void addReplyDouble(redisClient *c, double d) {
|
|||||||
|
|
||||||
/* Add a long long as integer reply or bulk len / multi bulk count.
|
/* Add a long long as integer reply or bulk len / multi bulk count.
|
||||||
* Basically this is used to output <prefix><long long><crlf>. */
|
* Basically this is used to output <prefix><long long><crlf>. */
|
||||||
void _addReplyLongLong(redisClient *c, long long ll, char prefix) {
|
void addReplyLongLongWithPrefix(redisClient *c, long long ll, char prefix) {
|
||||||
char buf[128];
|
char buf[128];
|
||||||
int len;
|
int len;
|
||||||
buf[0] = prefix;
|
buf[0] = prefix;
|
||||||
@ -352,11 +376,11 @@ void addReplyLongLong(redisClient *c, long long ll) {
|
|||||||
else if (ll == 1)
|
else if (ll == 1)
|
||||||
addReply(c,shared.cone);
|
addReply(c,shared.cone);
|
||||||
else
|
else
|
||||||
_addReplyLongLong(c,ll,':');
|
addReplyLongLongWithPrefix(c,ll,':');
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyMultiBulkLen(redisClient *c, long length) {
|
void addReplyMultiBulkLen(redisClient *c, long length) {
|
||||||
_addReplyLongLong(c,length,'*');
|
addReplyLongLongWithPrefix(c,length,'*');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create the length prefix of a bulk reply, example: $2234 */
|
/* Create the length prefix of a bulk reply, example: $2234 */
|
||||||
@ -378,7 +402,7 @@ void addReplyBulkLen(redisClient *c, robj *obj) {
|
|||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_addReplyLongLong(c,len,'$');
|
addReplyLongLongWithPrefix(c,len,'$');
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add a Redis Object as a bulk reply */
|
/* Add a Redis Object as a bulk reply */
|
||||||
@ -390,7 +414,7 @@ void addReplyBulk(redisClient *c, robj *obj) {
|
|||||||
|
|
||||||
/* Add a C buffer as bulk reply */
|
/* Add a C buffer as bulk reply */
|
||||||
void addReplyBulkCBuffer(redisClient *c, void *p, size_t len) {
|
void addReplyBulkCBuffer(redisClient *c, void *p, size_t len) {
|
||||||
_addReplyLongLong(c,len,'$');
|
addReplyLongLongWithPrefix(c,len,'$');
|
||||||
addReplyString(c,p,len);
|
addReplyString(c,p,len);
|
||||||
addReply(c,shared.crlf);
|
addReply(c,shared.crlf);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user