"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/t_hash.c" between
redis-6.2-rc3.tar.gz and redis-6.2.0.tar.gz

About: redis is an advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.

t_hash.c  (redis-6.2-rc3):t_hash.c  (redis-6.2.0)
skipping to change at line 218 skipping to change at line 218
zl = o->ptr; zl = o->ptr;
fptr = ziplistIndex(zl, ZIPLIST_HEAD); fptr = ziplistIndex(zl, ZIPLIST_HEAD);
if (fptr != NULL) { if (fptr != NULL) {
fptr = ziplistFind(zl, fptr, (unsigned char*)field, sdslen(field), 1 ); fptr = ziplistFind(zl, 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);
serverAssert(vptr != NULL); serverAssert(vptr != NULL);
update = 1; update = 1;
/* Delete value */ /* Replace value */
zl = ziplistDelete(zl, &vptr); zl = ziplistReplace(zl, vptr, (unsigned char*)value,
/* Insert new value */
zl = ziplistInsert(zl, vptr, (unsigned char*)value,
sdslen(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, (unsigned char*)field, sdslen(field), zl = ziplistPush(zl, (unsigned char*)field, sdslen(field),
ZIPLIST_TAIL); ZIPLIST_TAIL);
zl = ziplistPush(zl, (unsigned char*)value, sdslen(value), zl = ziplistPush(zl, (unsigned char*)value, sdslen(value),
ZIPLIST_TAIL); ZIPLIST_TAIL);
skipping to change at line 761 skipping to change at line 758
new = sdsnewlen(buf,len); new = sdsnewlen(buf,len);
hashTypeSet(o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE); hashTypeSet(o,c->argv[2]->ptr,new,HASH_SET_TAKE_VALUE);
addReplyBulkCBuffer(c,buf,len); addReplyBulkCBuffer(c,buf,len);
signalModifiedKey(c,c->db,c->argv[1]); signalModifiedKey(c,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++;
/* Always replicate HINCRBYFLOAT as an HSET command with the final value /* Always replicate HINCRBYFLOAT as an HSET command with the final value
* in order to make sure that differences in float precision or formatting * in order to make sure that differences in float precision or formatting
* will not create differences in replicas or after an AOF restart. */ * will not create differences in replicas or after an AOF restart. */
robj *aux, *newobj; robj *newobj;
aux = createStringObject("HSET",4);
newobj = createRawStringObject(buf,len); newobj = createRawStringObject(buf,len);
rewriteClientCommandArgument(c,0,aux); rewriteClientCommandArgument(c,0,shared.hset);
decrRefCount(aux);
rewriteClientCommandArgument(c,3,newobj); rewriteClientCommandArgument(c,3,newobj);
decrRefCount(newobj); decrRefCount(newobj);
} }
static void addHashFieldToReply(client *c, robj *o, sds field) { static void addHashFieldToReply(client *c, robj *o, sds field) {
int ret; int ret;
if (o == NULL) { if (o == NULL) {
addReplyNull(c); addReplyNull(c);
return; return;
skipping to change at line 961 skipping to change at line 956
void hscanCommand(client *c) { void hscanCommand(client *c) {
robj *o; robj *o;
unsigned long cursor; unsigned long cursor;
if (parseScanCursorOrReply(c,c->argv[2],&cursor) == C_ERR) return; if (parseScanCursorOrReply(c,c->argv[2],&cursor) == C_ERR) return;
if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptyscan)) == NULL || if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptyscan)) == NULL ||
checkType(c,o,OBJ_HASH)) return; checkType(c,o,OBJ_HASH)) return;
scanGenericCommand(c,o,cursor); scanGenericCommand(c,o,cursor);
} }
static void harndfieldReplyWithZiplist(client *c, unsigned int count, ziplistEnt
ry *keys, ziplistEntry *vals) {
for (unsigned long i = 0; i < count; i++) {
if (vals && c->resp > 2)
addReplyArrayLen(c,2);
if (keys[i].sval)
addReplyBulkCBuffer(c, keys[i].sval, keys[i].slen);
else
addReplyBulkLongLong(c, keys[i].lval);
if (vals) {
if (vals[i].sval)
addReplyBulkCBuffer(c, vals[i].sval, vals[i].slen);
else
addReplyBulkLongLong(c, vals[i].lval);
}
}
}
/* How many times bigger should be the hash compared to the requested size /* How many times bigger should be the hash compared to the requested size
* for us to not use the "remove elements" strategy? Read later in the * for us to not use the "remove elements" strategy? Read later in the
* implementation for more info. */ * implementation for more info. */
#define HRANDFIELD_SUB_STRATEGY_MUL 3 #define HRANDFIELD_SUB_STRATEGY_MUL 3
/* If client is trying to ask for a very large number of random elements,
* queuing may consume an unlimited amount of memory, so we want to limit
* the number of randoms per time. */
#define HRANDFIELD_RANDOM_SAMPLE_LIMIT 1000
void hrandfieldWithCountCommand(client *c, long l, int withvalues) { void hrandfieldWithCountCommand(client *c, long l, int withvalues) {
unsigned long count, size; unsigned long count, size;
int uniq = 1; int uniq = 1;
robj *hash; robj *hash;
if ((hash = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp])) if ((hash = lookupKeyReadOrReply(c,c->argv[1],shared.null[c->resp]))
== NULL || checkType(c,hash,OBJ_HASH)) return; == NULL || checkType(c,hash,OBJ_HASH)) return;
size = hashTypeLength(hash); size = hashTypeLength(hash);
if(l >= 0) { if(l >= 0) {
skipping to change at line 1001 skipping to change at line 1018
* structures. This case is the only one that also needs to return the * structures. This case is the only one that also needs to return the
* elements in random order. */ * elements in random order. */
if (!uniq || count == 1) { if (!uniq || count == 1) {
if (withvalues && c->resp == 2) if (withvalues && c->resp == 2)
addReplyArrayLen(c, count*2); addReplyArrayLen(c, count*2);
else else
addReplyArrayLen(c, count); addReplyArrayLen(c, count);
if (hash->encoding == OBJ_ENCODING_HT) { if (hash->encoding == OBJ_ENCODING_HT) {
sds key, value; sds key, value;
while (count--) { while (count--) {
dictEntry *de = dictGetRandomKey(hash->ptr); dictEntry *de = dictGetFairRandomKey(hash->ptr);
key = dictGetKey(de); key = dictGetKey(de);
value = dictGetVal(de); value = dictGetVal(de);
if (withvalues && c->resp > 2) if (withvalues && c->resp > 2)
addReplyArrayLen(c,2); addReplyArrayLen(c,2);
addReplyBulkCBuffer(c, key, sdslen(key)); addReplyBulkCBuffer(c, key, sdslen(key));
if (withvalues) if (withvalues)
addReplyBulkCBuffer(c, value, sdslen(value)); addReplyBulkCBuffer(c, value, sdslen(value));
} }
} else if (hash->encoding == OBJ_ENCODING_ZIPLIST) { } else if (hash->encoding == OBJ_ENCODING_ZIPLIST) {
ziplistEntry *keys, *vals = NULL; ziplistEntry *keys, *vals = NULL;
keys = zmalloc(sizeof(ziplistEntry)*count); unsigned long limit, sample_count;
limit = count > HRANDFIELD_RANDOM_SAMPLE_LIMIT ? HRANDFIELD_RANDOM_S
AMPLE_LIMIT : count;
keys = zmalloc(sizeof(ziplistEntry)*limit);
if (withvalues) if (withvalues)
vals = zmalloc(sizeof(ziplistEntry)*count); vals = zmalloc(sizeof(ziplistEntry)*limit);
ziplistRandomPairs(hash->ptr, count, keys, vals); while (count) {
for (unsigned long i = 0; i < count; i++) { sample_count = count > limit ? limit : count;
if (withvalues && c->resp > 2) count -= sample_count;
addReplyArrayLen(c,2); ziplistRandomPairs(hash->ptr, sample_count, keys, vals);
if (keys[i].sval) harndfieldReplyWithZiplist(c, sample_count, keys, vals);
addReplyBulkCBuffer(c, keys[i].sval, keys[i].slen);
else
addReplyBulkLongLong(c, keys[i].lval);
if (withvalues) {
if (vals[i].sval)
addReplyBulkCBuffer(c, vals[i].sval, vals[i].slen);
else
addReplyBulkLongLong(c, vals[i].lval);
}
} }
zfree(keys); zfree(keys);
zfree(vals); zfree(vals);
} }
return; return;
} }
/* Initiate reply count, RESP3 responds with nested array, RESP2 with flat o ne. */ /* Initiate reply count, RESP3 responds with nested array, RESP2 with flat o ne. */
long reply_size = count < size ? count : size; long reply_size = count < size ? count : size;
if (withvalues && c->resp == 2) if (withvalues && c->resp == 2)
skipping to change at line 1070 skipping to change at line 1080
* The number of elements inside the hash is not greater than * The number of elements inside the hash is not greater than
* HRANDFIELD_SUB_STRATEGY_MUL times the number of requested elements. * HRANDFIELD_SUB_STRATEGY_MUL times the number of requested elements.
* In this case we create a hash from scratch with all the elements, and * In this case we create a hash from scratch with all the elements, and
* subtract random elements to reach the requested number of elements. * subtract random elements to reach the requested number of elements.
* *
* This is done because if the number of requested elements is just * This is done because if the number of requested elements is just
* a bit less than the number of elements in the hash, the natural approach * a bit less than the number of elements in the hash, the natural approach
* used into CASE 4 is highly inefficient. */ * used into CASE 4 is highly inefficient. */
if (count*HRANDFIELD_SUB_STRATEGY_MUL > size) { if (count*HRANDFIELD_SUB_STRATEGY_MUL > size) {
dict *d = dictCreate(&sdsReplyDictType, NULL); dict *d = dictCreate(&sdsReplyDictType, NULL);
dictExpand(d, size);
hashTypeIterator *hi = hashTypeInitIterator(hash); hashTypeIterator *hi = hashTypeInitIterator(hash);
/* Add all the elements into the temporary dictionary. */ /* Add all the elements into the temporary dictionary. */
while ((hashTypeNext(hi)) != C_ERR) { while ((hashTypeNext(hi)) != C_ERR) {
int ret = DICT_ERR; int ret = DICT_ERR;
sds key, value = NULL; sds key, value = NULL;
key = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY); key = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_KEY);
if (withvalues) if (withvalues)
value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE); value = hashTypeCurrentObjectNewSds(hi,OBJ_HASH_VALUE);
skipping to change at line 1121 skipping to change at line 1132
dictReleaseIterator(di); dictReleaseIterator(di);
dictRelease(d); dictRelease(d);
} }
/* CASE 4: We have a big hash compared to the requested number of elements. /* CASE 4: We have a big hash compared to the requested number of elements.
* In this case we can simply get random elements from the hash and add * In this case we can simply get random elements from the hash and add
* to the temporary hash, trying to eventually get enough unique elements * to the temporary hash, trying to eventually get enough unique elements
* to reach the specified count. */ * to reach the specified count. */
else { else {
if (hash->encoding == OBJ_ENCODING_ZIPLIST) {
/* it is inefficient to repeatedly pick one random element from a
* ziplist. so we use this instead: */
ziplistEntry *keys, *vals = NULL;
keys = zmalloc(sizeof(ziplistEntry)*count);
if (withvalues)
vals = zmalloc(sizeof(ziplistEntry)*count);
serverAssert(ziplistRandomPairsUnique(hash->ptr, count, keys, vals)
== count);
harndfieldReplyWithZiplist(c, count, keys, vals);
zfree(keys);
zfree(vals);
return;
}
/* Hashtable encoding (generic implementation) */
unsigned long added = 0; unsigned long added = 0;
ziplistEntry key, value; ziplistEntry key, value;
dict *d = dictCreate(&hashDictType, NULL); dict *d = dictCreate(&hashDictType, NULL);
dictExpand(d, count);
while(added < count) { while(added < count) {
hashTypeRandomElement(hash, size, &key, withvalues? &value : NULL); hashTypeRandomElement(hash, size, &key, withvalues? &value : NULL);
/* Try to add the object to the dictionary. If it already exists /* Try to add the object to the dictionary. If it already exists
* free it, otherwise increment the number of objects we have * free it, otherwise increment the number of objects we have
* in the result dictionary. */ * in the result dictionary. */
sds skey = hashSdsFromZiplistEntry(&key); sds skey = hashSdsFromZiplistEntry(&key);
if (dictAdd(d,skey,NULL) != DICT_OK) { if (dictAdd(d,skey,NULL) != DICT_OK) {
sdsfree(skey); sdsfree(skey);
continue; continue;
 End of changes. 11 change blocks. 
26 lines changed or deleted 56 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)