static void setProtocolError(redisClient *c, int pos);
+/* To evaluate the output buffer size of a client we need to get size of
+ * allocated objects, however we can't used zmalloc_size() directly on sds
+ * strings because of the trick they use to work (the header is before the
+ * returned pointer), so we use this helper function. */
+size_t zmalloc_size_sds(sds s) {
+ return zmalloc_size(s-sizeof(struct sdshdr));
+}
+
void *dupClientReplyValue(void *o) {
incrRefCount((robj*)o);
return o;
if (listLength(c->reply) == 0) {
incrRefCount(o);
listAddNodeTail(c->reply,o);
+ c->reply_bytes += zmalloc_size_sds(o->ptr);
} else {
tail = listNodeValue(listLast(c->reply));
if (tail->ptr != NULL &&
sdslen(tail->ptr)+sdslen(o->ptr) <= REDIS_REPLY_CHUNK_BYTES)
{
+ c->reply_bytes -= zmalloc_size_sds(tail->ptr);
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,o->ptr,sdslen(o->ptr));
+ c->reply_bytes += zmalloc_size_sds(tail->ptr);
} else {
incrRefCount(o);
listAddNodeTail(c->reply,o);
+ c->reply_bytes += zmalloc_size_sds(o->ptr);
}
}
- c->reply_bytes += zmalloc_size(o->ptr);
asyncCloseClientOnOutputBufferLimitReached(c);
}
return;
}
- c->reply_bytes += zmalloc_size(s);
if (listLength(c->reply) == 0) {
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
+ c->reply_bytes += zmalloc_size_sds(s);
} else {
tail = listNodeValue(listLast(c->reply));
if (tail->ptr != NULL &&
sdslen(tail->ptr)+sdslen(s) <= REDIS_REPLY_CHUNK_BYTES)
{
+ c->reply_bytes -= zmalloc_size_sds(tail->ptr);
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,s,sdslen(s));
+ c->reply_bytes += zmalloc_size_sds(tail->ptr);
sdsfree(s);
} else {
listAddNodeTail(c->reply,createObject(REDIS_STRING,s));
+ c->reply_bytes += zmalloc_size_sds(s);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size(o->ptr);
+ c->reply_bytes += zmalloc_size_sds(o->ptr);
} else {
tail = listNodeValue(listLast(c->reply));
if (tail->ptr != NULL &&
sdslen(tail->ptr)+len <= REDIS_REPLY_CHUNK_BYTES)
{
- c->reply_bytes -= zmalloc_size(tail->ptr);
+ c->reply_bytes -= zmalloc_size_sds(tail->ptr);
tail = dupLastObjectIfNeeded(c->reply);
tail->ptr = sdscatlen(tail->ptr,s,len);
- c->reply_bytes += zmalloc_size(tail->ptr);
+ c->reply_bytes += zmalloc_size_sds(tail->ptr);
} else {
robj *o = createStringObject(s,len);
listAddNodeTail(c->reply,o);
- c->reply_bytes += zmalloc_size(o->ptr);
+ c->reply_bytes += zmalloc_size_sds(o->ptr);
}
}
asyncCloseClientOnOutputBufferLimitReached(c);
len = listNodeValue(ln);
len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
- c->reply_bytes += zmalloc_size(len->ptr);
+ c->reply_bytes += zmalloc_size_sds(len->ptr);
if (ln->next != NULL) {
next = listNodeValue(ln->next);
} else {
o = listNodeValue(listFirst(c->reply));
objlen = sdslen(o->ptr);
- objmem = zmalloc_size(o->ptr);
+ objmem = zmalloc_size_sds(o->ptr);
if (objlen == 0) {
listDelNode(c->reply,listFirst(c->reply));
int freeMemoryIfNeeded(void) {
size_t mem_used, mem_tofree, mem_freed;
int slaves = listLength(server.slaves);
+ static time_t xt;
+ int debug = 0;
+
+ if (xt != time(NULL)) {
+ debug = 1;
+ xt = time(NULL);
+ }
/* Remove the size of slaves output buffers and AOF buffer from the
* count of used memory. */
mem_used = zmalloc_used_memory();
+ if (debug) printf("used_full: %zu\n", mem_used);
if (slaves) {
listIter li;
listNode *ln;
mem_used -= obuf_bytes;
}
}
+ if (debug) printf("used_nosl: %zu\n", mem_used);
if (server.aof_state != REDIS_AOF_OFF) {
mem_used -= sdslen(server.aof_buf);
mem_used -= sdslen(server.aof_rewrite_buf);
/* Compute how much memory we need to free. */
mem_tofree = mem_used - server.maxmemory;
mem_freed = 0;
+ if (debug) printf("tofree: %zu\n", mem_tofree);
while (mem_freed < mem_tofree) {
int j, k, keys_freed = 0;
if (slaves) flushSlavesOutputBuffers();
}
}
- if (!keys_freed) return REDIS_ERR; /* nothing to free... */
+ if (!keys_freed) {
+ if (debug) printf("-freed: %zu\n\n", mem_freed);
+ return REDIS_ERR; /* nothing to free... */
+ }
}
+ if (debug) printf("+freed: %zu\n\n", mem_freed);
return REDIS_OK;
}