]> git.saurik.com Git - redis.git/blobdiff - redis.c
fix small error and memory leaks in SORT
[redis.git] / redis.c
diff --git a/redis.c b/redis.c
index 4627c681cccd9737f41afea182430050873bf8f2..1bdd14217c76be46a41842343b3c954923d9f5bd 100644 (file)
--- a/redis.c
+++ b/redis.c
@@ -6066,10 +6066,8 @@ static void hashTryConversion(robj *subject, robj **argv, int start, int end) {
 }
 
 /* Get the value from a hash identified by key. Returns either a string
- * object or NULL if the value cannot be found.
- * Note: the refcount for objects retrieved from a zipmap is set to 0.
- * This is done, so addReply will increment and clean up the object.
- * Make sure to clean up the object when it isn't added to a reply. */
+ * object or NULL if the value cannot be found. The refcount of the object
+ * is always increased by 1 when the value was found. */
 static robj *hashGet(robj *o, robj *key) {
     robj *value = NULL;
     if (o->encoding == REDIS_ENCODING_ZIPMAP) {
@@ -6078,13 +6076,13 @@ static robj *hashGet(robj *o, robj *key) {
         key = getDecodedObject(key);
         if (zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),&v,&vlen)) {
             value = createStringObject((char*)v,vlen);
-            value->refcount = 0;
         }
         decrRefCount(key);
     } else {
         dictEntry *de = dictFind(o->ptr,key);
         if (de != NULL) {
             value = dictGetEntryVal(de);
+            incrRefCount(value);
         }
     }
     return value;
@@ -6207,8 +6205,7 @@ static int hashNext(hashIterator *hi) {
 }
 
 /* Get key or value object at current iteration position.
- * See comments at hashGet for a discussion on the refcount for
- * keys and values retrieved from zipmaps. */
+ * This increases the refcount of the field object by 1. */
 static robj *hashCurrent(hashIterator *hi, int what) {
     robj *o;
     if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
@@ -6217,13 +6214,13 @@ static robj *hashCurrent(hashIterator *hi, int what) {
         } else {
             o = createStringObject((char*)hi->zv,hi->zvlen);
         }
-        o->refcount = 0;
     } else {
         if (what & REDIS_HASH_KEY) {
             o = dictGetEntryKey(hi->de);
         } else {
             o = dictGetEntryVal(hi->de);
         }
+        incrRefCount(o);
     }
     return o;
 }
@@ -6299,12 +6296,7 @@ static void hincrbyCommand(redisClient *c) {
             value = (long)current->ptr;
         else
             redisAssert(1 != 1);
-
-        /* clean up object when it was retrieved from a zipmap */
-        if (current->refcount == 0) {
-            current->refcount = 1;
-            decrRefCount(current);
-        }
+        decrRefCount(current);
     } else {
         value = 0;
     }
