redis dict 字典源码分析

// 调用hash生成函数,生成key对应的hash值
#define dictHashKey(d, key) (d)->type->hashFunction(key)


// 比较key1和key2是否相等,相等返回真
// 如果有提供key值比较的函数就调用这个函数,没有的话就直接比较key
#define dictCompareKeys(d, key1, key2) \
    (((d)->type->keyCompare) ? \
        (d)->type->keyCompare((d)->privdata, key1, key2) : \
        (key1) == (key2))

// 目的是为了设置entry的key值
// 如果提供了keyDup函数就调用这个函数
// 没有的话key直接赋值
#define dictSetKey(d, entry, _key_) do { \
    if ((d)->type->keyDup) \
        entry->key = (d)->type->keyDup((d)->privdata, _key_); \
    else \
        entry->key = (_key_); \
} while(0)



// 目的是为了设置entry的val值
// 如果提供了valDup函数就调用这个函数
// 没有的话val直接赋值
#define dictSetVal(d, entry, _val_) do { \
    if ((d)->type->valDup) \
        entry->v.val = (d)->type->valDup((d)->privdata, _val_); \
    else \
        entry->v.val = (_val_); \
} while(0)



// 找到第一个大于size的数并且这个数字是2的幂
static unsigned long _dictNextPower(unsigned long size)
{
    unsigned long i = DICT_HT_INITIAL_SIZE;
    // 最大不能大于LONG_MAX
    if (size >= LONG_MAX) return LONG_MAX;
    while(1) {
        if (i >= size)
            return i;
        i *= 2;  // 2的幂
    }
}


// 判断是否需要拓展hash table
// 注意返回的结果不是需不需要拓展,而是如果需要拓展就会直接拓展,返回值由dictExpand决定
// 不需要拓展则返回DICT_OK
static int _dictExpandIfNeeded(dict *d)
{
    /* Incremental rehashing already in progress. Return. */
    if (dictIsRehashing(d)) return DICT_OK;

    /* If the hash table is empty expand it to the initial size. */
    if (d->ht[0].size == 0) return dictExpand(d, DICT_HT_INITIAL_SIZE);

    /* If we reached the 1:1 ratio, and we are allowed to resize the hash
     * table (global setting) or we should avoid it but the ratio between
     * elements/buckets is over the "safe" threshold, we resize doubling
     * the number of buckets. */
    if (d->ht[0].used >= d->ht[0].size &&
        (dict_can_resize ||
         d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
    {
        return dictExpand(d, d->ht[0].used*2);
    }
    return DICT_OK;
}



// 添加key-val到d这个字典中
/* Add an element to the target hash table */
int dictAdd(dict *d, void *key, void *val)
{
    dictEntry *entry = dictAddRaw(d,key);

    if (!entry) return DICT_ERR;
    // 设置value值
    dictSetVal(d, entry, val);
    return DICT_OK;
}



dictEntry *dictAddRaw(dict *d, void *key)
{
    int index;
    dictEntry *entry;
    dictht *ht;

    if (dictIsRehashing(d)) _dictRehashStep(d);

    /* Get the index of the new element, or -1 if
     * the element already exists. */
    if ((index = _dictKeyIndex(d, key)) == -1)
        return NULL;

    /* Allocate the memory and store the new entry */
    // 如果正在rehash的话,直接返回ht[1]
    ht = dictIsRehashing(d) ? &d->ht[1] : &d->ht[0];
    entry = zmalloc(sizeof(*entry));
    entry->next = ht->table[index];// 头插法
    ht->table[index] = entry;   // 头插法
    ht->used++;                 // 元素数加一

    /* Set the hash entry fields. */
    dictSetKey(d, entry, key);
    return entry;
}

// 返回将来存储的索引位置
static int _dictKeyIndex(dict *d, const void *key)
{
    unsigned int h, idx, table;
    dictEntry *he;

    /* Expand the hash table if needed */
    if (_dictExpandIfNeeded(d) == DICT_ERR)
        return -1;
    /* Compute the key hash value */
    // 计算hash值
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        /* Search if this slot does not already contain the given key */
        he = d->ht[table].table[idx];
        while(he) {
            // 这一步防止同一链表中出现key值相同的情况,同一链表是hash值相同的key-val键值对
            if (dictCompareKeys(d, key, he->key))
                return -1;
            he = he->next;
        }
        // 没有正在进行rehash的话直接结束
        if (!dictIsRehashing(d)) break;
    }
    // 返回这个key对应的索引位置
    return idx;
}




// 在字典中查找key对应的dictEntry
// 返回NULL,说明没找到
dictEntry *dictFind(dict *d, const void *key)
{
    dictEntry *he;
    unsigned int h, idx, table;

    if (d->ht[0].size == 0) return NULL; /* We don't have a table at all */
    if (dictIsRehashing(d)) _dictRehashStep(d);
    // 计算hash值
    h = dictHashKey(d, key);
    for (table = 0; table <= 1; table++) {
        // 找到对应的索引值
        idx = h & d->ht[table].sizemask;
        // 找到对应的链表
        he = d->ht[table].table[idx];
        while(he) {
            // 遍历链表,并且比较每个元素的key,如果key值相等就返回这个dictEntry
            if (dictCompareKeys(d, key, he->key))
                return he;
            he = he->next;
        }
        // 如果没有在rehash直接返回
        if (!dictIsRehashing(d)) return NULL;
    }
    return NULL;
}


// 和dictAdd不同的是,如果原来的键值对不存在那么直接调用dictAdd插入
// 如果存在的话就替换他们
int dictReplace(dict *d, void *key, void *val)
{
    dictEntry *entry, auxentry;

    /* Try to add the element. If the key
     * does not exists dictAdd will suceed. */
    // 键值对原来就不存在,直接插入
    if (dictAdd(d, key, val) == DICT_OK)
        return 1;
    /* It already exists, get the entry */
    // 键值对存在
    entry = dictFind(d, key);
    /* Set the new value and free the old one. Note that it is important
     * to do that in this order, as the value may just be exactly the same
     * as the previous one. In this context, think to reference counting,
     * you want to increment (set), and then decrement (free), and not the
     * reverse. */
    auxentry = *entry; // 这里可以解引用是因为上面已经确定了键值对存在,那么返回值一定不是NULL
    dictSetVal(d, entry, val);      // 修改对应的value值
    dictFreeVal(d, &auxentry);      // 释放原来的
    return 0;
}


// 返回dictEntry中的key值
#define dictGetKey(he) ((he)->key)
// 返回dictEntry中的value值
#define dictGetVal(he) ((he)->v.val)


// 返回key对应的value值
void *dictFetchValue(dict *d, const void *key) {
    dictEntry *he;

    he = dictFind(d,key);
    return he ? dictGetVal(he) : NULL;
}


// 先看到这里,后面用到啥在补充

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值