mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
Changed reply buildup internals
This commit is contained in:
parent
4a7893ca9c
commit
36c19d03e0
151
src/networking.c
151
src/networking.c
@ -13,13 +13,9 @@ int listMatchObjects(void *a, void *b) {
|
|||||||
redisClient *createClient(int fd) {
|
redisClient *createClient(int fd) {
|
||||||
redisClient *c;
|
redisClient *c;
|
||||||
|
|
||||||
/* Make sure to allocate a multiple of the page size to prevent wasting
|
/* Allocate more space to hold a static write buffer. */
|
||||||
* memory. A page size of 4096 is assumed here. We need to compensate
|
c = zmalloc(sizeof(redisClient)+REDIS_REPLY_CHUNK_BYTES);
|
||||||
* for the zmalloc overhead of sizeof(size_t) bytes. */
|
c->buflen = REDIS_REPLY_CHUNK_BYTES;
|
||||||
size_t size = 8192-sizeof(size_t);
|
|
||||||
redisAssert(size > sizeof(redisClient));
|
|
||||||
c = zmalloc(size);
|
|
||||||
c->buflen = size-sizeof(redisClient);
|
|
||||||
c->bufpos = 0;
|
c->bufpos = 0;
|
||||||
|
|
||||||
anetNonBlock(NULL,fd);
|
anetNonBlock(NULL,fd);
|
||||||
@ -71,40 +67,95 @@ int _ensureFileEvent(redisClient *c) {
|
|||||||
return REDIS_OK;
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addReplyObjectToList(redisClient *c, robj *obj) {
|
/* Create a duplicate of the last object in the reply list when
|
||||||
redisAssert(obj->type == REDIS_STRING &&
|
* it is not exclusively owned by the reply list. */
|
||||||
obj->encoding == REDIS_ENCODING_RAW);
|
robj *dupLastObjectIfNeeded(list *reply) {
|
||||||
listAddNodeTail(c->reply,obj);
|
robj *new, *cur;
|
||||||
|
listNode *ln;
|
||||||
|
redisAssert(listLength(reply) > 0);
|
||||||
|
ln = listLast(reply);
|
||||||
|
cur = listNodeValue(ln);
|
||||||
|
if (cur->refcount > 1) {
|
||||||
|
new = dupStringObject(cur);
|
||||||
|
decrRefCount(cur);
|
||||||
|
listNodeValue(ln) = new;
|
||||||
|
}
|
||||||
|
return listNodeValue(ln);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _ensureBufferInReplyList(redisClient *c) {
|
int _addReplyToBuffer(redisClient *c, char *s, size_t len) {
|
||||||
sds buffer = sdsnewlen(NULL,REDIS_REPLY_CHUNK_SIZE);
|
size_t available = c->buflen-c->bufpos;
|
||||||
sdsupdatelen(buffer); /* sdsnewlen expects non-empty string */
|
|
||||||
listAddNodeTail(c->reply,createObject(REDIS_REPLY_NODE,buffer));
|
/* If there already are entries in the reply list, we cannot
|
||||||
|
* add anything more to the static buffer. */
|
||||||
|
if (listLength(c->reply) > 0) return REDIS_ERR;
|
||||||
|
|
||||||
|
/* Check that the buffer has enough space available for this string. */
|
||||||
|
if (len > available) return REDIS_ERR;
|
||||||
|
|
||||||
|
memcpy(c->buf+c->bufpos,s,len);
|
||||||
|
c->bufpos+=len;
|
||||||
|
return REDIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addReplyStringToBuffer(redisClient *c, char *s, size_t len) {
|
void _addReplyObjectToList(redisClient *c, robj *o) {
|
||||||
size_t available = 0;
|
robj *tail;
|
||||||
redisAssert(len < REDIS_REPLY_CHUNK_THRESHOLD);
|
if (listLength(c->reply) == 0) {
|
||||||
if (listLength(c->reply) > 0) {
|
incrRefCount(o);
|
||||||
robj *o = listNodeValue(listLast(c->reply));
|
listAddNodeTail(c->reply,o);
|
||||||
|
|
||||||
/* Make sure to append to a reply node with enough bytes available. */
|
|
||||||
if (o->type == REDIS_REPLY_NODE) available = sdsavail(o->ptr);
|
|
||||||
if (o->type != REDIS_REPLY_NODE || len > available) {
|
|
||||||
_ensureBufferInReplyList(c);
|
|
||||||
_addReplyStringToBuffer(c,s,len);
|
|
||||||
} else {
|
|
||||||
o->ptr = sdscatlen(o->ptr,s,len);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
available = c->buflen-c->bufpos;
|
tail = listNodeValue(listLast(c->reply));
|
||||||
if (len > available) {
|
|
||||||
_ensureBufferInReplyList(c);
|
/* Append to this object when possible. */
|
||||||
_addReplyStringToBuffer(c,s,len);
|
if (tail->ptr != NULL &&
|
||||||
|
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
|
{
|
||||||
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
|
tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
|
||||||
} else {
|
} else {
|
||||||
memcpy(c->buf+c->bufpos,s,len);
|
incrRefCount(o);
|
||||||
c->bufpos += len;
|
listAddNodeTail(c->reply,o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method takes responsibility over the sds. When it is no longer
|
||||||
|
* needed it will be free'd, otherwise it ends up in a robj. */
|
||||||
|
void _addReplySdsToList(redisClient *c, sds s) {
|
||||||
|
robj *tail;
|
||||||
|
if (listLength(c->reply) == 0) {
|
||||||
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
||||||
|
} else {
|
||||||
|
tail = listNodeValue(listLast(c->reply));
|
||||||
|
|
||||||
|
/* Append to this object when possible. */
|
||||||
|
if (tail->ptr != NULL &&
|
||||||
|
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
|
{
|
||||||
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
|
tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
|
||||||
|
sdsfree(s);
|
||||||
|
} else {
|
||||||
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _addReplyStringToList(redisClient *c, char *s, size_t len) {
|
||||||
|
robj *tail;
|
||||||
|
if (listLength(c->reply) == 0) {
|
||||||
|
listAddNodeTail(c->reply,createStringObject(s,len));
|
||||||
|
} else {
|
||||||
|
tail = listNodeValue(listLast(c->reply));
|
||||||
|
|
||||||
|
/* Append to this object when possible. */
|
||||||
|
if (tail->ptr != NULL &&
|
||||||
|
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
|
||||||
|
{
|
||||||
|
tail = dupLastObjectIfNeeded(c->reply);
|
||||||
|
tail->ptr = sdscatlen(tail->ptr,s,len);
|
||||||
|
} else {
|
||||||
|
listAddNodeTail(c->reply,createStringObject(s,len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -118,13 +169,9 @@ void addReply(redisClient *c, robj *obj) {
|
|||||||
/* This increments the refcount. */
|
/* This increments the refcount. */
|
||||||
obj = getDecodedObject(obj);
|
obj = getDecodedObject(obj);
|
||||||
}
|
}
|
||||||
|
if (_addReplyToBuffer(c,obj->ptr,sdslen(obj->ptr)) != REDIS_OK)
|
||||||
if (sdslen(obj->ptr) < REDIS_REPLY_CHUNK_THRESHOLD) {
|
|
||||||
_addReplyStringToBuffer(c,obj->ptr,sdslen(obj->ptr));
|
|
||||||
decrRefCount(obj);
|
|
||||||
} else {
|
|
||||||
_addReplyObjectToList(c,obj);
|
_addReplyObjectToList(c,obj);
|
||||||
}
|
decrRefCount(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplySds(redisClient *c, sds s) {
|
void addReplySds(redisClient *c, sds s) {
|
||||||
@ -133,28 +180,25 @@ void addReplySds(redisClient *c, sds s) {
|
|||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (sdslen(s) < REDIS_REPLY_CHUNK_THRESHOLD) {
|
if (_addReplyToBuffer(c,s,sdslen(s)) == REDIS_OK) {
|
||||||
_addReplyStringToBuffer(c,s,sdslen(s));
|
|
||||||
sdsfree(s);
|
sdsfree(s);
|
||||||
} else {
|
} else {
|
||||||
_addReplyObjectToList(c,createObject(REDIS_STRING,s));
|
/* This method free's the sds when it is no longer needed. */
|
||||||
|
_addReplySdsToList(c,s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addReplyString(redisClient *c, char *s, size_t len) {
|
void addReplyString(redisClient *c, char *s, size_t len) {
|
||||||
if (_ensureFileEvent(c) != REDIS_OK) return;
|
if (_ensureFileEvent(c) != REDIS_OK) return;
|
||||||
if (len < REDIS_REPLY_CHUNK_THRESHOLD) {
|
if (_addReplyToBuffer(c,s,len) != REDIS_OK)
|
||||||
_addReplyStringToBuffer(c,s,len);
|
_addReplyStringToList(c,s,len);
|
||||||
} else {
|
|
||||||
_addReplyObjectToList(c,createStringObject(s,len));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Adds an empty object to the reply list that will contain the multi bulk
|
/* Adds an empty object to the reply list that will contain the multi bulk
|
||||||
* length, which is not known when this function is called. */
|
* length, which is not known when this function is called. */
|
||||||
void *addDeferredMultiBulkLength(redisClient *c) {
|
void *addDeferredMultiBulkLength(redisClient *c) {
|
||||||
if (_ensureFileEvent(c) != REDIS_OK) return NULL;
|
if (_ensureFileEvent(c) != REDIS_OK) return NULL;
|
||||||
_addReplyObjectToList(c,createObject(REDIS_STRING,NULL));
|
listAddNodeTail(c->reply,createObject(REDIS_STRING,NULL));
|
||||||
return listLast(c->reply);
|
return listLast(c->reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,9 +214,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
|
|||||||
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
|
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
|
||||||
if (ln->next != NULL) {
|
if (ln->next != NULL) {
|
||||||
next = listNodeValue(ln->next);
|
next = listNodeValue(ln->next);
|
||||||
/* Only glue when the next node is a reply chunk. */
|
|
||||||
if (next->type == REDIS_REPLY_NODE) {
|
/* Only glue when the next node is an sds */
|
||||||
len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
|
if (next->ptr != NULL) {
|
||||||
|
len->ptr = sdscat(len->ptr,next->ptr);
|
||||||
listDelNode(c->reply,ln->next);
|
listDelNode(c->reply,ln->next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,7 +196,6 @@ void decrRefCount(void *obj) {
|
|||||||
case REDIS_SET: freeSetObject(o); break;
|
case REDIS_SET: freeSetObject(o); break;
|
||||||
case REDIS_ZSET: freeZsetObject(o); break;
|
case REDIS_ZSET: freeZsetObject(o); break;
|
||||||
case REDIS_HASH: freeHashObject(o); break;
|
case REDIS_HASH: freeHashObject(o); break;
|
||||||
case REDIS_REPLY_NODE: freeStringObject(o); break;
|
|
||||||
default: redisPanic("Unknown object type"); break;
|
default: redisPanic("Unknown object type"); break;
|
||||||
}
|
}
|
||||||
o->ptr = NULL; /* defensive programming. We'll see NULL in traces. */
|
o->ptr = NULL; /* defensive programming. We'll see NULL in traces. */
|
||||||
|
11
src/redis.h
11
src/redis.h
@ -47,15 +47,7 @@
|
|||||||
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
|
#define REDIS_MAX_WRITE_PER_EVENT (1024*64)
|
||||||
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
|
#define REDIS_REQUEST_MAX_SIZE (1024*1024*256) /* max bytes in inline command */
|
||||||
#define REDIS_SHARED_INTEGERS 10000
|
#define REDIS_SHARED_INTEGERS 10000
|
||||||
|
#define REDIS_REPLY_CHUNK_BYTES (5*1500) /* 5 TCP packets with default MTU */
|
||||||
/* Size of a reply chunk, configured to exactly allocate 4k bytes */
|
|
||||||
#define REDIS_REPLY_CHUNK_BYTES (4*1024)
|
|
||||||
#define REDIS_REPLY_CHUNK_SIZE (REDIS_REPLY_CHUNK_BYTES-sizeof(struct sdshdr)-1-sizeof(size_t))
|
|
||||||
/* It doesn't make sense to memcpy objects to a chunk when the net result is
|
|
||||||
* not being able to glue other objects. We want to make sure it can be glued
|
|
||||||
* to at least a bulk length or \r\n, so set the threshold to be a couple
|
|
||||||
* of bytes less than the size of the buffer. */
|
|
||||||
#define REDIS_REPLY_CHUNK_THRESHOLD (REDIS_REPLY_CHUNK_SIZE-16)
|
|
||||||
|
|
||||||
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
|
/* If more then REDIS_WRITEV_THRESHOLD write packets are pending use writev */
|
||||||
#define REDIS_WRITEV_THRESHOLD 3
|
#define REDIS_WRITEV_THRESHOLD 3
|
||||||
@ -81,7 +73,6 @@
|
|||||||
#define REDIS_SET 2
|
#define REDIS_SET 2
|
||||||
#define REDIS_ZSET 3
|
#define REDIS_ZSET 3
|
||||||
#define REDIS_HASH 4
|
#define REDIS_HASH 4
|
||||||
#define REDIS_REPLY_NODE 5
|
|
||||||
#define REDIS_VMPOINTER 8
|
#define REDIS_VMPOINTER 8
|
||||||
|
|
||||||
/* Objects encoding. Some kind of objects like Strings and Hashes can be
|
/* Objects encoding. Some kind of objects like Strings and Hashes can be
|
||||||
|
Loading…
Reference in New Issue
Block a user