/* The goal of this function is to return the amount of memory used by * the UniqueType value. */ size_t UniqueTypeMemUsage(const void *value) { const unique *unique = value; size_t list = listLength(unique->l) * sizeof(listNode) + sizeof(list); size_t dict = sizeof(dict) + 2*sizeof(dictht) + dictSlots(unique->d) * sizeof(dictEntry); return list + dict + unique->mem; }
int htNeedsResize(dict *dict) { long long size, used; size = dictSlots(dict); used = dictSize(dict); return (size && used && size > DICT_HT_INITIAL_SIZE && (used*100/size < HASHTABLE_MIN_FILL)); }
/* convert a hash dictionary encoding to a dictionary array encoding */ cowDictZArray *cowConvertDictToZArray(dict *hdict) { dictIterator * di; dictEntry *de; int dsize; cowDictZArray *dar; int dcount = 0; dictZEntry *dezNew; dictZEntry *dezPrev; /* create copy */ dsize = dictSize(hdict) > dictSlots(hdict) ? dictSize(hdict) : dictSlots(hdict); dar = (cowDictZArray *)zmalloc(sizeof(cowDictZArray) + (dsize * sizeof(dictZEntry)) ); /* copy all entries without refcounting or copying values */ /* can't just memcpy the whole dictionary because entries are allocated */ di = dictGetSafeIterator(hdict); dezNew = &dar->zde[0]; dezPrev = NULL; while((de = dictNext(di)) != NULL && dcount < dsize) { double *score = (double *)dictGetEntryVal(de); /* copy score value into array and point val to score. */ dezNew->de.key = de->key; dezNew->score = *score; dezNew->de.val = &dezNew->score; /* fix next ptr of prev entry */ if (dezPrev != NULL) { dezPrev->de.next = &dezNew->de; } dezPrev = dezNew; dezNew++; dcount++; } if (dezPrev != NULL) { dezPrev->de.next = NULL; } dar->numele = dcount; dictReleaseIterator(di); return dar; }
/* convert a hash dictionary encoding to a dictionary array encoding */ cowDictArray *cowConvertDictToArray(dict *hdict) { dictIterator * di; dictEntry *de; int dsize; cowDictArray *dar; int dcount = 0; dictEntry *deNew; dictEntry *dePrev; /* create copy */ dsize = dictSize(hdict) > dictSlots(hdict) ? dictSize(hdict) : dictSlots(hdict); dar = (cowDictArray *)zmalloc(sizeof(cowDictArray) + (dsize * sizeof(dictEntry))); /* copy all entries without refcounting or copying values */ /* can't just memcpy the whole dictionary because entries are allocated */ di = dictGetSafeIterator(hdict); deNew = &dar->de[0]; dePrev = NULL; while((de = dictNext(di)) != NULL && dcount < dsize) { /* copy object value to dict array Do not incr ref count. */ deNew->val = de->val; deNew->key = de->key; /* fix next ptr of prev entry */ if (dePrev != NULL) { dePrev->next = deNew; } dePrev = deNew; deNew++; dcount++; } if (dePrev != NULL) { dePrev->next = NULL; } dar->numele = dcount; dictReleaseIterator(di); return dar; }
/* How a good candidate is this object for swapping? * The better candidate it is, the greater the returned value. * * Currently we try to perform a fast estimation of the object size in * memory, and combine it with aging informations. * * Basically swappability = idle-time * log(estimated size) * * Bigger objects are preferred over smaller objects, but not * proportionally, this is why we use the logarithm. This algorithm is * just a first try and will probably be tuned later. */ double computeObjectSwappability(robj *o) { /* actual age can be >= minage, but not < minage. As we use wrapping * 21 bit clocks with minutes resolution for the LRU. */ time_t minage = estimateObjectIdleTime(o); #ifdef _WIN32 ssize_t asize = 0, elesize; #else long asize = 0, elesize; #endif robj *ele; list *l; listNode *ln; dict *d; struct dictEntry *de; if (minage <= 0) return 0; switch(o->type) { case REDIS_STRING: if (o->encoding != REDIS_ENCODING_RAW) { asize = sizeof(*o); } else { #ifdef _WIN32 asize = sdslen(o->ptr)+sizeof(*o)+sizeof(size_t)*2; #else asize = sdslen(o->ptr)+sizeof(*o)+sizeof(long)*2; #endif } break; case REDIS_LIST: if (o->encoding == REDIS_ENCODING_ZIPLIST) { asize = sizeof(*o)+ziplistBlobLen(o->ptr); } else { l = o->ptr; ln = listFirst(l); asize = sizeof(list); if (ln) { ele = ln->value; elesize = (ele->encoding == REDIS_ENCODING_RAW) ? (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); asize += (sizeof(listNode)+elesize)*listLength(l); } } break; case REDIS_SET: if (o->encoding == REDIS_ENCODING_INTSET) { intset *is = o->ptr; asize = sizeof(*is)+is->encoding*is->length; } else { d = o->ptr; asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d)); if (dictSize(d)) { de = dictGetRandomKey(d); ele = dictGetEntryKey(de); elesize = (ele->encoding == REDIS_ENCODING_RAW) ? (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); asize += (sizeof(struct dictEntry)+elesize)*dictSize(d); } } break; case REDIS_ZSET: if (o->encoding == REDIS_ENCODING_ZIPLIST) { asize = sizeof(*o)+(ziplistBlobLen(o->ptr) / 2); } else { d = ((zset*)o->ptr)->dict; asize = sizeof(zset)+(sizeof(struct dictEntry*)*dictSlots(d)); if (dictSize(d)) { de = dictGetRandomKey(d); ele = dictGetEntryKey(de); elesize = (ele->encoding == REDIS_ENCODING_RAW) ? (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); asize += (sizeof(struct dictEntry)+elesize)*dictSize(d); asize += sizeof(zskiplistNode)*dictSize(d); } } break; case REDIS_HASH: if (o->encoding == REDIS_ENCODING_ZIPMAP) { unsigned char *p = zipmapRewind((unsigned char*)o->ptr); unsigned int len = zipmapLen((unsigned char*)o->ptr); unsigned int klen, vlen; unsigned char *key, *val; if ((p = zipmapNext(p,&key,&klen,&val,&vlen)) == NULL) { klen = 0; vlen = 0; } asize = len*(klen+vlen+3); } else if (o->encoding == REDIS_ENCODING_HT) { d = o->ptr; asize = sizeof(dict)+(sizeof(struct dictEntry*)*dictSlots(d)); if (dictSize(d)) { de = dictGetRandomKey(d); ele = dictGetEntryKey(de); elesize = (ele->encoding == REDIS_ENCODING_RAW) ? (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); ele = dictGetEntryVal(de); elesize = (ele->encoding == REDIS_ENCODING_RAW) ? (sizeof(*o)+sdslen(ele->ptr)) : sizeof(*o); asize += (sizeof(struct dictEntry)+elesize)*dictSize(d); } } break; } return (double)minage*log(1+(double)asize); }