Hash new implementation memleaks fixed.

This commit is contained in:
antirez 2015-09-23 11:43:28 +02:00
parent 97ba4e3886
commit 1dab60df81
2 changed files with 52 additions and 12 deletions

View File

@ -1334,7 +1334,6 @@ void hashTypeConvert(robj *o, int enc);
void hashTypeTryConversion(robj *subject, robj **argv, int start, int end); void hashTypeTryConversion(robj *subject, robj **argv, int start, int end);
void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2); void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2);
int hashTypeExists(robj *o, sds key); int hashTypeExists(robj *o, sds key);
int hashTypeSet(robj *o, sds key, sds value);
int hashTypeDelete(robj *o, sds key); int hashTypeDelete(robj *o, sds key);
unsigned long hashTypeLength(robj *o); unsigned long hashTypeLength(robj *o);
hashTypeIterator *hashTypeInitIterator(robj *subject); hashTypeIterator *hashTypeInitIterator(robj *subject);

View File

@ -179,9 +179,27 @@ int hashTypeExists(robj *o, sds field) {
} }
/* Add a new field, overwrite the old with the new value if it already exists. /* Add a new field, overwrite the old with the new value if it already exists.
* Return 0 on insert and 1 on update. The key and value SDS strings are copied * Return 0 on insert and 1 on update.
* if needed, so the caller retains ownership of the strings passed. */ *
int hashTypeSet(robj *o, sds field, sds value) { * By default, the key and value SDS strings are copied if needed, so the
* caller retains ownership of the strings passed. However this behavior
* can be effected by passing appropriate flags (possibly bitwise OR-ed):
*
* HASH_SET_TAKE_FIELD -- The SDS field ownership passes to the function.
* HASH_SET_TAKE_VALUE -- The SDS value ownership passes to the function.
*
* When the flags are used the caller does not need to release the passed
* SDS string(s). It's up to the function to use the string to create a new
* entry or to free the SDS string before returning to the caller.
*
* HASH_SET_COPY corresponds to no flags passed, and means the default
* semantics of copying the values if needed.
*
*/
#define HASH_SET_TAKE_FIELD (1<<0)
#define HASH_SET_TAKE_VALUE (1<<1)
#define HASH_SET_COPY 0
int hashTypeSet(robj *o, sds field, sds value, int flags) {
int update = 0; int update = 0;
if (o->encoding == OBJ_ENCODING_ZIPLIST) { if (o->encoding == OBJ_ENCODING_ZIPLIST) {
@ -222,14 +240,37 @@ int hashTypeSet(robj *o, sds field, sds value) {
dictEntry *de = dictFind(o->ptr,field); dictEntry *de = dictFind(o->ptr,field);
if (de) { if (de) {
sdsfree(dictGetVal(de)); sdsfree(dictGetVal(de));
if (flags & HASH_SET_TAKE_VALUE) {
dictGetVal(de) = value;
value = NULL;
} else {
dictGetVal(de) = sdsdup(value); dictGetVal(de) = sdsdup(value);
}
update = 1; update = 1;
} else { } else {
dictAdd(o->ptr,sdsdup(field),sdsdup(value)); sds f,v;
if (flags & HASH_SET_TAKE_FIELD) {
f = field;
field = NULL;
} else {
f = sdsdup(field);
}
if (flags & HASH_SET_TAKE_VALUE) {
v = value;
value = NULL;
} else {
v = sdsdup(value);
}
dictAdd(o->ptr,f,v);
} }
} else { } else {
serverPanic("Unknown hash encoding"); serverPanic("Unknown hash encoding");
} }
/* Free SDS strings we did not referenced elsewhere if the flags
* want this function to be responsible. */
if (flags & HASH_SET_TAKE_FIELD && field) sdsfree(field);
if (flags & HASH_SET_TAKE_VALUE && value) sdsfree(value);
return update; return update;
} }
@ -476,7 +517,7 @@ void hsetCommand(client *c) {
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
hashTypeTryConversion(o,c->argv,2,3); hashTypeTryConversion(o,c->argv,2,3);
update = hashTypeSet(o,c->argv[2]->ptr,c->argv[3]->ptr); update = hashTypeSet(o,c->argv[2]->ptr,c->argv[3]->ptr,HASH_SET_COPY);
addReply(c, update ? shared.czero : shared.cone); addReply(c, update ? shared.czero : shared.cone);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id);
@ -491,7 +532,7 @@ void hsetnxCommand(client *c) {
if (hashTypeExists(o, c->argv[2]->ptr)) { if (hashTypeExists(o, c->argv[2]->ptr)) {
addReply(c, shared.czero); addReply(c, shared.czero);
} else { } else {
hashTypeSet(o,c->argv[2]->ptr,c->argv[3]->ptr); hashTypeSet(o,c->argv[2]->ptr,c->argv[3]->ptr,HASH_SET_COPY);
addReply(c, shared.cone); addReply(c, shared.cone);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_HASH,"hset",c->argv[1],c->db->id);
@ -511,7 +552,7 @@ void hmsetCommand(client *c) {
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
hashTypeTryConversion(o,c->argv,2,c->argc-1); hashTypeTryConversion(o,c->argv,2,c->argc-1);
for (i = 2; i < c->argc; i += 2) { for (i = 2; i < c->argc; i += 2) {
hashTypeSet(o,c->argv[i]->ptr,c->argv[i+1]->ptr); hashTypeSet(o,c->argv[i]->ptr,c->argv[i+1]->ptr,HASH_SET_COPY);
} }
addReply(c, shared.ok); addReply(c, shared.ok);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
@ -547,7 +588,7 @@ void hincrbyCommand(client *c) {
} }
value += incr; value += incr;
new = sdsfromlonglong(value); new = sdsfromlonglong(value);
hashTypeSet(o,c->argv[2]->ptr,new); hashTypeSet(o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE);
addReplyLongLong(c,value); addReplyLongLong(c,value);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_HASH,"hincrby",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_HASH,"hincrby",c->argv[1],c->db->id);
@ -582,8 +623,8 @@ void hincrbyfloatCommand(client *c) {
char buf[256]; char buf[256];
int len = ld2string(buf,sizeof(buf),value,1); int len = ld2string(buf,sizeof(buf),value,1);
new = sdsnewlen(buf,len); new = sdsnewlen(buf,len);
hashTypeSet(o,c->argv[2]->ptr,new); hashTypeSet(o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE);
addReplyBulkSds(c,new); addReplyBulkCBuffer(c,buf,len);
signalModifiedKey(c->db,c->argv[1]); signalModifiedKey(c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_HASH,"hincrbyfloat",c->argv[1],c->db->id); notifyKeyspaceEvent(NOTIFY_HASH,"hincrbyfloat",c->argv[1],c->db->id);
server.dirty++; server.dirty++;