mirror of
https://github.com/fluencelabs/redis
synced 2025-04-13 12:46:03 +00:00
Lazyfree: Hash converted to use plain SDS WIP 4.
This commit is contained in:
parent
4a18352877
commit
974514b936
12
src/aof.c
12
src/aof.c
@ -928,17 +928,13 @@ static int rioWriteHashIteratorCursor(rio *r, hashTypeIterator *hi, int what) {
|
|||||||
long long vll = LLONG_MAX;
|
long long vll = LLONG_MAX;
|
||||||
|
|
||||||
hashTypeCurrentFromZiplist(hi, what, &vstr, &vlen, &vll);
|
hashTypeCurrentFromZiplist(hi, what, &vstr, &vlen, &vll);
|
||||||
if (vstr) {
|
if (vstr)
|
||||||
return rioWriteBulkString(r, (char*)vstr, vlen);
|
return rioWriteBulkString(r, (char*)vstr, vlen);
|
||||||
} else {
|
else
|
||||||
return rioWriteBulkLongLong(r, vll);
|
return rioWriteBulkLongLong(r, vll);
|
||||||
}
|
|
||||||
|
|
||||||
} else if (hi->encoding == OBJ_ENCODING_HT) {
|
} else if (hi->encoding == OBJ_ENCODING_HT) {
|
||||||
robj *value;
|
sds value = hashTypeCurrentFromHashTable(hi, what);
|
||||||
|
return rioWriteBulkString(r, value, sdslen(value));
|
||||||
hashTypeCurrentFromHashTable(hi, what, &value);
|
|
||||||
return rioWriteBulkObject(r, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverPanic("Unknown hash encoding");
|
serverPanic("Unknown hash encoding");
|
||||||
|
8
src/db.c
8
src/db.c
@ -420,11 +420,11 @@ void scanCallback(void *privdata, const dictEntry *de) {
|
|||||||
} else if (o->type == OBJ_HASH) {
|
} else if (o->type == OBJ_HASH) {
|
||||||
sds sdskey = dictGetKey(de);
|
sds sdskey = dictGetKey(de);
|
||||||
sds sdsval = dictGetVal(de);
|
sds sdsval = dictGetVal(de);
|
||||||
key = createStringObject(keysds,sdslen(keysds));
|
key = createStringObject(sdskey,sdslen(sdskey));
|
||||||
val = createStringObject(valsds,sdslen(valsds));
|
val = createStringObject(sdsval,sdslen(sdsval));
|
||||||
} else if (o->type == OBJ_ZSET) {
|
} else if (o->type == OBJ_ZSET) {
|
||||||
sds keysds = dictGetKey(de);
|
sds sdskey = dictGetKey(de);
|
||||||
key = createStringObject(keysds,sdslen(keysds));
|
key = createStringObject(sdskey,sdslen(sdskey));
|
||||||
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
|
val = createStringObjectFromLongDouble(*(double*)dictGetVal(de),0);
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Type not handled in SCAN callback.");
|
serverPanic("Type not handled in SCAN callback.");
|
||||||
|
18
src/debug.c
18
src/debug.c
@ -222,20 +222,18 @@ void computeDatasetDigest(unsigned char *final) {
|
|||||||
serverPanic("Unknown sorted set encoding");
|
serverPanic("Unknown sorted set encoding");
|
||||||
}
|
}
|
||||||
} else if (o->type == OBJ_HASH) {
|
} else if (o->type == OBJ_HASH) {
|
||||||
hashTypeIterator *hi;
|
hashTypeIterator *hi = hashTypeInitIterator(o);
|
||||||
robj *obj;
|
|
||||||
|
|
||||||
hi = hashTypeInitIterator(o);
|
|
||||||
while (hashTypeNext(hi) != C_ERR) {
|
while (hashTypeNext(hi) != C_ERR) {
|
||||||
unsigned char eledigest[20];
|
unsigned char eledigest[20];
|
||||||
|
sds sdsele;
|
||||||
|
|
||||||
memset(eledigest,0,20);
|
memset(eledigest,0,20);
|
||||||
obj = hashTypeCurrentObject(hi,OBJ_HASH_KEY);
|
sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
|
||||||
mixObjectDigest(eledigest,obj);
|
mixDigest(eledigest,sdsele,sdslen(sdsele));
|
||||||
decrRefCount(obj);
|
sdsfree(sdsele);
|
||||||
obj = hashTypeCurrentObject(hi,OBJ_HASH_VALUE);
|
sdsele = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
|
||||||
mixObjectDigest(eledigest,obj);
|
mixDigest(eledigest,sdsele,sdslen(sdsele));
|
||||||
decrRefCount(obj);
|
sdsfree(sdsele);
|
||||||
xorDigest(digest,eledigest,20);
|
xorDigest(digest,eledigest,20);
|
||||||
}
|
}
|
||||||
hashTypeReleaseIterator(hi);
|
hashTypeReleaseIterator(hi);
|
||||||
|
@ -613,7 +613,7 @@ int strict_strtoll(char *str, long long *vp) {
|
|||||||
long long value;
|
long long value;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
value = strtoll(o->ptr, &eptr, 10);
|
value = strtoll(str, &eptr, 10);
|
||||||
if (isspace(str[0]) || eptr[0] != '\0' || errno == ERANGE) return C_ERR;
|
if (isspace(str[0]) || eptr[0] != '\0' || errno == ERANGE) return C_ERR;
|
||||||
if (vp) *vp = value;
|
if (vp) *vp = value;
|
||||||
return C_OK;
|
return C_OK;
|
||||||
|
@ -607,7 +607,7 @@ dictType hashDictType = {
|
|||||||
dictSdsHash, /* hash function */
|
dictSdsHash, /* hash function */
|
||||||
NULL, /* key dup */
|
NULL, /* key dup */
|
||||||
NULL, /* val dup */
|
NULL, /* val dup */
|
||||||
dictsdsKeyCompare, /* key compare */
|
dictSdsKeyCompare, /* key compare */
|
||||||
dictSdsDestructor, /* key destructor */
|
dictSdsDestructor, /* key destructor */
|
||||||
dictSdsDestructor /* val destructor */
|
dictSdsDestructor /* val destructor */
|
||||||
};
|
};
|
||||||
|
13
src/server.h
13
src/server.h
@ -1333,10 +1333,9 @@ void setTypeConvert(robj *subject, int enc);
|
|||||||
void hashTypeConvert(robj *o, int enc);
|
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);
|
||||||
robj *hashTypeGetObject(robj *o, robj *key);
|
int hashTypeExists(robj *o, sds key);
|
||||||
int hashTypeExists(robj *o, robj *key);
|
int hashTypeSet(robj *o, sds key, sds value);
|
||||||
int hashTypeSet(robj *o, robj *key, robj *value);
|
int hashTypeDelete(robj *o, sds key);
|
||||||
int hashTypeDelete(robj *o, robj *key);
|
|
||||||
unsigned long hashTypeLength(robj *o);
|
unsigned long hashTypeLength(robj *o);
|
||||||
hashTypeIterator *hashTypeInitIterator(robj *subject);
|
hashTypeIterator *hashTypeInitIterator(robj *subject);
|
||||||
void hashTypeReleaseIterator(hashTypeIterator *hi);
|
void hashTypeReleaseIterator(hashTypeIterator *hi);
|
||||||
@ -1345,9 +1344,11 @@ void hashTypeCurrentFromZiplist(hashTypeIterator *hi, int what,
|
|||||||
unsigned char **vstr,
|
unsigned char **vstr,
|
||||||
unsigned int *vlen,
|
unsigned int *vlen,
|
||||||
long long *vll);
|
long long *vll);
|
||||||
void hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what, robj **dst);
|
sds hashTypeCurrentFromHashTable(hashTypeIterator *hi, int what);
|
||||||
robj *hashTypeCurrentObject(hashTypeIterator *hi, int what);
|
void hashTypeCurrentObject(hashTypeIterator *hi, int what, unsigned char **vstr, unsigned int *vlen, long long *vll);
|
||||||
|
sds hashTypeCurrentObjectNewSds(hashTypeIterator *hi, int what);
|
||||||
robj *hashTypeLookupWriteOrCreate(client *c, robj *key);
|
robj *hashTypeLookupWriteOrCreate(client *c, robj *key);
|
||||||
|
robj *hashTypeGetValueObject(robj *o, sds field);
|
||||||
|
|
||||||
/* Pub / Sub */
|
/* Pub / Sub */
|
||||||
int pubsubUnsubscribeAllChannels(client *c, int notify);
|
int pubsubUnsubscribeAllChannels(client *c, int notify);
|
||||||
|
@ -112,9 +112,9 @@ robj *lookupKeyByPattern(redisDb *db, robj *pattern, robj *subst) {
|
|||||||
if (fieldobj) {
|
if (fieldobj) {
|
||||||
if (o->type != OBJ_HASH) goto noobj;
|
if (o->type != OBJ_HASH) goto noobj;
|
||||||
|
|
||||||
/* Retrieve value from hash by the field name. This operation
|
/* Retrieve value from hash by the field name. The returend object
|
||||||
* already increases the refcount of the returned object. */
|
* is a new object with refcount already incremented. */
|
||||||
o = hashTypeGetObject(o, fieldobj);
|
o = hashTypeGetValueObject(o, fieldobj->ptr);
|
||||||
} else {
|
} else {
|
||||||
if (o->type != OBJ_STRING) goto noobj;
|
if (o->type != OBJ_STRING) goto noobj;
|
||||||
|
|
||||||
|
73
src/t_hash.c
73
src/t_hash.c
@ -67,7 +67,7 @@ int hashTypeGetFromZiplist(robj *o, sds field,
|
|||||||
zl = o->ptr;
|
zl = o->ptr;
|
||||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
fptr = ziplistFind(fptr, field, sdslen(field), 1);
|
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
/* Grab pointer to the value (fptr points to the field) */
|
/* Grab pointer to the value (fptr points to the field) */
|
||||||
vptr = ziplistNext(zl, fptr);
|
vptr = ziplistNext(zl, fptr);
|
||||||
@ -106,15 +106,15 @@ sds hashTypeGetFromHashTable(robj *o, sds field) {
|
|||||||
* If *vll is populated *vstr is set to NULL, so the caller
|
* If *vll is populated *vstr is set to NULL, so the caller
|
||||||
* can always check the function return by checking the return value
|
* can always check the function return by checking the return value
|
||||||
* for C_OK and checking if vll (or vstr) is NULL. */
|
* for C_OK and checking if vll (or vstr) is NULL. */
|
||||||
int hashTypeGetObject(robj *o, sds field, unsigned char **vstr, unsigned int *vlen, long long *vll) {
|
int hashTypeGetValue(robj *o, sds field, unsigned char **vstr, unsigned int *vlen, long long *vll) {
|
||||||
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
if (o->encoding == OBJ_ENCODING_ZIPLIST) {
|
||||||
*vstr = NULL;
|
*vstr = NULL;
|
||||||
if (hashTypeGetFromZiplist(o, field, vstr, vlen, vll) == 0)
|
if (hashTypeGetFromZiplist(o, field, vstr, vlen, vll) == 0)
|
||||||
return C_OK;
|
return C_OK;
|
||||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||||
sds value;
|
sds value;
|
||||||
if (value = hashTypeGetFromHashTable(o, field) != NULL) {
|
if ((value = hashTypeGetFromHashTable(o, field)) != NULL) {
|
||||||
*vstr = value;
|
*vstr = (unsigned char*) value;
|
||||||
*vlen = sdslen(value);
|
*vlen = sdslen(value);
|
||||||
return C_OK;
|
return C_OK;
|
||||||
}
|
}
|
||||||
@ -124,6 +124,20 @@ int hashTypeGetObject(robj *o, sds field, unsigned char **vstr, unsigned int *vl
|
|||||||
return C_ERR;
|
return C_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Like hashTypeGetValue() but returns a Redis object, which is useful for
|
||||||
|
* interaction with the hash type outside t_hash.c.
|
||||||
|
* The function returns NULL if the field is not found in the hash. Otherwise
|
||||||
|
* a newly allocated string object with the value is returned. */
|
||||||
|
robj *hashTypeGetValueObject(robj *o, sds field) {
|
||||||
|
unsigned char *vstr;
|
||||||
|
unsigned int vlen;
|
||||||
|
long long vll;
|
||||||
|
|
||||||
|
if (hashTypeGetValue(o,field,&vstr,&vlen,&vll) == C_ERR) return NULL;
|
||||||
|
if (vstr) return createStringObject((char*)vstr,vlen);
|
||||||
|
else return createStringObjectFromLongLong(vll);
|
||||||
|
}
|
||||||
|
|
||||||
/* Higher level function using hashTypeGet*() to return the length of the
|
/* Higher level function using hashTypeGet*() to return the length of the
|
||||||
* object associated with the requested field, or 0 if the field does not
|
* object associated with the requested field, or 0 if the field does not
|
||||||
* exist. */
|
* exist. */
|
||||||
@ -157,8 +171,6 @@ int hashTypeExists(robj *o, sds field) {
|
|||||||
|
|
||||||
if (hashTypeGetFromZiplist(o, field, &vstr, &vlen, &vll) == 0) return 1;
|
if (hashTypeGetFromZiplist(o, field, &vstr, &vlen, &vll) == 0) return 1;
|
||||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||||
robj *aux;
|
|
||||||
|
|
||||||
if (hashTypeGetFromHashTable(o, field) != NULL) return 1;
|
if (hashTypeGetFromHashTable(o, field) != NULL) return 1;
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Unknown hash encoding");
|
serverPanic("Unknown hash encoding");
|
||||||
@ -178,7 +190,7 @@ int hashTypeSet(robj *o, sds field, sds value) {
|
|||||||
zl = o->ptr;
|
zl = o->ptr;
|
||||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
fptr = ziplistFind(fptr, field, sdslen(field), 1);
|
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
/* Grab pointer to the value (fptr points to the field) */
|
/* Grab pointer to the value (fptr points to the field) */
|
||||||
vptr = ziplistNext(zl, fptr);
|
vptr = ziplistNext(zl, fptr);
|
||||||
@ -189,14 +201,17 @@ int hashTypeSet(robj *o, sds field, sds value) {
|
|||||||
zl = ziplistDelete(zl, &vptr);
|
zl = ziplistDelete(zl, &vptr);
|
||||||
|
|
||||||
/* Insert new value */
|
/* Insert new value */
|
||||||
zl = ziplistInsert(zl, vptr, value->ptr, sdslen(value->ptr));
|
zl = ziplistInsert(zl, vptr, (unsigned char*)value,
|
||||||
|
sdslen(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!update) {
|
if (!update) {
|
||||||
/* Push new field/value pair onto the tail of the ziplist */
|
/* Push new field/value pair onto the tail of the ziplist */
|
||||||
zl = ziplistPush(zl, field, sdslen(field), ZIPLIST_TAIL);
|
zl = ziplistPush(zl, (unsigned char*)field, sdslen(field),
|
||||||
zl = ziplistPush(zl, value, sdslen(value), ZIPLIST_TAIL);
|
ZIPLIST_TAIL);
|
||||||
|
zl = ziplistPush(zl, (unsigned char*)value, sdslen(value),
|
||||||
|
ZIPLIST_TAIL);
|
||||||
}
|
}
|
||||||
o->ptr = zl;
|
o->ptr = zl;
|
||||||
|
|
||||||
@ -210,7 +225,7 @@ int hashTypeSet(robj *o, sds field, sds value) {
|
|||||||
dictGetVal(de) = sdsdup(value);
|
dictGetVal(de) = sdsdup(value);
|
||||||
update = 1;
|
update = 1;
|
||||||
} else {
|
} else {
|
||||||
dictAdd(o->ptr,sdsdup(key),sdsdup(value));
|
dictAdd(o->ptr,sdsdup(field),sdsdup(value));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Unknown hash encoding");
|
serverPanic("Unknown hash encoding");
|
||||||
@ -229,7 +244,7 @@ int hashTypeDelete(robj *o, sds field) {
|
|||||||
zl = o->ptr;
|
zl = o->ptr;
|
||||||
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
fptr = ziplistIndex(zl, ZIPLIST_HEAD);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
fptr = ziplistFind(fptr, field, sdslen(field), 1);
|
fptr = ziplistFind(fptr, (unsigned char*)field, sdslen(field), 1);
|
||||||
if (fptr != NULL) {
|
if (fptr != NULL) {
|
||||||
zl = ziplistDelete(zl,&fptr);
|
zl = ziplistDelete(zl,&fptr);
|
||||||
zl = ziplistDelete(zl,&fptr);
|
zl = ziplistDelete(zl,&fptr);
|
||||||
@ -237,9 +252,6 @@ int hashTypeDelete(robj *o, sds field) {
|
|||||||
deleted = 1;
|
deleted = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
decrRefCount(field);
|
|
||||||
|
|
||||||
} else if (o->encoding == OBJ_ENCODING_HT) {
|
} else if (o->encoding == OBJ_ENCODING_HT) {
|
||||||
if (dictDelete((dict*)o->ptr, field) == C_OK) {
|
if (dictDelete((dict*)o->ptr, field) == C_OK) {
|
||||||
deleted = 1;
|
deleted = 1;
|
||||||
@ -376,7 +388,7 @@ void hashTypeCurrentObject(hashTypeIterator *hi, int what, unsigned char **vstr,
|
|||||||
hashTypeCurrentFromZiplist(hi, what, vstr, vlen, vll);
|
hashTypeCurrentFromZiplist(hi, what, vstr, vlen, vll);
|
||||||
} else if (hi->encoding == OBJ_ENCODING_HT) {
|
} else if (hi->encoding == OBJ_ENCODING_HT) {
|
||||||
sds ele = hashTypeCurrentFromHashTable(hi, what);
|
sds ele = hashTypeCurrentFromHashTable(hi, what);
|
||||||
*vstr = ele;
|
*vstr = (unsigned char*) ele;
|
||||||
*vlen = sdslen(ele);
|
*vlen = sdslen(ele);
|
||||||
} else {
|
} else {
|
||||||
serverPanic("Unknown hash encoding");
|
serverPanic("Unknown hash encoding");
|
||||||
@ -424,14 +436,11 @@ void hashTypeConvertZiplist(robj *o, int enc) {
|
|||||||
dict = dictCreate(&hashDictType, NULL);
|
dict = dictCreate(&hashDictType, NULL);
|
||||||
|
|
||||||
while (hashTypeNext(hi) != C_ERR) {
|
while (hashTypeNext(hi) != C_ERR) {
|
||||||
unsigned char *vstr;
|
|
||||||
unsigned int vlen;
|
|
||||||
long long vll;
|
|
||||||
sds key, value;
|
sds key, value;
|
||||||
|
|
||||||
key = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
|
key = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
|
||||||
value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
|
value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
|
||||||
ret = dictAdd(dict, field, value);
|
ret = dictAdd(dict, key, value);
|
||||||
if (ret != DICT_OK) {
|
if (ret != DICT_OK) {
|
||||||
serverLogHexDump(LL_WARNING,"ziplist with dup elements dump",
|
serverLogHexDump(LL_WARNING,"ziplist with dup elements dump",
|
||||||
o->ptr,ziplistBlobLen(o->ptr));
|
o->ptr,ziplistBlobLen(o->ptr));
|
||||||
@ -515,17 +524,17 @@ void hincrbyCommand(client *c) {
|
|||||||
robj *o;
|
robj *o;
|
||||||
sds new;
|
sds new;
|
||||||
unsigned char *vstr;
|
unsigned char *vstr;
|
||||||
unsigned int *lven;
|
unsigned int vlen;
|
||||||
|
|
||||||
if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
||||||
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||||
if (hashTypeGetObject(o,c->argv[2],&vstr,&vlen,&value) == C_OK) {
|
if (hashTypeGetValue(o,c->argv[2]->ptr,&vstr,&vlen,&value) == C_OK) {
|
||||||
if (vstr) {
|
if (vstr) {
|
||||||
if (string2ll(vstr,vlen,&value) == 0) {
|
if (string2ll((char*)vstr,vlen,&value) == 0) {
|
||||||
addReplyError(c,"hash value is not an integer");
|
addReplyError(c,"hash value is not an integer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} /* Else hashTypeGetObject() already stored it into &value */
|
} /* Else hashTypeGetValue() already stored it into &value */
|
||||||
} else {
|
} else {
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
@ -551,13 +560,13 @@ void hincrbyfloatCommand(client *c) {
|
|||||||
robj *o;
|
robj *o;
|
||||||
sds new;
|
sds new;
|
||||||
unsigned char *vstr;
|
unsigned char *vstr;
|
||||||
unsigned int *lven;
|
unsigned int vlen;
|
||||||
|
|
||||||
if (getLongDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
if (getDoubleFromObjectOrReply(c,c->argv[3],&incr,NULL) != C_OK) return;
|
||||||
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
|
||||||
if (hashTypeGetObject(o,c->argv[2],vstr,vlen,&ll) == C_OK) {
|
if (hashTypeGetValue(o,c->argv[2]->ptr,&vstr,&vlen,&ll) == C_OK) {
|
||||||
if (vstr) {
|
if (vstr) {
|
||||||
if (string2d(vstr,vlen,&value) == 0) {
|
if (string2d((char*)vstr,vlen,&value) == 0) {
|
||||||
addReplyError(c,"hash value is not an integer");
|
addReplyError(c,"hash value is not an integer");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -571,9 +580,9 @@ void hincrbyfloatCommand(client *c) {
|
|||||||
value += incr;
|
value += incr;
|
||||||
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int len = ld2string(buf,sizeof(buf),value,humanfriendly);
|
int len = ld2string(buf,sizeof(buf),value,1);
|
||||||
new = sdsnewlen(buf,len);
|
new = sdsnewlen(buf,len);
|
||||||
hashTypeSet(o,c->argv[2],new);
|
hashTypeSet(o,c->argv[2]->ptr,new);
|
||||||
addReplyBulkSds(c,new);
|
addReplyBulkSds(c,new);
|
||||||
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);
|
||||||
@ -587,12 +596,10 @@ void hincrbyfloatCommand(client *c) {
|
|||||||
newobj = createRawStringObject(buf,len);
|
newobj = createRawStringObject(buf,len);
|
||||||
rewriteClientCommandArgument(c,0,aux);
|
rewriteClientCommandArgument(c,0,aux);
|
||||||
decrRefCount(aux);
|
decrRefCount(aux);
|
||||||
rewriteClientCommandArgument(c,3,new);
|
rewriteClientCommandArgument(c,3,newobj);
|
||||||
decrRefCount(newobj);
|
decrRefCount(newobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX From here. */
|
|
||||||
|
|
||||||
static void addHashFieldToReply(client *c, robj *o, sds field) {
|
static void addHashFieldToReply(client *c, robj *o, sds field) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
12
src/util.c
12
src/util.c
@ -427,12 +427,17 @@ int string2l(const char *s, size_t slen, long *lval) {
|
|||||||
* a double: no spaces or other characters before or after the string
|
* a double: no spaces or other characters before or after the string
|
||||||
* representing the number are accepted. */
|
* representing the number are accepted. */
|
||||||
int string2d(const char *s, size_t slen, double *dp) {
|
int string2d(const char *s, size_t slen, double *dp) {
|
||||||
|
char buf[256];
|
||||||
double value;
|
double value;
|
||||||
|
char *eptr;
|
||||||
|
|
||||||
|
if (slen >= sizeof(buf)) return 0;
|
||||||
|
memcpy(buf,s,slen);
|
||||||
|
buf[slen] = '\0';
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
value = strtod(o->ptr, &eptr);
|
value = strtod(buf, &eptr);
|
||||||
if (isspace(((char*)o->ptr)[0]) ||
|
if (isspace(buf[0]) || eptr[0] != '\0' ||
|
||||||
eptr[0] != '\0' ||
|
|
||||||
(errno == ERANGE &&
|
(errno == ERANGE &&
|
||||||
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
|
(value == HUGE_VAL || value == -HUGE_VAL || value == 0)) ||
|
||||||
errno == EINVAL ||
|
errno == EINVAL ||
|
||||||
@ -493,7 +498,6 @@ int d2string(char *buf, size_t len, double value) {
|
|||||||
* The function returns the length of the string or zero if there was not
|
* The function returns the length of the string or zero if there was not
|
||||||
* enough buffer room to store it. */
|
* enough buffer room to store it. */
|
||||||
int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
|
int ld2string(char *buf, size_t len, long double value, int humanfriendly) {
|
||||||
char buf[256];
|
|
||||||
size_t l;
|
size_t l;
|
||||||
|
|
||||||
if (isinf(value)) {
|
if (isinf(value)) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user