@@ -6324,6 +6316,7 @@ static void hgetCommand(redisClient *c) {
 
     if ((value = hashGet(o,c->argv[2])) != NULL) {
         addReplyBulk(c,value);
+        decrRefCount(value);
     } else {
         addReply(c,shared.nullbulk);
     }
@@ -6344,6 +6337,7 @@ static void hmgetCommand(redisClient *c) {
     for (i = 2; i < c->argc; i++) {
         if (o != NULL && (value = hashGet(o,c->argv[i])) != NULL) {
             addReplyBulk(c,value);
+            decrRefCount(value);
         } else {
             addReply(c,shared.nullbulk);
         }
@@ -6389,11 +6383,13 @@ static void genericHgetallCommand(redisClient *c, int flags) {
         if (flags & REDIS_HASH_KEY) {
             obj = hashCurrent(hi,REDIS_HASH_KEY);
             addReplyBulk(c,obj);
+            decrRefCount(obj);
             count++;
         }
         if (flags & REDIS_HASH_VALUE) {
             obj = hashCurrent(hi,REDIS_HASH_VALUE);
             addReplyBulk(c,obj);
+            decrRefCount(obj);
             count++;
         }
     }
@@ -6471,7 +6467,9 @@ static redisSortOperation *createSortOperation(int type, robj *pattern) {
 }
 
 /* Return the value associated to the key with a name obtained
- * substituting the first occurence of '*' in 'pattern' with 'subst' */
+ * substituting the first occurence of '*' in 'pattern' with 'subst'.
+ * The returned object will always have its refcount increased by 1
+ * when it is non-NULL. */
 static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
     char *p, *f;
     sds spat, ssub;
@@ -6488,6 +6486,7 @@ static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
      * to implement the "SORT ... GET #" feature. */
     spat = pattern->ptr;
     if (spat[0] == '#' && spat[1] == '\0') {
+        incrRefCount(subst);
         return subst;
     }
 
@@ -6527,14 +6526,21 @@ static robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
     /* Lookup substituted key */
     initStaticStringObject(keyobj,((char*)&keyname)+(sizeof(long)*2));
     o = lookupKeyRead(db,&keyobj);
+    if (o == NULL) return NULL;
 
-    /* Retrieve value from hash by the field name */
-    if (o != NULL && fieldlen > 0) {
-        if (o->type != REDIS_HASH || fieldname.len < 1) {
-            return NULL;
-        }
+    if (fieldlen > 0) {
+        if (o->type != REDIS_HASH || fieldname.len < 1) return NULL;
+
+        /* Retrieve value from hash by the field name. This operation
+         * already increases the refcount of the returned object. */
         initStaticStringObject(fieldobj,((char*)&fieldname)+(sizeof(long)*2));
         o = hashGet(o, &fieldobj);
+    } else {
+        if (o->type != REDIS_STRING) return NULL;
+
+        /* Every object that this function returns needs to have its refcount
+         * increased. sortCommand decreases it again. */
+        incrRefCount(o);
     }
 
     return o;
@@ -6705,15 +6711,13 @@ static void sortCommand(redisClient *c) {
             if (sortby) {
                 /* lookup value to sort by */
                 byval = lookupKeyByPattern(c->db,sortby,vector[j].obj);
-                if (!byval || byval->type != REDIS_STRING) continue;
+                if (!byval) continue;
             } else {
                 /* use object itself to sort by */
                 byval = vector[j].obj;
             }
 
             if (alpha) {
-                /* getDecodedObject increments refcount, so the corresponding
-                 * decrRefCount will clean up values coming from a zipmap. */
                 vector[j].u.cmpobj = getDecodedObject(byval);
             } else {
                 if (byval->encoding == REDIS_ENCODING_RAW) {
@@ -6726,12 +6730,12 @@ static void sortCommand(redisClient *c) {
                 } else {
                     redisAssert(1 != 1);
                 }
+            }
 
-                /* clean up immediately if this value came from a zipmap */
-                if (byval->refcount == 0) {
-                    byval->refcount = 1;
-                    decrRefCount(byval);
-                }
+            /* when the object was retrieved using lookupKeyByPattern,
+             * its refcount needs to be decreased. */
+            if (sortby) {
+                decrRefCount(byval);
             }
         }
     }
@@ -6774,10 +6778,11 @@ static void sortCommand(redisClient *c) {
                     vector[j].obj);
 
                 if (sop->type == REDIS_SORT_GET) {
-                    if (!val || val->type != REDIS_STRING) {
+                    if (!val) {
                         addReply(c,shared.nullbulk);
                     } else {
                         addReplyBulk(c,val);
+                        decrRefCount(val);
                     }
                 } else {
                     redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
@@ -6804,11 +6809,14 @@ static void sortCommand(redisClient *c) {
                     vector[j].obj);
 
                 if (sop->type == REDIS_SORT_GET) {
-                    if (!val || val->type != REDIS_STRING) {
+                    if (!val) {
                         listAddNodeTail(listPtr,createStringObject("",0));
                     } else {
+                        /* We should do a incrRefCount on val because it is
+                         * added to the list, but also a decrRefCount because
+                         * it is returned by lookupKeyByPattern. This results
+                         * in doing nothing at all. */
                         listAddNodeTail(listPtr,val);
-                        incrRefCount(val);
                     }
                 } else {
                     redisAssert(sop->type == REDIS_SORT_GET); /* always fails */
@@ -7065,7 +7073,7 @@ static void expireGenericCommand(redisClient *c, robj *key, robj *param, long of
         addReply(c,shared.czero);
         return;
     }
-    if (seconds < 0) {
+    if (seconds <= 0) {
         if (deleteKey(c->db,key)) server.dirty++;
         addReply(c, shared.cone);
         return;