Make dictEntry opaque
Use functions for all accesses to dictEntry (except in dict.c). Dict abuses e.g. in defrag.c have been replaced by support functions provided by dict.
This commit is contained in:
parent
25dc3b0757
commit
c84248b5d2
@ -7288,7 +7288,7 @@ int clusterRedirectBlockedClientIfNeeded(client *c) {
|
|||||||
* understand if we have keys for a given hash slot. */
|
* understand if we have keys for a given hash slot. */
|
||||||
|
|
||||||
void slotToKeyAddEntry(dictEntry *entry, redisDb *db) {
|
void slotToKeyAddEntry(dictEntry *entry, redisDb *db) {
|
||||||
sds key = entry->key;
|
sds key = dictGetKey(entry);
|
||||||
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
||||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||||
slot_to_keys->count++;
|
slot_to_keys->count++;
|
||||||
@ -7305,7 +7305,7 @@ void slotToKeyAddEntry(dictEntry *entry, redisDb *db) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void slotToKeyDelEntry(dictEntry *entry, redisDb *db) {
|
void slotToKeyDelEntry(dictEntry *entry, redisDb *db) {
|
||||||
sds key = entry->key;
|
sds key = dictGetKey(entry);
|
||||||
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
||||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||||
slot_to_keys->count--;
|
slot_to_keys->count--;
|
||||||
@ -7337,7 +7337,7 @@ void slotToKeyReplaceEntry(dictEntry *entry, redisDb *db) {
|
|||||||
dictEntryNextInSlot(prev) = entry;
|
dictEntryNextInSlot(prev) = entry;
|
||||||
} else {
|
} else {
|
||||||
/* The replaced entry was the first in the list. */
|
/* The replaced entry was the first in the list. */
|
||||||
sds key = entry->key;
|
sds key = dictGetKey(entry);
|
||||||
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
||||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||||
slot_to_keys->head = entry;
|
slot_to_keys->head = entry;
|
||||||
|
@ -989,8 +989,8 @@ void configGetCommand(client *c) {
|
|||||||
/* Note that hidden configs require an exact match (not a pattern) */
|
/* Note that hidden configs require an exact match (not a pattern) */
|
||||||
if (config->flags & HIDDEN_CONFIG) continue;
|
if (config->flags & HIDDEN_CONFIG) continue;
|
||||||
if (dictFind(matches, config->name)) continue;
|
if (dictFind(matches, config->name)) continue;
|
||||||
if (stringmatch(name, de->key, 1)) {
|
if (stringmatch(name, dictGetKey(de), 1)) {
|
||||||
dictAdd(matches, de->key, config);
|
dictAdd(matches, dictGetKey(de), config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dictReleaseIterator(di);
|
dictReleaseIterator(di);
|
||||||
@ -1000,7 +1000,7 @@ void configGetCommand(client *c) {
|
|||||||
addReplyMapLen(c, dictSize(matches));
|
addReplyMapLen(c, dictSize(matches));
|
||||||
while ((de = dictNext(di)) != NULL) {
|
while ((de = dictNext(di)) != NULL) {
|
||||||
standardConfig *config = (standardConfig *) dictGetVal(de);
|
standardConfig *config = (standardConfig *) dictGetVal(de);
|
||||||
addReplyBulkCString(c, de->key);
|
addReplyBulkCString(c, dictGetKey(de));
|
||||||
addReplyBulkSds(c, config->interface.get(config));
|
addReplyBulkSds(c, config->interface.get(config));
|
||||||
}
|
}
|
||||||
dictReleaseIterator(di);
|
dictReleaseIterator(di);
|
||||||
@ -1754,7 +1754,7 @@ int rewriteConfig(char *path, int force_write) {
|
|||||||
standardConfig *config = dictGetVal(de);
|
standardConfig *config = dictGetVal(de);
|
||||||
/* Only rewrite the primary names */
|
/* Only rewrite the primary names */
|
||||||
if (config->flags & ALIAS_CONFIG) continue;
|
if (config->flags & ALIAS_CONFIG) continue;
|
||||||
if (config->interface.rewrite) config->interface.rewrite(config, de->key, state);
|
if (config->interface.rewrite) config->interface.rewrite(config, dictGetKey(de), state);
|
||||||
}
|
}
|
||||||
dictReleaseIterator(di);
|
dictReleaseIterator(di);
|
||||||
|
|
||||||
|
9
src/db.c
9
src/db.c
@ -228,7 +228,6 @@ static void dbSetValue(redisDb *db, robj *key, robj *val, int overwrite) {
|
|||||||
dictEntry *de = dictFind(db->dict,key->ptr);
|
dictEntry *de = dictFind(db->dict,key->ptr);
|
||||||
|
|
||||||
serverAssertWithInfo(NULL,key,de != NULL);
|
serverAssertWithInfo(NULL,key,de != NULL);
|
||||||
dictEntry auxentry = *de;
|
|
||||||
robj *old = dictGetVal(de);
|
robj *old = dictGetVal(de);
|
||||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||||
val->lru = old->lru;
|
val->lru = old->lru;
|
||||||
@ -246,17 +245,15 @@ static void dbSetValue(redisDb *db, robj *key, robj *val, int overwrite) {
|
|||||||
decrRefCount(old);
|
decrRefCount(old);
|
||||||
/* Because of RM_StringDMA, old may be changed, so we need get old again */
|
/* Because of RM_StringDMA, old may be changed, so we need get old again */
|
||||||
old = dictGetVal(de);
|
old = dictGetVal(de);
|
||||||
/* Entry in auxentry may be changed, so we need update auxentry */
|
|
||||||
auxentry = *de;
|
|
||||||
}
|
}
|
||||||
dictSetVal(db->dict, de, val);
|
dictSetVal(db->dict, de, val);
|
||||||
|
|
||||||
if (server.lazyfree_lazy_server_del) {
|
if (server.lazyfree_lazy_server_del) {
|
||||||
freeObjAsync(key,old,db->id);
|
freeObjAsync(key,old,db->id);
|
||||||
dictSetVal(db->dict, &auxentry, NULL);
|
} else {
|
||||||
|
/* This is just decrRefCount(old); */
|
||||||
|
db->dict->type->valDestructor(db->dict, old);
|
||||||
}
|
}
|
||||||
|
|
||||||
dictFreeVal(db->dict, &auxentry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Replace an existing key with a new value, we just replace value and don't
|
/* Replace an existing key with a new value, we just replace value and don't
|
||||||
|
@ -868,7 +868,7 @@ NULL
|
|||||||
sds sizes = sdsempty();
|
sds sizes = sdsempty();
|
||||||
sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
|
sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
|
||||||
sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
|
sizes = sdscatprintf(sizes,"robj:%d ",(int)sizeof(robj));
|
||||||
sizes = sdscatprintf(sizes,"dictentry:%d ",(int)sizeof(dictEntry));
|
sizes = sdscatprintf(sizes,"dictentry:%d ",(int)dictEntryMemUsage());
|
||||||
sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
|
sizes = sdscatprintf(sizes,"sdshdr5:%d ",(int)sizeof(struct sdshdr5));
|
||||||
sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
|
sizes = sdscatprintf(sizes,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
|
||||||
sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
|
sizes = sdscatprintf(sizes,"sdshdr16:%d ",(int)sizeof(struct sdshdr16));
|
||||||
|
61
src/defrag.c
61
src/defrag.c
@ -163,7 +163,7 @@ long dictIterDefragEntry(dictIterator *iter) {
|
|||||||
if (newde) {
|
if (newde) {
|
||||||
defragged++;
|
defragged++;
|
||||||
iter->nextEntry = newde;
|
iter->nextEntry = newde;
|
||||||
iter->entry->next = newde;
|
dictSetNext(iter->entry, newde);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* handle the case of the first entry in the hash bucket. */
|
/* handle the case of the first entry in the hash bucket. */
|
||||||
@ -264,7 +264,7 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
|
|||||||
long defragged = 0;
|
long defragged = 0;
|
||||||
sds sdsele = dictGetKey(de);
|
sds sdsele = dictGetKey(de);
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
defragged++, de->key = newsds;
|
defragged++, dictSetKey(zs->dict, de, newsds);
|
||||||
newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
|
newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
|
||||||
if (newscore) {
|
if (newscore) {
|
||||||
dictSetVal(zs->dict, de, newscore);
|
dictSetVal(zs->dict, de, newscore);
|
||||||
@ -288,24 +288,24 @@ long activeDefragSdsDict(dict* d, int val_type) {
|
|||||||
while((de = dictNext(di)) != NULL) {
|
while((de = dictNext(di)) != NULL) {
|
||||||
sds sdsele = dictGetKey(de), newsds;
|
sds sdsele = dictGetKey(de), newsds;
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
de->key = newsds, defragged++;
|
dictSetKey(d, de, newsds), defragged++;
|
||||||
/* defrag the value */
|
/* defrag the value */
|
||||||
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||||
sdsele = dictGetVal(de);
|
sdsele = dictGetVal(de);
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
de->v.val = newsds, defragged++;
|
dictSetVal(d, de, newsds), defragged++;
|
||||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||||
robj *newele, *ele = dictGetVal(de);
|
robj *newele, *ele = dictGetVal(de);
|
||||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||||
de->v.val = newele;
|
dictSetVal(d, de, newele);
|
||||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||||
void *newptr, *ptr = dictGetVal(de);
|
void *newptr, *ptr = dictGetVal(de);
|
||||||
if ((newptr = activeDefragAlloc(ptr)))
|
if ((newptr = activeDefragAlloc(ptr)))
|
||||||
de->v.val = newptr, defragged++;
|
dictSetVal(d, de, newptr), defragged++;
|
||||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT) {
|
} else if (val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT) {
|
||||||
void *newptr, *ptr = dictGetVal(de);
|
void *newptr, *ptr = dictGetVal(de);
|
||||||
if ((newptr = activeDefragLuaScript(ptr, &defragged)))
|
if ((newptr = activeDefragLuaScript(ptr, &defragged)))
|
||||||
de->v.val = newptr;
|
dictSetVal(d, de, newptr);
|
||||||
}
|
}
|
||||||
defragged += dictIterDefragEntry(di);
|
defragged += dictIterDefragEntry(di);
|
||||||
}
|
}
|
||||||
@ -374,7 +374,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
|||||||
uint64_t hash = dictGetHash(d, newsds);
|
uint64_t hash = dictGetHash(d, newsds);
|
||||||
dictEntry **deref = dictFindEntryRefByPtrAndHash(d, sdsele, hash);
|
dictEntry **deref = dictFindEntryRefByPtrAndHash(d, sdsele, hash);
|
||||||
if (deref)
|
if (deref)
|
||||||
(*deref)->key = newsds;
|
dictSetKey(d, *deref, newsds);
|
||||||
ln->value = newsds;
|
ln->value = newsds;
|
||||||
defragged++;
|
defragged++;
|
||||||
}
|
}
|
||||||
@ -386,15 +386,15 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
|||||||
if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||||
sds newsds, sdsele = dictGetVal(de);
|
sds newsds, sdsele = dictGetVal(de);
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
de->v.val = newsds, defragged++;
|
dictSetVal(d, de, newsds), defragged++;
|
||||||
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||||
robj *newele, *ele = dictGetVal(de);
|
robj *newele, *ele = dictGetVal(de);
|
||||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||||
de->v.val = newele;
|
dictSetVal(d, de, newele);
|
||||||
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||||
void *newptr, *ptr = dictGetVal(de);
|
void *newptr, *ptr = dictGetVal(de);
|
||||||
if ((newptr = activeDefragAlloc(ptr)))
|
if ((newptr = activeDefragAlloc(ptr)))
|
||||||
de->v.val = newptr, defragged++;
|
dictSetVal(d, de, newptr), defragged++;
|
||||||
}
|
}
|
||||||
defragged += dictIterDefragEntry(di);
|
defragged += dictIterDefragEntry(di);
|
||||||
}
|
}
|
||||||
@ -420,7 +420,7 @@ dictEntry* replaceSatelliteDictKeyPtrAndOrDefragDictEntry(dict *d, sds oldkey, s
|
|||||||
(*defragged)++;
|
(*defragged)++;
|
||||||
}
|
}
|
||||||
if (newkey)
|
if (newkey)
|
||||||
de->key = newkey;
|
dictSetKey(d, de, newkey);
|
||||||
return de;
|
return de;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -531,43 +531,48 @@ long scanLaterZset(robj *ob, unsigned long *cursor) {
|
|||||||
return data.defragged;
|
return data.defragged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
dict *dict;
|
||||||
|
long defragged;
|
||||||
|
} scanLaterDictData;
|
||||||
|
|
||||||
void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
|
void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
|
||||||
dictEntry *de = (dictEntry*)_de;
|
dictEntry *de = (dictEntry*)_de;
|
||||||
long *defragged = privdata;
|
scanLaterDictData *data = privdata;
|
||||||
sds sdsele = dictGetKey(de), newsds;
|
sds sdsele = dictGetKey(de), newsds;
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
(*defragged)++, de->key = newsds;
|
data->defragged++, dictSetKey(data->dict, de, newsds);
|
||||||
server.stat_active_defrag_scanned++;
|
server.stat_active_defrag_scanned++;
|
||||||
}
|
}
|
||||||
|
|
||||||
long scanLaterSet(robj *ob, unsigned long *cursor) {
|
long scanLaterSet(robj *ob, unsigned long *cursor) {
|
||||||
long defragged = 0;
|
|
||||||
if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT)
|
if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT)
|
||||||
return 0;
|
return 0;
|
||||||
dict *d = ob->ptr;
|
dict *d = ob->ptr;
|
||||||
*cursor = dictScan(d, *cursor, scanLaterSetCallback, defragDictBucketCallback, &defragged);
|
scanLaterDictData data = {d, 0};
|
||||||
return defragged;
|
*cursor = dictScan(d, *cursor, scanLaterSetCallback, defragDictBucketCallback, &data);
|
||||||
|
return data.defragged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
|
void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
|
||||||
dictEntry *de = (dictEntry*)_de;
|
dictEntry *de = (dictEntry*)_de;
|
||||||
long *defragged = privdata;
|
scanLaterDictData *data = privdata;
|
||||||
sds sdsele = dictGetKey(de), newsds;
|
sds sdsele = dictGetKey(de), newsds;
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
(*defragged)++, de->key = newsds;
|
data->defragged++, dictSetKey(data->dict, de, newsds);
|
||||||
sdsele = dictGetVal(de);
|
sdsele = dictGetVal(de);
|
||||||
if ((newsds = activeDefragSds(sdsele)))
|
if ((newsds = activeDefragSds(sdsele)))
|
||||||
(*defragged)++, de->v.val = newsds;
|
data->defragged++, dictSetVal(data->dict, de, newsds);
|
||||||
server.stat_active_defrag_scanned++;
|
server.stat_active_defrag_scanned++;
|
||||||
}
|
}
|
||||||
|
|
||||||
long scanLaterHash(robj *ob, unsigned long *cursor) {
|
long scanLaterHash(robj *ob, unsigned long *cursor) {
|
||||||
long defragged = 0;
|
|
||||||
if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT)
|
if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT)
|
||||||
return 0;
|
return 0;
|
||||||
dict *d = ob->ptr;
|
dict *d = ob->ptr;
|
||||||
*cursor = dictScan(d, *cursor, scanLaterHashCallback, defragDictBucketCallback, &defragged);
|
scanLaterDictData data = {d, 0};
|
||||||
return defragged;
|
*cursor = dictScan(d, *cursor, scanLaterHashCallback, defragDictBucketCallback, &data);
|
||||||
|
return data.defragged;
|
||||||
}
|
}
|
||||||
|
|
||||||
long defragQuicklist(redisDb *db, dictEntry *kde) {
|
long defragQuicklist(redisDb *db, dictEntry *kde) {
|
||||||
@ -847,19 +852,19 @@ long defragKey(redisDb *db, dictEntry *de) {
|
|||||||
/* Try to defrag the key name. */
|
/* Try to defrag the key name. */
|
||||||
newsds = activeDefragSds(keysds);
|
newsds = activeDefragSds(keysds);
|
||||||
if (newsds)
|
if (newsds)
|
||||||
defragged++, de->key = newsds;
|
defragged++, dictSetKey(db->dict, de, newsds);
|
||||||
if (dictSize(db->expires)) {
|
if (dictSize(db->expires)) {
|
||||||
/* Dirty code:
|
/* Dirty code:
|
||||||
* I can't search in db->expires for that key after i already released
|
* I can't search in db->expires for that key after i already released
|
||||||
* the pointer it holds it won't be able to do the string compare */
|
* the pointer it holds it won't be able to do the string compare */
|
||||||
uint64_t hash = dictGetHash(db->dict, de->key);
|
uint64_t hash = dictGetHash(db->dict, dictGetKey(de));
|
||||||
replaceSatelliteDictKeyPtrAndOrDefragDictEntry(db->expires, keysds, newsds, hash, &defragged);
|
replaceSatelliteDictKeyPtrAndOrDefragDictEntry(db->expires, keysds, newsds, hash, &defragged);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to defrag robj and / or string value. */
|
/* Try to defrag robj and / or string value. */
|
||||||
ob = dictGetVal(de);
|
ob = dictGetVal(de);
|
||||||
if ((newob = activeDefragStringOb(ob, &defragged))) {
|
if ((newob = activeDefragStringOb(ob, &defragged))) {
|
||||||
de->v.val = newob;
|
dictSetVal(db->dict, de, newob);
|
||||||
ob = newob;
|
ob = newob;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -928,7 +933,7 @@ void defragScanCallback(void *privdata, const dictEntry *de) {
|
|||||||
/* Defrag scan callback for each hash table bucket,
|
/* Defrag scan callback for each hash table bucket,
|
||||||
* used in order to defrag the dictEntry allocations. */
|
* used in order to defrag the dictEntry allocations. */
|
||||||
void defragDictBucketCallback(dict *d, dictEntry **bucketref) {
|
void defragDictBucketCallback(dict *d, dictEntry **bucketref) {
|
||||||
while(*bucketref) {
|
while (bucketref && *bucketref) {
|
||||||
dictEntry *de = *bucketref, *newde;
|
dictEntry *de = *bucketref, *newde;
|
||||||
if ((newde = activeDefragAlloc(de))) {
|
if ((newde = activeDefragAlloc(de))) {
|
||||||
*bucketref = newde;
|
*bucketref = newde;
|
||||||
@ -937,7 +942,7 @@ void defragDictBucketCallback(dict *d, dictEntry **bucketref) {
|
|||||||
slotToKeyReplaceEntry(newde, server.db);
|
slotToKeyReplaceEntry(newde, server.db);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bucketref = &(*bucketref)->next;
|
bucketref = dictGetNextRef(*bucketref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
108
src/dict.c
108
src/dict.c
@ -58,6 +58,22 @@
|
|||||||
static dictResizeEnable dict_can_resize = DICT_RESIZE_ENABLE;
|
static dictResizeEnable dict_can_resize = DICT_RESIZE_ENABLE;
|
||||||
static unsigned int dict_force_resize_ratio = 5;
|
static unsigned int dict_force_resize_ratio = 5;
|
||||||
|
|
||||||
|
/* -------------------------- types ----------------------------------------- */
|
||||||
|
|
||||||
|
struct dictEntry {
|
||||||
|
void *key;
|
||||||
|
union {
|
||||||
|
void *val;
|
||||||
|
uint64_t u64;
|
||||||
|
int64_t s64;
|
||||||
|
double d;
|
||||||
|
} v;
|
||||||
|
struct dictEntry *next; /* Next entry in the same hash bucket. */
|
||||||
|
void *metadata[]; /* An arbitrary number of bytes (starting at a
|
||||||
|
* pointer-aligned address) of size as returned
|
||||||
|
* by dictType's dictEntryMetadataBytes(). */
|
||||||
|
};
|
||||||
|
|
||||||
/* -------------------------- private prototypes ---------------------------- */
|
/* -------------------------- private prototypes ---------------------------- */
|
||||||
|
|
||||||
static int _dictExpandIfNeeded(dict *d);
|
static int _dictExpandIfNeeded(dict *d);
|
||||||
@ -596,6 +612,98 @@ void dictTwoPhaseUnlinkFree(dict *d, dictEntry *he, dictEntry **plink, int table
|
|||||||
dictResumeRehashing(d);
|
dictResumeRehashing(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dictSetKey(dict *d, dictEntry* de, void *key) {
|
||||||
|
if (d->type->keyDup)
|
||||||
|
de->key = d->type->keyDup(d, key);
|
||||||
|
else
|
||||||
|
de->key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dictSetVal(dict *d, dictEntry *de, void *val) {
|
||||||
|
de->v.val = d->type->valDup ? d->type->valDup(d, val) : val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dictSetSignedIntegerVal(dictEntry *de, int64_t val) {
|
||||||
|
de->v.s64 = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dictSetUnsignedIntegerVal(dictEntry *de, uint64_t val) {
|
||||||
|
de->v.u64 = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dictSetDoubleVal(dictEntry *de, double val) {
|
||||||
|
de->v.d = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t dictIncrSignedIntegerVal(dictEntry *de, int64_t val) {
|
||||||
|
return de->v.s64 += val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dictIncrUnsignedIntegerVal(dictEntry *de, uint64_t val) {
|
||||||
|
return de->v.u64 += val;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dictIncrDoubleVal(dictEntry *de, double val) {
|
||||||
|
return de->v.d += val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only used when the next in hash bucket has been reallocated. */
|
||||||
|
void dictSetNext(dictEntry *de, dictEntry *next) {
|
||||||
|
de->next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A pointer to the metadata section within the dict entry. */
|
||||||
|
void *dictMetadata(dictEntry *de) {
|
||||||
|
return &de->metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dictGetKey(const dictEntry *de) {
|
||||||
|
return de->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *dictGetVal(const dictEntry *de) {
|
||||||
|
return de->v.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t dictGetSignedIntegerVal(const dictEntry *de) {
|
||||||
|
return de->v.s64;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t dictGetUnsignedIntegerVal(const dictEntry *de) {
|
||||||
|
return de->v.u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dictGetDoubleVal(const dictEntry *de) {
|
||||||
|
return de->v.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns a mutable reference to the value as a double within the entry. */
|
||||||
|
double *dictGetDoubleValPtr(dictEntry *de) {
|
||||||
|
return &de->v.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The next entry in same hash bucket. */
|
||||||
|
dictEntry *dictGetNext(const dictEntry *de) {
|
||||||
|
return de->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A pointer to the 'next' field within the entry, or NULL if there is no next
|
||||||
|
* field. */
|
||||||
|
dictEntry **dictGetNextRef(dictEntry *de) {
|
||||||
|
return &de->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the memory usage in bytes of the dict, excluding the size of the keys
|
||||||
|
* and values. */
|
||||||
|
size_t dictMemUsage(const dict *d) {
|
||||||
|
return dictSize(d) * sizeof(dictEntry) +
|
||||||
|
dictSlots(d) * sizeof(dictEntry*);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t dictEntryMemUsage(void) {
|
||||||
|
return sizeof(dictEntry);
|
||||||
|
}
|
||||||
|
|
||||||
/* A fingerprint is a 64 bit number that represents the state of the dictionary
|
/* A fingerprint is a 64 bit number that represents the state of the dictionary
|
||||||
* at a given time, it's just a few dict properties xored together.
|
* at a given time, it's just a few dict properties xored together.
|
||||||
* When an unsafe iterator is initialized, we get the dict fingerprint, and check
|
* When an unsafe iterator is initialized, we get the dict fingerprint, and check
|
||||||
|
76
src/dict.h
76
src/dict.h
@ -44,19 +44,7 @@
|
|||||||
#define DICT_OK 0
|
#define DICT_OK 0
|
||||||
#define DICT_ERR 1
|
#define DICT_ERR 1
|
||||||
|
|
||||||
typedef struct dictEntry {
|
typedef struct dictEntry dictEntry; /* opaque */
|
||||||
void *key;
|
|
||||||
union {
|
|
||||||
void *val;
|
|
||||||
uint64_t u64;
|
|
||||||
int64_t s64;
|
|
||||||
double d;
|
|
||||||
} v;
|
|
||||||
struct dictEntry *next; /* Next entry in the same hash bucket. */
|
|
||||||
void *metadata[]; /* An arbitrary number of bytes (starting at a
|
|
||||||
* pointer-aligned address) of size as returned
|
|
||||||
* by dictType's dictEntryMetadataBytes(). */
|
|
||||||
} dictEntry;
|
|
||||||
|
|
||||||
typedef struct dict dict;
|
typedef struct dict dict;
|
||||||
|
|
||||||
@ -112,60 +100,22 @@ typedef void (dictScanBucketFunction)(dict *d, dictEntry **bucketref);
|
|||||||
/* ------------------------------- Macros ------------------------------------*/
|
/* ------------------------------- Macros ------------------------------------*/
|
||||||
#define dictFreeVal(d, entry) do { \
|
#define dictFreeVal(d, entry) do { \
|
||||||
if ((d)->type->valDestructor) \
|
if ((d)->type->valDestructor) \
|
||||||
(d)->type->valDestructor((d), (entry)->v.val); \
|
(d)->type->valDestructor((d), dictGetVal(entry)); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define dictSetVal(d, entry, _val_) do { \
|
|
||||||
if ((d)->type->valDup) \
|
|
||||||
(entry)->v.val = (d)->type->valDup((d), _val_); \
|
|
||||||
else \
|
|
||||||
(entry)->v.val = (_val_); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define dictSetSignedIntegerVal(entry, _val_) \
|
|
||||||
do { (entry)->v.s64 = _val_; } while(0)
|
|
||||||
|
|
||||||
#define dictSetUnsignedIntegerVal(entry, _val_) \
|
|
||||||
do { (entry)->v.u64 = _val_; } while(0)
|
|
||||||
|
|
||||||
#define dictSetDoubleVal(entry, _val_) \
|
|
||||||
do { (entry)->v.d = _val_; } while(0)
|
|
||||||
|
|
||||||
#define dictIncrSignedIntegerVal(entry, _val_) \
|
|
||||||
((entry)->v.s64 += _val_)
|
|
||||||
|
|
||||||
#define dictIncrUnsignedIntegerVal(entry, _val_) \
|
|
||||||
((entry)->v.u64 += _val_)
|
|
||||||
|
|
||||||
#define dictIncrDoubleVal(entry, _val_) \
|
|
||||||
((entry)->v.d += _val_)
|
|
||||||
|
|
||||||
#define dictFreeKey(d, entry) \
|
#define dictFreeKey(d, entry) \
|
||||||
if ((d)->type->keyDestructor) \
|
if ((d)->type->keyDestructor) \
|
||||||
(d)->type->keyDestructor((d), (entry)->key)
|
(d)->type->keyDestructor((d), dictGetKey(entry))
|
||||||
|
|
||||||
#define dictSetKey(d, entry, _key_) do { \
|
|
||||||
if ((d)->type->keyDup) \
|
|
||||||
(entry)->key = (d)->type->keyDup((d), _key_); \
|
|
||||||
else \
|
|
||||||
(entry)->key = (_key_); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
#define dictCompareKeys(d, key1, key2) \
|
#define dictCompareKeys(d, key1, key2) \
|
||||||
(((d)->type->keyCompare) ? \
|
(((d)->type->keyCompare) ? \
|
||||||
(d)->type->keyCompare((d), key1, key2) : \
|
(d)->type->keyCompare((d), key1, key2) : \
|
||||||
(key1) == (key2))
|
(key1) == (key2))
|
||||||
|
|
||||||
#define dictMetadata(entry) (&(entry)->metadata)
|
|
||||||
#define dictMetadataSize(d) ((d)->type->dictEntryMetadataBytes \
|
#define dictMetadataSize(d) ((d)->type->dictEntryMetadataBytes \
|
||||||
? (d)->type->dictEntryMetadataBytes(d) : 0)
|
? (d)->type->dictEntryMetadataBytes(d) : 0)
|
||||||
|
|
||||||
#define dictHashKey(d, key) ((d)->type->hashFunction(key))
|
#define dictHashKey(d, key) ((d)->type->hashFunction(key))
|
||||||
#define dictGetKey(he) ((he)->key)
|
|
||||||
#define dictGetVal(he) ((he)->v.val)
|
|
||||||
#define dictGetSignedIntegerVal(he) ((he)->v.s64)
|
|
||||||
#define dictGetUnsignedIntegerVal(he) ((he)->v.u64)
|
|
||||||
#define dictGetDoubleVal(he) ((he)->v.d)
|
|
||||||
#define dictSlots(d) (DICTHT_SIZE((d)->ht_size_exp[0])+DICTHT_SIZE((d)->ht_size_exp[1]))
|
#define dictSlots(d) (DICTHT_SIZE((d)->ht_size_exp[0])+DICTHT_SIZE((d)->ht_size_exp[1]))
|
||||||
#define dictSize(d) ((d)->ht_used[0]+(d)->ht_used[1])
|
#define dictSize(d) ((d)->ht_used[0]+(d)->ht_used[1])
|
||||||
#define dictIsRehashing(d) ((d)->rehashidx != -1)
|
#define dictIsRehashing(d) ((d)->rehashidx != -1)
|
||||||
@ -202,6 +152,26 @@ void dictRelease(dict *d);
|
|||||||
dictEntry * dictFind(dict *d, const void *key);
|
dictEntry * dictFind(dict *d, const void *key);
|
||||||
void *dictFetchValue(dict *d, const void *key);
|
void *dictFetchValue(dict *d, const void *key);
|
||||||
int dictResize(dict *d);
|
int dictResize(dict *d);
|
||||||
|
void dictSetKey(dict *d, dictEntry* de, void *key);
|
||||||
|
void dictSetVal(dict *d, dictEntry *de, void *val);
|
||||||
|
void dictSetSignedIntegerVal(dictEntry *de, int64_t val);
|
||||||
|
void dictSetUnsignedIntegerVal(dictEntry *de, uint64_t val);
|
||||||
|
void dictSetDoubleVal(dictEntry *de, double val);
|
||||||
|
int64_t dictIncrSignedIntegerVal(dictEntry *de, int64_t val);
|
||||||
|
uint64_t dictIncrUnsignedIntegerVal(dictEntry *de, uint64_t val);
|
||||||
|
double dictIncrDoubleVal(dictEntry *de, double val);
|
||||||
|
void dictSetNext(dictEntry *de, dictEntry *next);
|
||||||
|
void *dictMetadata(dictEntry *de);
|
||||||
|
void *dictGetKey(const dictEntry *de);
|
||||||
|
void *dictGetVal(const dictEntry *de);
|
||||||
|
int64_t dictGetSignedIntegerVal(const dictEntry *de);
|
||||||
|
uint64_t dictGetUnsignedIntegerVal(const dictEntry *de);
|
||||||
|
double dictGetDoubleVal(const dictEntry *de);
|
||||||
|
double *dictGetDoubleValPtr(dictEntry *de);
|
||||||
|
dictEntry *dictGetNext(const dictEntry *de);
|
||||||
|
dictEntry **dictGetNextRef(dictEntry *de);
|
||||||
|
size_t dictMemUsage(const dict *d);
|
||||||
|
size_t dictEntryMemUsage(void);
|
||||||
dictIterator *dictGetIterator(dict *d);
|
dictIterator *dictGetIterator(dict *d);
|
||||||
dictIterator *dictGetSafeIterator(dict *d);
|
dictIterator *dictGetSafeIterator(dict *d);
|
||||||
void dictInitIterator(dictIterator *iter, dict *d);
|
void dictInitIterator(dictIterator *iter, dict *d);
|
||||||
|
@ -677,8 +677,8 @@ dict* evalScriptsDict() {
|
|||||||
|
|
||||||
unsigned long evalScriptsMemory() {
|
unsigned long evalScriptsMemory() {
|
||||||
return lctx.lua_scripts_mem +
|
return lctx.lua_scripts_mem +
|
||||||
dictSize(lctx.lua_scripts) * (sizeof(dictEntry) + sizeof(luaScript)) +
|
dictMemUsage(lctx.lua_scripts) +
|
||||||
dictSlots(lctx.lua_scripts) * sizeof(dictEntry*);
|
dictSize(lctx.lua_scripts) * sizeof(luaScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
|
@ -258,7 +258,7 @@ void activeExpireCycle(int type) {
|
|||||||
/* Get the next entry now since this entry may get
|
/* Get the next entry now since this entry may get
|
||||||
* deleted. */
|
* deleted. */
|
||||||
dictEntry *e = de;
|
dictEntry *e = de;
|
||||||
de = de->next;
|
de = dictGetNext(de);
|
||||||
|
|
||||||
ttl = dictGetSignedIntegerVal(e)-now;
|
ttl = dictGetSignedIntegerVal(e)-now;
|
||||||
if (activeExpireCycleTryExpire(db,e,now)) {
|
if (activeExpireCycleTryExpire(db,e,now)) {
|
||||||
@ -444,8 +444,8 @@ void rememberSlaveKeyWithExpire(redisDb *db, robj *key) {
|
|||||||
* representing the key: we don't want to need to take those keys
|
* representing the key: we don't want to need to take those keys
|
||||||
* in sync with the main DB. The keys will be removed by expireSlaveKeys()
|
* in sync with the main DB. The keys will be removed by expireSlaveKeys()
|
||||||
* as it scans to find keys to remove. */
|
* as it scans to find keys to remove. */
|
||||||
if (de->key == key->ptr) {
|
if (dictGetKey(de) == key->ptr) {
|
||||||
de->key = sdsdup(key->ptr);
|
dictSetKey(slaveKeysWithExpire, de, sdsdup(key->ptr));
|
||||||
dictSetUnsignedIntegerVal(de,0);
|
dictSetUnsignedIntegerVal(de,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1091,10 +1091,9 @@ unsigned long functionsMemory() {
|
|||||||
|
|
||||||
/* Return memory overhead of all the engines combine */
|
/* Return memory overhead of all the engines combine */
|
||||||
unsigned long functionsMemoryOverhead() {
|
unsigned long functionsMemoryOverhead() {
|
||||||
size_t memory_overhead = dictSize(engines) * sizeof(dictEntry) +
|
size_t memory_overhead = dictMemUsage(engines);
|
||||||
dictSlots(engines) * sizeof(dictEntry*);
|
memory_overhead += dictMemUsage(curr_functions_lib_ctx->functions);
|
||||||
memory_overhead += dictSize(curr_functions_lib_ctx->functions) * sizeof(dictEntry) +
|
memory_overhead += sizeof(functionsLibCtx);
|
||||||
dictSlots(curr_functions_lib_ctx->functions) * sizeof(dictEntry*) + sizeof(functionsLibCtx);
|
|
||||||
memory_overhead += curr_functions_lib_ctx->cache_memory;
|
memory_overhead += curr_functions_lib_ctx->cache_memory;
|
||||||
memory_overhead += engine_cache_memory;
|
memory_overhead += engine_cache_memory;
|
||||||
|
|
||||||
|
14
src/object.c
14
src/object.c
@ -1029,7 +1029,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) {
|
|||||||
asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
|
asize = sizeof(*o)+sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d));
|
||||||
while((de = dictNext(di)) != NULL && samples < sample_size) {
|
while((de = dictNext(di)) != NULL && samples < sample_size) {
|
||||||
ele = dictGetKey(de);
|
ele = dictGetKey(de);
|
||||||
elesize += sizeof(struct dictEntry) + sdsZmallocSize(ele);
|
elesize += dictEntryMemUsage() + sdsZmallocSize(ele);
|
||||||
samples++;
|
samples++;
|
||||||
}
|
}
|
||||||
dictReleaseIterator(di);
|
dictReleaseIterator(di);
|
||||||
@ -1053,7 +1053,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) {
|
|||||||
zmalloc_size(zsl->header);
|
zmalloc_size(zsl->header);
|
||||||
while(znode != NULL && samples < sample_size) {
|
while(znode != NULL && samples < sample_size) {
|
||||||
elesize += sdsZmallocSize(znode->ele);
|
elesize += sdsZmallocSize(znode->ele);
|
||||||
elesize += sizeof(struct dictEntry)+zmalloc_size(znode);
|
elesize += dictEntryMemUsage()+zmalloc_size(znode);
|
||||||
samples++;
|
samples++;
|
||||||
znode = znode->level[0].forward;
|
znode = znode->level[0].forward;
|
||||||
}
|
}
|
||||||
@ -1072,7 +1072,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) {
|
|||||||
ele = dictGetKey(de);
|
ele = dictGetKey(de);
|
||||||
ele2 = dictGetVal(de);
|
ele2 = dictGetVal(de);
|
||||||
elesize += sdsZmallocSize(ele) + sdsZmallocSize(ele2);
|
elesize += sdsZmallocSize(ele) + sdsZmallocSize(ele2);
|
||||||
elesize += sizeof(struct dictEntry);
|
elesize += dictEntryMemUsage();
|
||||||
samples++;
|
samples++;
|
||||||
}
|
}
|
||||||
dictReleaseIterator(di);
|
dictReleaseIterator(di);
|
||||||
@ -1242,14 +1242,12 @@ struct redisMemOverhead *getMemoryOverheadData(void) {
|
|||||||
mh->db = zrealloc(mh->db,sizeof(mh->db[0])*(mh->num_dbs+1));
|
mh->db = zrealloc(mh->db,sizeof(mh->db[0])*(mh->num_dbs+1));
|
||||||
mh->db[mh->num_dbs].dbid = j;
|
mh->db[mh->num_dbs].dbid = j;
|
||||||
|
|
||||||
mem = dictSize(db->dict) * sizeof(dictEntry) +
|
mem = dictMemUsage(db->dict) +
|
||||||
dictSlots(db->dict) * sizeof(dictEntry*) +
|
|
||||||
dictSize(db->dict) * sizeof(robj);
|
dictSize(db->dict) * sizeof(robj);
|
||||||
mh->db[mh->num_dbs].overhead_ht_main = mem;
|
mh->db[mh->num_dbs].overhead_ht_main = mem;
|
||||||
mem_total+=mem;
|
mem_total+=mem;
|
||||||
|
|
||||||
mem = dictSize(db->expires) * sizeof(dictEntry) +
|
mem = dictMemUsage(db->expires);
|
||||||
dictSlots(db->expires) * sizeof(dictEntry*);
|
|
||||||
mh->db[mh->num_dbs].overhead_ht_expires = mem;
|
mh->db[mh->num_dbs].overhead_ht_expires = mem;
|
||||||
mem_total+=mem;
|
mem_total+=mem;
|
||||||
|
|
||||||
@ -1547,7 +1545,7 @@ NULL
|
|||||||
}
|
}
|
||||||
size_t usage = objectComputeSize(c->argv[2],dictGetVal(de),samples,c->db->id);
|
size_t usage = objectComputeSize(c->argv[2],dictGetVal(de),samples,c->db->id);
|
||||||
usage += sdsZmallocSize(dictGetKey(de));
|
usage += sdsZmallocSize(dictGetKey(de));
|
||||||
usage += sizeof(dictEntry);
|
usage += dictEntryMemUsage();
|
||||||
usage += dictMetadataSize(c->db->dict);
|
usage += dictMetadataSize(c->db->dict);
|
||||||
addReplyLongLong(c,usage);
|
addReplyLongLong(c,usage);
|
||||||
} else if (!strcasecmp(c->argv[1]->ptr,"stats") && c->argc == 2) {
|
} else if (!strcasecmp(c->argv[1]->ptr,"stats") && c->argc == 2) {
|
||||||
|
@ -727,10 +727,8 @@ size_t pubsubMemOverhead(client *c) {
|
|||||||
/* PubSub patterns */
|
/* PubSub patterns */
|
||||||
size_t mem = listLength(c->pubsub_patterns) * sizeof(listNode);
|
size_t mem = listLength(c->pubsub_patterns) * sizeof(listNode);
|
||||||
/* Global PubSub channels */
|
/* Global PubSub channels */
|
||||||
mem += dictSize(c->pubsub_channels) * sizeof(dictEntry) +
|
mem += dictMemUsage(c->pubsub_channels);
|
||||||
dictSlots(c->pubsub_channels) * sizeof(dictEntry*);
|
|
||||||
/* Sharded PubSub channels */
|
/* Sharded PubSub channels */
|
||||||
mem += dictSize(c->pubsubshard_channels) * sizeof(dictEntry) +
|
mem += dictMemUsage(c->pubsubshard_channels);
|
||||||
dictSlots(c->pubsubshard_channels) * sizeof(dictEntry*);
|
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
@ -762,7 +762,7 @@ void cliInitGroupHelpEntries(dict *groups) {
|
|||||||
for (entry = dictNext(iter); entry != NULL; entry = dictNext(iter)) {
|
for (entry = dictNext(iter); entry != NULL; entry = dictNext(iter)) {
|
||||||
tmp.argc = 1;
|
tmp.argc = 1;
|
||||||
tmp.argv = zmalloc(sizeof(sds));
|
tmp.argv = zmalloc(sizeof(sds));
|
||||||
tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",(char *)entry->key);
|
tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",(char *)dictGetKey(entry));
|
||||||
tmp.full = tmp.argv[0];
|
tmp.full = tmp.argv[0];
|
||||||
tmp.type = CLI_HELP_GROUP;
|
tmp.type = CLI_HELP_GROUP;
|
||||||
tmp.org.name = NULL;
|
tmp.org.name = NULL;
|
||||||
|
@ -1428,7 +1428,7 @@ int zsetAdd(robj *zobj, double score, sds ele, int in_flags, int *out_flags, dou
|
|||||||
/* Note that we did not removed the original element from
|
/* Note that we did not removed the original element from
|
||||||
* the hash table representing the sorted set, so we just
|
* the hash table representing the sorted set, so we just
|
||||||
* update the score. */
|
* update the score. */
|
||||||
dictGetVal(de) = &znode->score; /* Update score ptr. */
|
dictSetVal(zs->dict, de, &znode->score); /* Update score ptr. */
|
||||||
*out_flags |= ZADD_OUT_UPDATED;
|
*out_flags |= ZADD_OUT_UPDATED;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@ -2741,7 +2741,8 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
|
|||||||
* Here we access directly the dictEntry double
|
* Here we access directly the dictEntry double
|
||||||
* value inside the union as it is a big speedup
|
* value inside the union as it is a big speedup
|
||||||
* compared to using the getDouble/setDouble API. */
|
* compared to using the getDouble/setDouble API. */
|
||||||
zunionInterAggregate(&existing->v.d,score,aggregate);
|
double *existing_score_ptr = dictGetDoubleValPtr(existing);
|
||||||
|
zunionInterAggregate(existing_score_ptr, score, aggregate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
zuiClearIterator(&src[i]);
|
zuiClearIterator(&src[i]);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user