]> git.saurik.com Git - redis.git/commitdiff
Reclaim space from the client querybuf if needed.
authorantirez <antirez@gmail.com>
Wed, 14 Mar 2012 14:32:30 +0000 (15:32 +0100)
committerantirez <antirez@gmail.com>
Wed, 14 Mar 2012 14:32:30 +0000 (15:32 +0100)
src/aof.c
src/networking.c
src/redis.c
src/redis.h

index 64cd76d3d76abf9a965b532e135fd161b8dd0696..83633217f796354649929880f6ed509cad552f32 100644 (file)
--- a/src/aof.c
+++ b/src/aof.c
@@ -287,6 +287,7 @@ struct redisClient *createFakeClient(void) {
     selectDb(c,0);
     c->fd = -1;
     c->querybuf = sdsempty();
+    c->querybuf_peak = 0;
     c->argc = 0;
     c->argv = NULL;
     c->bufpos = 0;
index ae77d11b231cd1376e0e4b81df3ff48f04827b9a..375186d1e01b29ce35d38b4a5b3341955e018d47 100644 (file)
@@ -43,6 +43,7 @@ redisClient *createClient(int fd) {
     c->fd = fd;
     c->bufpos = 0;
     c->querybuf = sdsempty();
+    c->querybuf_peak = 0;
     c->reqtype = 0;
     c->argc = 0;
     c->argv = NULL;
@@ -998,6 +999,7 @@ void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {
     }
 
     qblen = sdslen(c->querybuf);
+    if (c->querybuf_peak < qblen) c->querybuf_peak = qblen;
     c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);
     nread = read(fd, c->querybuf+qblen, readlen);
     if (nread == -1) {
index f46f2376d7e53a181ec28a0cc3d1c906c300fac1..5388f5b72e8627f0bab94cc765081f06fe9b880e 100644 (file)
@@ -642,7 +642,7 @@ long long getOperationsPerSecond(void) {
 }
 
 void clientsCronHandleTimeout(redisClient *c) {
-    time_t now = time(NULL);
+    time_t now = server.unixtime;
 
     if (server.maxidletime &&
         !(c->flags & REDIS_SLAVE) &&    /* no timeout for slaves */
@@ -662,15 +662,40 @@ void clientsCronHandleTimeout(redisClient *c) {
     }
 }
 
+/* The client query buffer is an sds.c string that can end with a lot of
+ * free space not used, this function reclaims space if needed. */
+void clientsCronResizeQueryBuffer(redisClient *c) {
+    size_t querybuf_size = sdsAllocSize(c->querybuf);
+    time_t idletime = server.unixtime - c->lastinteraction;
+
+    /* There are two conditions to resize the query buffer:
+     * 1) Query buffer is > BIG_ARG and too big for latest peak.
+     * 2) Client is inactive and the buffer is bigger than 1k. */
+    if (((querybuf_size > REDIS_MBULK_BIG_ARG) &&
+         (querybuf_size/(c->querybuf_peak+1)) > 2) ||
+         (querybuf_size > 1024 && idletime > 2))
+    {
+        /* Only resize the query buffer if it is actually wasting space. */
+        if (sdsavail(c->querybuf) > 1024) {
+            c->querybuf = sdsRemoveFreeSpace(c->querybuf);
+        }
+    }
+    /* Reset the peak again to capture the peak memory usage in the next
+     * cycle. */
+    c->querybuf_peak = 0;
+}
+
 void clientsCron(void) {
     /* Make sure to process at least 1/100 of clients per call.
      * Since this function is called 10 times per second we are sure that
      * in the worst case we process all the clients in 10 seconds.
      * In normal conditions (a reasonable number of clients) we process
      * all the clients in a shorter time. */
-    int iterations = listLength(server.clients)/100;
-    if (iterations < 50) iterations = 50;
+    int numclients = listLength(server.clients);
+    int iterations = numclients/100;
 
+    if (iterations < 50)
+        iterations = (numclients < 50) ? numclients : 50;
     while(listLength(server.clients) && iterations--) {
         redisClient *c;
         listNode *head;
@@ -682,6 +707,7 @@ void clientsCron(void) {
         head = listFirst(server.clients);
         c = listNodeValue(head);
         clientsCronHandleTimeout(c);
+        clientsCronResizeQueryBuffer(c);
     }
 }
 
index 1d1f572b37130a3e5a843d35805abc9730a63356..49b69523738cbfac33cb2fe9b75c868380390b8b 100644 (file)
@@ -323,6 +323,7 @@ typedef struct redisClient {
     redisDb *db;
     int dictid;
     sds querybuf;
+    size_t querybuf_peak;   /* Recent (100ms or more) peak of querybuf size */
     int argc;
     robj **argv;
     struct redisCommand *cmd, *lastcmd;