}
/* 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) {
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;
}
/* 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) {
} 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;
}
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;
}
if ((value = hashGet(o,c->argv[2])) != NULL) {
addReplyBulk(c,value);
+ decrRefCount(value);
} else {
addReply(c,shared.nullbulk);
}
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);
}
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++;
}
}
}
/* 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;
* to implement the "SORT ... GET #" feature. */
spat = pattern->ptr;
if (spat[0] == '#' && spat[1] == '\0') {
+ incrRefCount(subst);
return 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;
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) {
} 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);
}
}
}
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 */
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 */
addReply(c,shared.czero);
return;
}
- if (seconds < 0) {
+ if (seconds <= 0) {
if (deleteKey(c->db,key)) server.dirty++;
addReply(c, shared.cone);
return;