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. */
|
||||
|
||||
void slotToKeyAddEntry(dictEntry *entry, redisDb *db) {
|
||||
sds key = entry->key;
|
||||
sds key = dictGetKey(entry);
|
||||
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||
slot_to_keys->count++;
|
||||
@ -7305,7 +7305,7 @@ void slotToKeyAddEntry(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));
|
||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||
slot_to_keys->count--;
|
||||
@ -7337,7 +7337,7 @@ void slotToKeyReplaceEntry(dictEntry *entry, redisDb *db) {
|
||||
dictEntryNextInSlot(prev) = entry;
|
||||
} else {
|
||||
/* The replaced entry was the first in the list. */
|
||||
sds key = entry->key;
|
||||
sds key = dictGetKey(entry);
|
||||
unsigned int hashslot = keyHashSlot(key, sdslen(key));
|
||||
slotToKeys *slot_to_keys = &(*db->slots_to_keys).by_slot[hashslot];
|
||||
slot_to_keys->head = entry;
|
||||
|
@ -989,8 +989,8 @@ void configGetCommand(client *c) {
|
||||
/* Note that hidden configs require an exact match (not a pattern) */
|
||||
if (config->flags & HIDDEN_CONFIG) continue;
|
||||
if (dictFind(matches, config->name)) continue;
|
||||
if (stringmatch(name, de->key, 1)) {
|
||||
dictAdd(matches, de->key, config);
|
||||
if (stringmatch(name, dictGetKey(de), 1)) {
|
||||
dictAdd(matches, dictGetKey(de), config);
|
||||
}
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@ -1000,7 +1000,7 @@ void configGetCommand(client *c) {
|
||||
addReplyMapLen(c, dictSize(matches));
|
||||
while ((de = dictNext(di)) != NULL) {
|
||||
standardConfig *config = (standardConfig *) dictGetVal(de);
|
||||
addReplyBulkCString(c, de->key);
|
||||
addReplyBulkCString(c, dictGetKey(de));
|
||||
addReplyBulkSds(c, config->interface.get(config));
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@ -1754,7 +1754,7 @@ int rewriteConfig(char *path, int force_write) {
|
||||
standardConfig *config = dictGetVal(de);
|
||||
/* Only rewrite the primary names */
|
||||
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);
|
||||
|
||||
|
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);
|
||||
|
||||
serverAssertWithInfo(NULL,key,de != NULL);
|
||||
dictEntry auxentry = *de;
|
||||
robj *old = dictGetVal(de);
|
||||
if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
|
||||
val->lru = old->lru;
|
||||
@ -246,17 +245,15 @@ static void dbSetValue(redisDb *db, robj *key, robj *val, int overwrite) {
|
||||
decrRefCount(old);
|
||||
/* Because of RM_StringDMA, old may be changed, so we need get old again */
|
||||
old = dictGetVal(de);
|
||||
/* Entry in auxentry may be changed, so we need update auxentry */
|
||||
auxentry = *de;
|
||||
}
|
||||
dictSetVal(db->dict, de, val);
|
||||
|
||||
if (server.lazyfree_lazy_server_del) {
|
||||
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
|
||||
|
@ -868,7 +868,7 @@ NULL
|
||||
sds sizes = sdsempty();
|
||||
sizes = sdscatprintf(sizes,"bits:%d ",(sizeof(void*) == 8)?64:32);
|
||||
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,"sdshdr8:%d ",(int)sizeof(struct sdshdr8));
|
||||
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) {
|
||||
defragged++;
|
||||
iter->nextEntry = newde;
|
||||
iter->entry->next = newde;
|
||||
dictSetNext(iter->entry, newde);
|
||||
}
|
||||
}
|
||||
/* handle the case of the first entry in the hash bucket. */
|
||||
@ -264,7 +264,7 @@ long activeDefragZsetEntry(zset *zs, dictEntry *de) {
|
||||
long defragged = 0;
|
||||
sds sdsele = dictGetKey(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
defragged++, de->key = newsds;
|
||||
defragged++, dictSetKey(zs->dict, de, newsds);
|
||||
newscore = zslDefrag(zs->zsl, *(double*)dictGetVal(de), sdsele, newsds);
|
||||
if (newscore) {
|
||||
dictSetVal(zs->dict, de, newscore);
|
||||
@ -288,24 +288,24 @@ long activeDefragSdsDict(dict* d, int val_type) {
|
||||
while((de = dictNext(di)) != NULL) {
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
de->key = newsds, defragged++;
|
||||
dictSetKey(d, de, newsds), defragged++;
|
||||
/* defrag the value */
|
||||
if (val_type == DEFRAG_SDS_DICT_VAL_IS_SDS) {
|
||||
sdsele = dictGetVal(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
de->v.val = newsds, defragged++;
|
||||
dictSetVal(d, de, newsds), defragged++;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_IS_STROB) {
|
||||
robj *newele, *ele = dictGetVal(de);
|
||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||
de->v.val = newele;
|
||||
dictSetVal(d, de, newele);
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||
void *newptr, *ptr = dictGetVal(de);
|
||||
if ((newptr = activeDefragAlloc(ptr)))
|
||||
de->v.val = newptr, defragged++;
|
||||
dictSetVal(d, de, newptr), defragged++;
|
||||
} else if (val_type == DEFRAG_SDS_DICT_VAL_LUA_SCRIPT) {
|
||||
void *newptr, *ptr = dictGetVal(de);
|
||||
if ((newptr = activeDefragLuaScript(ptr, &defragged)))
|
||||
de->v.val = newptr;
|
||||
dictSetVal(d, de, newptr);
|
||||
}
|
||||
defragged += dictIterDefragEntry(di);
|
||||
}
|
||||
@ -374,7 +374,7 @@ long activeDefragSdsListAndDict(list *l, dict *d, int dict_val_type) {
|
||||
uint64_t hash = dictGetHash(d, newsds);
|
||||
dictEntry **deref = dictFindEntryRefByPtrAndHash(d, sdsele, hash);
|
||||
if (deref)
|
||||
(*deref)->key = newsds;
|
||||
dictSetKey(d, *deref, newsds);
|
||||
ln->value = newsds;
|
||||
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) {
|
||||
sds newsds, sdsele = dictGetVal(de);
|
||||
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) {
|
||||
robj *newele, *ele = dictGetVal(de);
|
||||
if ((newele = activeDefragStringOb(ele, &defragged)))
|
||||
de->v.val = newele;
|
||||
dictSetVal(d, de, newele);
|
||||
} else if (dict_val_type == DEFRAG_SDS_DICT_VAL_VOID_PTR) {
|
||||
void *newptr, *ptr = dictGetVal(de);
|
||||
if ((newptr = activeDefragAlloc(ptr)))
|
||||
de->v.val = newptr, defragged++;
|
||||
dictSetVal(d, de, newptr), defragged++;
|
||||
}
|
||||
defragged += dictIterDefragEntry(di);
|
||||
}
|
||||
@ -420,7 +420,7 @@ dictEntry* replaceSatelliteDictKeyPtrAndOrDefragDictEntry(dict *d, sds oldkey, s
|
||||
(*defragged)++;
|
||||
}
|
||||
if (newkey)
|
||||
de->key = newkey;
|
||||
dictSetKey(d, de, newkey);
|
||||
return de;
|
||||
}
|
||||
return NULL;
|
||||
@ -531,43 +531,48 @@ long scanLaterZset(robj *ob, unsigned long *cursor) {
|
||||
return data.defragged;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
dict *dict;
|
||||
long defragged;
|
||||
} scanLaterDictData;
|
||||
|
||||
void scanLaterSetCallback(void *privdata, const dictEntry *_de) {
|
||||
dictEntry *de = (dictEntry*)_de;
|
||||
long *defragged = privdata;
|
||||
scanLaterDictData *data = privdata;
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->key = newsds;
|
||||
data->defragged++, dictSetKey(data->dict, de, newsds);
|
||||
server.stat_active_defrag_scanned++;
|
||||
}
|
||||
|
||||
long scanLaterSet(robj *ob, unsigned long *cursor) {
|
||||
long defragged = 0;
|
||||
if (ob->type != OBJ_SET || ob->encoding != OBJ_ENCODING_HT)
|
||||
return 0;
|
||||
dict *d = ob->ptr;
|
||||
*cursor = dictScan(d, *cursor, scanLaterSetCallback, defragDictBucketCallback, &defragged);
|
||||
return defragged;
|
||||
scanLaterDictData data = {d, 0};
|
||||
*cursor = dictScan(d, *cursor, scanLaterSetCallback, defragDictBucketCallback, &data);
|
||||
return data.defragged;
|
||||
}
|
||||
|
||||
void scanLaterHashCallback(void *privdata, const dictEntry *_de) {
|
||||
dictEntry *de = (dictEntry*)_de;
|
||||
long *defragged = privdata;
|
||||
scanLaterDictData *data = privdata;
|
||||
sds sdsele = dictGetKey(de), newsds;
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->key = newsds;
|
||||
data->defragged++, dictSetKey(data->dict, de, newsds);
|
||||
sdsele = dictGetVal(de);
|
||||
if ((newsds = activeDefragSds(sdsele)))
|
||||
(*defragged)++, de->v.val = newsds;
|
||||
data->defragged++, dictSetVal(data->dict, de, newsds);
|
||||
server.stat_active_defrag_scanned++;
|
||||
}
|
||||
|
||||
long scanLaterHash(robj *ob, unsigned long *cursor) {
|
||||
long defragged = 0;
|
||||
if (ob->type != OBJ_HASH || ob->encoding != OBJ_ENCODING_HT)
|
||||
return 0;
|
||||
dict *d = ob->ptr;
|
||||
*cursor = dictScan(d, *cursor, scanLaterHashCallback, defragDictBucketCallback, &defragged);
|
||||
return defragged;
|
||||
scanLaterDictData data = {d, 0};
|
||||
*cursor = dictScan(d, *cursor, scanLaterHashCallback, defragDictBucketCallback, &data);
|
||||
return data.defragged;
|
||||
}
|
||||
|
||||
long defragQuicklist(redisDb *db, dictEntry *kde) {
|
||||
@ -847,19 +852,19 @@ long defragKey(redisDb *db, dictEntry *de) {
|
||||
/* Try to defrag the key name. */
|
||||
newsds = activeDefragSds(keysds);
|
||||
if (newsds)
|
||||
defragged++, de->key = newsds;
|
||||
defragged++, dictSetKey(db->dict, de, newsds);
|
||||
if (dictSize(db->expires)) {
|
||||
/* Dirty code:
|
||||
* 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 */
|
||||
uint64_t hash = dictGetHash(db->dict, de->key);
|
||||
uint64_t hash = dictGetHash(db->dict, dictGetKey(de));
|
||||
replaceSatelliteDictKeyPtrAndOrDefragDictEntry(db->expires, keysds, newsds, hash, &defragged);
|
||||
}
|
||||
|
||||
/* Try to defrag robj and / or string value. */
|
||||
ob = dictGetVal(de);
|
||||
if ((newob = activeDefragStringOb(ob, &defragged))) {
|
||||
de->v.val = newob;
|
||||
dictSetVal(db->dict, de, newob);
|
||||
ob = newob;
|
||||
}
|
||||
|
||||
@ -928,7 +933,7 @@ void defragScanCallback(void *privdata, const dictEntry *de) {
|
||||
/* Defrag scan callback for each hash table bucket,
|
||||
* used in order to defrag the dictEntry allocations. */
|
||||
void defragDictBucketCallback(dict *d, dictEntry **bucketref) {
|
||||
while(*bucketref) {
|
||||
while (bucketref && *bucketref) {
|
||||
dictEntry *de = *bucketref, *newde;
|
||||
if ((newde = activeDefragAlloc(de))) {
|
||||
*bucketref = newde;
|
||||
@ -937,7 +942,7 @@ void defragDictBucketCallback(dict *d, dictEntry **bucketref) {
|
||||
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 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 ---------------------------- */
|
||||
|
||||
static int _dictExpandIfNeeded(dict *d);
|
||||
@ -596,6 +612,98 @@ void dictTwoPhaseUnlinkFree(dict *d, dictEntry *he, dictEntry **plink, int table
|
||||
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
|
||||
* 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
|
||||
|
76
src/dict.h
76
src/dict.h
@ -44,19 +44,7 @@
|
||||
#define DICT_OK 0
|
||||
#define DICT_ERR 1
|
||||
|
||||
typedef 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(). */
|
||||
} dictEntry;
|
||||
typedef struct dictEntry dictEntry; /* opaque */
|
||||
|
||||
typedef struct dict dict;
|
||||
|
||||
@ -112,60 +100,22 @@ typedef void (dictScanBucketFunction)(dict *d, dictEntry **bucketref);
|
||||
/* ------------------------------- Macros ------------------------------------*/
|
||||
#define dictFreeVal(d, entry) do { \
|
||||
if ((d)->type->valDestructor) \
|
||||
(d)->type->valDestructor((d), (entry)->v.val); \
|
||||
(d)->type->valDestructor((d), dictGetVal(entry)); \
|
||||
} 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) \
|
||||
if ((d)->type->keyDestructor) \
|
||||
(d)->type->keyDestructor((d), (entry)->key)
|
||||
|
||||
#define dictSetKey(d, entry, _key_) do { \
|
||||
if ((d)->type->keyDup) \
|
||||
(entry)->key = (d)->type->keyDup((d), _key_); \
|
||||
else \
|
||||
(entry)->key = (_key_); \
|
||||
} while(0)
|
||||
(d)->type->keyDestructor((d), dictGetKey(entry))
|
||||
|
||||
#define dictCompareKeys(d, key1, key2) \
|
||||
(((d)->type->keyCompare) ? \
|
||||
(d)->type->keyCompare((d), key1, key2) : \
|
||||
(key1) == (key2))
|
||||
|
||||
#define dictMetadata(entry) (&(entry)->metadata)
|
||||
#define dictMetadataSize(d) ((d)->type->dictEntryMetadataBytes \
|
||||
? (d)->type->dictEntryMetadataBytes(d) : 0)
|
||||
|
||||
#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 dictSize(d) ((d)->ht_used[0]+(d)->ht_used[1])
|
||||
#define dictIsRehashing(d) ((d)->rehashidx != -1)
|
||||
@ -202,6 +152,26 @@ void dictRelease(dict *d);
|
||||
dictEntry * dictFind(dict *d, const void *key);
|
||||
void *dictFetchValue(dict *d, const void *key);
|
||||
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 *dictGetSafeIterator(dict *d);
|
||||
void dictInitIterator(dictIterator *iter, dict *d);
|
||||
|
@ -677,8 +677,8 @@ dict* evalScriptsDict() {
|
||||
|
||||
unsigned long evalScriptsMemory() {
|
||||
return lctx.lua_scripts_mem +
|
||||
dictSize(lctx.lua_scripts) * (sizeof(dictEntry) + sizeof(luaScript)) +
|
||||
dictSlots(lctx.lua_scripts) * sizeof(dictEntry*);
|
||||
dictMemUsage(lctx.lua_scripts) +
|
||||
dictSize(lctx.lua_scripts) * sizeof(luaScript);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
@ -258,7 +258,7 @@ void activeExpireCycle(int type) {
|
||||
/* Get the next entry now since this entry may get
|
||||
* deleted. */
|
||||
dictEntry *e = de;
|
||||
de = de->next;
|
||||
de = dictGetNext(de);
|
||||
|
||||
ttl = dictGetSignedIntegerVal(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
|
||||
* in sync with the main DB. The keys will be removed by expireSlaveKeys()
|
||||
* as it scans to find keys to remove. */
|
||||
if (de->key == key->ptr) {
|
||||
de->key = sdsdup(key->ptr);
|
||||
if (dictGetKey(de) == key->ptr) {
|
||||
dictSetKey(slaveKeysWithExpire, de, sdsdup(key->ptr));
|
||||
dictSetUnsignedIntegerVal(de,0);
|
||||
}
|
||||
|
||||
|
@ -1091,10 +1091,9 @@ unsigned long functionsMemory() {
|
||||
|
||||
/* Return memory overhead of all the engines combine */
|
||||
unsigned long functionsMemoryOverhead() {
|
||||
size_t memory_overhead = dictSize(engines) * sizeof(dictEntry) +
|
||||
dictSlots(engines) * sizeof(dictEntry*);
|
||||
memory_overhead += dictSize(curr_functions_lib_ctx->functions) * sizeof(dictEntry) +
|
||||
dictSlots(curr_functions_lib_ctx->functions) * sizeof(dictEntry*) + sizeof(functionsLibCtx);
|
||||
size_t memory_overhead = dictMemUsage(engines);
|
||||
memory_overhead += dictMemUsage(curr_functions_lib_ctx->functions);
|
||||
memory_overhead += sizeof(functionsLibCtx);
|
||||
memory_overhead += curr_functions_lib_ctx->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));
|
||||
while((de = dictNext(di)) != NULL && samples < sample_size) {
|
||||
ele = dictGetKey(de);
|
||||
elesize += sizeof(struct dictEntry) + sdsZmallocSize(ele);
|
||||
elesize += dictEntryMemUsage() + sdsZmallocSize(ele);
|
||||
samples++;
|
||||
}
|
||||
dictReleaseIterator(di);
|
||||
@ -1053,7 +1053,7 @@ size_t objectComputeSize(robj *key, robj *o, size_t sample_size, int dbid) {
|
||||
zmalloc_size(zsl->header);
|
||||
while(znode != NULL && samples < sample_size) {
|
||||
elesize += sdsZmallocSize(znode->ele);
|
||||
elesize += sizeof(struct dictEntry)+zmalloc_size(znode);
|
||||
elesize += dictEntryMemUsage()+zmalloc_size(znode);
|
||||
samples++;
|
||||
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);
|
||||
ele2 = dictGetVal(de);
|
||||
elesize += sdsZmallocSize(ele) + sdsZmallocSize(ele2);
|
||||
elesize += sizeof(struct dictEntry);
|
||||
elesize += dictEntryMemUsage();
|
||||
samples++;
|
||||
}
|
||||
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[mh->num_dbs].dbid = j;
|
||||
|
||||
mem = dictSize(db->dict) * sizeof(dictEntry) +
|
||||
dictSlots(db->dict) * sizeof(dictEntry*) +
|
||||
mem = dictMemUsage(db->dict) +
|
||||
dictSize(db->dict) * sizeof(robj);
|
||||
mh->db[mh->num_dbs].overhead_ht_main = mem;
|
||||
mem_total+=mem;
|
||||
|
||||
mem = dictSize(db->expires) * sizeof(dictEntry) +
|
||||
dictSlots(db->expires) * sizeof(dictEntry*);
|
||||
mem = dictMemUsage(db->expires);
|
||||
mh->db[mh->num_dbs].overhead_ht_expires = mem;
|
||||
mem_total+=mem;
|
||||
|
||||
@ -1547,7 +1545,7 @@ NULL
|
||||
}
|
||||
size_t usage = objectComputeSize(c->argv[2],dictGetVal(de),samples,c->db->id);
|
||||
usage += sdsZmallocSize(dictGetKey(de));
|
||||
usage += sizeof(dictEntry);
|
||||
usage += dictEntryMemUsage();
|
||||
usage += dictMetadataSize(c->db->dict);
|
||||
addReplyLongLong(c,usage);
|
||||
} else if (!strcasecmp(c->argv[1]->ptr,"stats") && c->argc == 2) {
|
||||
|
@ -727,10 +727,8 @@ size_t pubsubMemOverhead(client *c) {
|
||||
/* PubSub patterns */
|
||||
size_t mem = listLength(c->pubsub_patterns) * sizeof(listNode);
|
||||
/* Global PubSub channels */
|
||||
mem += dictSize(c->pubsub_channels) * sizeof(dictEntry) +
|
||||
dictSlots(c->pubsub_channels) * sizeof(dictEntry*);
|
||||
mem += dictMemUsage(c->pubsub_channels);
|
||||
/* Sharded PubSub channels */
|
||||
mem += dictSize(c->pubsubshard_channels) * sizeof(dictEntry) +
|
||||
dictSlots(c->pubsubshard_channels) * sizeof(dictEntry*);
|
||||
mem += dictMemUsage(c->pubsubshard_channels);
|
||||
return mem;
|
||||
}
|
||||
|
@ -762,7 +762,7 @@ void cliInitGroupHelpEntries(dict *groups) {
|
||||
for (entry = dictNext(iter); entry != NULL; entry = dictNext(iter)) {
|
||||
tmp.argc = 1;
|
||||
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.type = CLI_HELP_GROUP;
|
||||
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
|
||||
* the hash table representing the sorted set, so we just
|
||||
* update the score. */
|
||||
dictGetVal(de) = &znode->score; /* Update score ptr. */
|
||||
dictSetVal(zs->dict, de, &znode->score); /* Update score ptr. */
|
||||
*out_flags |= ZADD_OUT_UPDATED;
|
||||
}
|
||||
return 1;
|
||||
@ -2741,7 +2741,8 @@ void zunionInterDiffGenericCommand(client *c, robj *dstkey, int numkeysIndex, in
|
||||
* Here we access directly the dictEntry double
|
||||
* value inside the union as it is a big speedup
|
||||
* 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]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user