Redis存储键值方式详解(3)

/* Expand or create the hash table */
int dictExpand(dict *d, unsigned long size)
{
    dictht n; /* the new hash table */
    unsigned long realsize = _dictNextPower(size);

/* the size is invalid if it is smaller than the number of
    * elements already inside the hash table */
    if (dictIsRehashing(d) || d->ht[0].used > size)
        return DICT_ERR;

/* Rehashing to the same table size is not useful. */
    if (realsize == d->ht[0].size) return DICT_ERR;

/* Allocate the new hash table and initialize all pointers to NULL */
    n.size = realsize;
    n.sizemask = realsize-1;
    n.table = zcalloc(realsize*sizeof(dictEntry*));
    n.used = 0;

/* Is this the first initialization? If so it's not really a rehashing
    * we just set the first hash table so that it can accept keys. */
    if (d->ht[0].table == NULL) {
        d->ht[0] = n;
        return DICT_OK;
    }

/* Prepare a second hash table for incremental rehashing */
    d->ht[1] = n;
    d->rehashidx = 0;
    return DICT_OK;
}

从数据结构的角度来看,redis的dict和java的HashMap很像,区别在于rehash:HashMap在resize时是一次性拷贝的,然后使用新的数组,而dict维持了2个dictht,平常使用ht[0],一旦开始rehash则使用ht[0]和ht[1],rehash被分摊到每次的dictAdd和dictFind等操作中。

dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    unsigned int h, idx, table;

if (d->ht[0].used + d->ht[1].used == 0) return NULL; /* dict is empty */
    if (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) { //会遍历d->ht[0]和d->ht[1]
        idx = h & d->ht[table].sizemask;
        he = d->ht[table].table[idx];
        while(he) {
            if (key==he->key || dictCompareKeys(d, key, he->key))
                return he; //找到即返回
            he = he->next;
        }
        if (!dictIsRehashing(d)) return NULL;
    }
    return NULL;
}

redis为什么要如此设计?

试想一下,如果和java的HashMap一样,redis也是一次性拷贝,那么当这个dict非常大时,拷贝就会比较耗时,而在这段时间内,redis就无法对外提供服务了。

这种设计增加了复杂度,开始rehash后,dict的数据分散在ht[0]和ht[1]中,对于查询(dictFind)和删除(dictDelete)和设置(dictReplace),则会遍历ht[0]和ht[1]。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/4dc303c4e08d7a6eb9e7693eede8056c.html