summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2012-06-15 10:03:25 +0200
committerantirez <antirez@gmail.com>2012-06-15 10:11:27 +0200
commit6fe9c402a2b9dcd3cb1a15aed08a86338ec143f3 (patch)
tree9236147f847d2ec33f74646cf91b993180854366 /src
parent8361d6c406fec73106c627159f28e092cedef1ee (diff)
downloadredis-6fe9c402a2b9dcd3cb1a15aed08a86338ec143f3.tar.gz
Fix c->reply_bytes computation in setDeferredMultiBulkLength()
In order to implement reply buffer limits introduced in 2.6 and useful to close the connection under user-selected circumastances of big output buffers (for instance slow consumers in pub/sub, a blocked slave, and so forth) Redis takes a counter with the amount of used memory in objects inside the output list stored into c->reply. The computation was broken in the function setDeferredMultiBulkLength(), in the case the object was glued with the next one. This caused the c->reply_bytes field to go out of sync, be subtracted more than needed, and wrap back near to ULONG_MAX values. This commit fixes this bug and adds an assertion that is able to trap this class of problems. This problem was discovered looking at the INFO output of an unrelated issue (issue #547).
Diffstat (limited to 'src')
-rw-r--r--src/networking.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/src/networking.c b/src/networking.c
index f922e2975..b3b7b94a7 100644
--- a/src/networking.c
+++ b/src/networking.c
@@ -364,7 +364,10 @@ void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
/* Only glue when the next node is non-NULL (an sds in this case) */
if (next->ptr != NULL) {
+ c->reply_bytes -= zmalloc_size_sds(len->ptr);
+ c->reply_bytes -= zmalloc_size_sds(next->ptr);
len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
+ c->reply_bytes += zmalloc_size_sds(len->ptr);
listDelNode(c->reply,ln->next);
}
}
@@ -1302,6 +1305,7 @@ int checkClientOutputBufferLimits(redisClient *c) {
* called from contexts where the client can't be freed safely, i.e. from the
* lower level functions pushing data inside the client output buffers. */
void asyncCloseClientOnOutputBufferLimitReached(redisClient *c) {
+ redisAssert(c->reply_bytes < ULONG_MAX-(1024*64));
if (c->reply_bytes == 0 || c->flags & REDIS_CLOSE_ASAP) return;
if (checkClientOutputBufferLimits(c)) {
sds client = getClientInfoString(c);