]> git.saurik.com Git - redis.git/commitdiff
Wrapper for adding unknown multi bulk length to reply list
authorPieter Noordhuis <pcnoordhuis@gmail.com>
Mon, 30 Aug 2010 14:02:06 +0000 (16:02 +0200)
committerPieter Noordhuis <pcnoordhuis@gmail.com>
Mon, 30 Aug 2010 14:39:14 +0000 (16:39 +0200)
src/config.c
src/db.c
src/networking.c
src/redis.h
src/t_hash.c
src/t_set.c
src/t_zset.c

index e1b743dbf41ace2c6b41a9b10ef1cd65aac0455b..5c449886939117e6e6300492671c7d58d5dfb068 100644 (file)
@@ -332,13 +332,10 @@ badfmt: /* Bad format errors */
 
 void configGetCommand(redisClient *c) {
     robj *o = getDecodedObject(c->argv[2]);
-    robj *lenobj = createObject(REDIS_STRING,NULL);
+    void *replylen = addDeferredMultiBulkLength(c);
     char *pattern = o->ptr;
     int matches = 0;
 
-    addReply(c,lenobj);
-    decrRefCount(lenobj);
-
     if (stringmatch(pattern,"dbfilename",0)) {
         addReplyBulkCString(c,"dbfilename");
         addReplyBulkCString(c,server.dbfilename);
@@ -410,7 +407,7 @@ void configGetCommand(redisClient *c) {
         matches++;
     }
     decrRefCount(o);
-    lenobj->ptr = sdscatprintf(sdsempty(),"*%d\r\n",matches*2);
+    setDeferredMultiBulkLength(c,replylen,matches*2);
 }
 
 void configCommand(redisClient *c) {
index 6d287d72c914762eef4ec17eb08a2f324df71e58..8c6c6bc82d4c2cb2610e692875651e6a59fa7fe7 100644 (file)
--- a/src/db.c
+++ b/src/db.c
@@ -223,11 +223,9 @@ void keysCommand(redisClient *c) {
     sds pattern = c->argv[1]->ptr;
     int plen = sdslen(pattern);
     unsigned long numkeys = 0;
-    robj *lenobj = createObject(REDIS_STRING,NULL);
+    void *replylen = addDeferredMultiBulkLength(c);
 
     di = dictGetIterator(c->db->dict);
-    addReply(c,lenobj);
-    decrRefCount(lenobj);
     while((de = dictNext(di)) != NULL) {
         sds key = dictGetEntryKey(de);
         robj *keyobj;
@@ -243,7 +241,7 @@ void keysCommand(redisClient *c) {
         }
     }
     dictReleaseIterator(di);
-    lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",numkeys);
+    setDeferredMultiBulkLength(c,replylen,numkeys);
 }
 
 void dbsizeCommand(redisClient *c) {
index da0cd0a16343319089523564d52c033cf6432007..464d5e02cc8f9ff95940dbf25e412bce8bf27ec0 100644 (file)
@@ -145,6 +145,34 @@ void addReplyString(redisClient *c, char *s, size_t len) {
     }
 }
 
+/* Adds an empty object to the reply list that will contain the multi bulk
+ * length, which is not known when this function is called. */
+void *addDeferredMultiBulkLength(redisClient *c) {
+    if (_ensureFileEvent(c) != REDIS_OK) return NULL;
+    _addReplyObjectToList(c,createObject(REDIS_STRING,NULL));
+    return listLast(c->reply);
+}
+
+/* Populate the length object and try glueing it to the next chunk. */
+void setDeferredMultiBulkLength(redisClient *c, void *node, long length) {
+    listNode *ln = (listNode*)node;
+    robj *len, *next;
+
+    /* Abort when *node is NULL (see addDeferredMultiBulkLength). */
+    if (node == NULL) return;
+
+    len = listNodeValue(ln);
+    len->ptr = sdscatprintf(sdsempty(),"*%ld\r\n",length);
+    if (ln->next != NULL) {
+        next = listNodeValue(ln->next);
+        /* Only glue when the next node is a reply chunk. */
+        if (next->type == REDIS_REPLY_NODE) {
+            len->ptr = sdscatlen(len->ptr,next->ptr,sdslen(next->ptr));
+            listDelNode(c->reply,ln->next);
+        }
+    }
+}
+
 void addReplyDouble(redisClient *c, double d) {
     char dbuf[128], sbuf[128];
     int dlen, slen;
index e2f694543166aa71fd9a4e6ee7c9e54cbd4413dc..752d56c301e48e60c0f3873d2cc2e93c80717363 100644 (file)
@@ -603,6 +603,8 @@ void resetClient(redisClient *c);
 void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask);
 void sendReplyToClientWritev(aeEventLoop *el, int fd, void *privdata, int mask);
 void addReply(redisClient *c, robj *obj);
+void *addDeferredMultiBulkLength(redisClient *c);
+void setDeferredMultiBulkLength(redisClient *c, void *node, long length);
 void addReplySds(redisClient *c, sds s);
 void processInputBuffer(redisClient *c);
 void acceptHandler(aeEventLoop *el, int fd, void *privdata, int mask);
index b6be284fa12d58bce12ccc8808c7a481f20453e2..c8be72f2d3ec8b0fd17366e3f70721e8af04d56f 100644 (file)
@@ -350,17 +350,15 @@ void hlenCommand(redisClient *c) {
 }
 
 void genericHgetallCommand(redisClient *c, int flags) {
-    robj *o, *lenobj, *obj;
+    robj *o, *obj;
     unsigned long count = 0;
     hashTypeIterator *hi;
+    void *replylen = NULL;
 
     if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
         || checkType(c,o,REDIS_HASH)) return;
 
-    lenobj = createObject(REDIS_STRING,NULL);
-    addReply(c,lenobj);
-    decrRefCount(lenobj);
-
+    replylen = addDeferredMultiBulkLength(c);
     hi = hashTypeInitIterator(o);
     while (hashTypeNext(hi) != REDIS_ERR) {
         if (flags & REDIS_HASH_KEY) {
@@ -377,8 +375,7 @@ void genericHgetallCommand(redisClient *c, int flags) {
         }
     }
     hashTypeReleaseIterator(hi);
-
-    lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",count);
+    setDeferredMultiBulkLength(c,replylen,count);
 }
 
 void hkeysCommand(redisClient *c) {
index 68e132278f96c938e605490e6ed55aff46177ef8..d6041e72489f24c68f7ce50354706f0c4de0473b 100644 (file)
@@ -320,7 +320,8 @@ int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
 void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, robj *dstkey) {
     robj **sets = zmalloc(sizeof(robj*)*setnum);
     setTypeIterator *si;
-    robj *ele, *lenobj = NULL, *dstset = NULL;
+    robj *ele, *dstset = NULL;
+    void *replylen = NULL;
     unsigned long j, cardinality = 0;
 
     for (j = 0; j < setnum; j++) {
@@ -356,9 +357,7 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
      * to the output list and save the pointer to later modify it with the
      * right length */
     if (!dstkey) {
-        lenobj = createObject(REDIS_STRING,NULL);
-        addReply(c,lenobj);
-        decrRefCount(lenobj);
+        replylen = addDeferredMultiBulkLength(c);
     } else {
         /* If we have a target key where to store the resulting set
          * create this key with an empty set inside */
@@ -400,7 +399,7 @@ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum,
         touchWatchedKey(c->db,dstkey);
         server.dirty++;
     } else {
-        lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",cardinality);
+        setDeferredMultiBulkLength(c,replylen,cardinality);
     }
     zfree(sets);
 }
index e93e5c406a5cb2088b134aeea7cbc249995ac83d..d25b1a669996347b064fa46f469bff99bd1fbba8 100644 (file)
@@ -866,7 +866,8 @@ void genericZrangebyscoreCommand(redisClient *c, int justcount) {
             zset *zsetobj = o->ptr;
             zskiplist *zsl = zsetobj->zsl;
             zskiplistNode *ln;
-            robj *ele, *lenobj = NULL;
+            robj *ele;
+            void *replylen = NULL;
             unsigned long rangelen = 0;
 
             /* Get the first node with the score >= min, or with
@@ -884,11 +885,8 @@ void genericZrangebyscoreCommand(redisClient *c, int justcount) {
              * are in the list, so we push this object that will represent
              * the multi-bulk length in the output buffer, and will "fix"
              * it later */
-            if (!justcount) {
-                lenobj = createObject(REDIS_STRING,NULL);
-                addReply(c,lenobj);
-                decrRefCount(lenobj);
-            }
+            if (!justcount)
+                replylen = addDeferredMultiBulkLength(c);
 
             while(ln && (maxex ? (ln->score < max) : (ln->score <= max))) {
                 if (offset) {
@@ -910,7 +908,7 @@ void genericZrangebyscoreCommand(redisClient *c, int justcount) {
             if (justcount) {
                 addReplyLongLong(c,(long)rangelen);
             } else {
-                lenobj->ptr = sdscatprintf(sdsempty(),"*%lu\r\n",
+                setDeferredMultiBulkLength(c,replylen,
                      withscores ? (rangelen*2) : rangelen);
             }
         }