一图清晰了解redis内核dict实现原理

                                                                                                               

                                                                                                      凡是总须研究,才会明白。------鲁迅

 

 

    redis数据库底层通过多个数据结构,最终实现了其对外服务的强大功能,其中dict是基础而核心的功能。dict通过哈希表模式,并结合链表实现了键值存储功能。我们在redis命令行界面,很清晰可以看到自己存储的键值数据:

127.0.0.1:6379> set book learn redis
(error) ERR syntax error
127.0.0.1:6379> set book "learn redis"
OK
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379>
127.0.0.1:6379> get book
"learn redis"

    可以看到,book就是我们设置的键,“learn redis”就是我们设置的值。

 

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;


typedef struct dictht {
    dictEntry **table;
    PORT_ULONG size;
    PORT_ULONG sizemask;
    PORT_ULONG used;
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    PORT_LONG rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running */
} dict;






一、结构体成员解析:    

我们观看本文开始图片及结合redis dict源码:

dict结构体:

    type是一个指向dictType结构体的指针,该结构体中声明了多个函数。(该结构体不再详述)

    privdata则是指定一个私有数据,它通过和type结合,可以为多类型的数据服务。

    ht[2],这是一个类型为dictht的数组,通常情况下ht[1]为空,不使用,所有数据存放在ht[0]中。

    rehashidx,代表是否在进行重构hash表

    iterators,记录多少在用的迭代器。

 

dictht结构体:

    table是一个指向dictEntry结构体指针的指针,也可以理解为指向含有多个dictEntry结构体指针的数组的指针。

    size:指明hash表大小。

    sizemask:代表哈希表大小掩码,总是等于size-1;

    used:代表已有节点数量。

 

dictEntry结构体:

    key:用来存放键值

    v:用了一个union结构,一来可以节省空间,二来其中多个变量类型使得可以存储多种类型。

    next:用来指向下一个dictEntry节点的指针(当通过hash算法算出两个键的索引值一样时候,将存放在链表中)。

 

二、重点解析

1,dict结构体中rehashidx值不等于-1时,代表hash表在进行重构(键值哈希值冲突过多)。rehash过程中,ht[1]将被启用:

    如果是进行扩展,ht[1]的大小为第一个大于等于ht[0].used*2的2的n次方幂。

    如果是进行收缩,ht[1]的大小为第一个大于等于ht[0].used的2的n次方幂。

2,dict扩展的因子由参数dict_force_resize_ratio决定,它的值为5,代表当used的值/size的值大于5时,将进行扩展操作。

3,hash表进行rehash过程中,使用的渐进式的流程,慢慢将ht[0]中的数据通过重新计算hash值写入到ht[0]中,该过程中,新加的数据将只在ht[1]中进行,读取将在ht[0]和ht[1]中进行。等待rehash过程完成,ht[0]将置空,ht[1]将变为ht[0]。

4,redis哈算算法使用了MurmurHash2(by Austin Appleby),算法如下:

unsigned int dictGenHashFunction(const void *key, int len) {
    /* 'm' and 'r' are mixing constants generated offline.
     They're not really 'magic', they just happen to work well.  */
    uint32_t seed = dict_hash_function_seed;
    const uint32_t m = 0x5bd1e995;
    const int r = 24;

    /* Initialize the hash to a 'random' value */
    uint32_t h = seed ^ len;

    /* Mix 4 bytes at a time into the hash */
    const unsigned char *data = (const unsigned char *)key;

    while(len >= 4) {
        uint32_t k = *(uint32_t*)data;

        k *= m;
        k ^= k >> r;
        k *= m;

        h *= m;
        h ^= k;

        data += 4;
        len -= 4;
    }

    /* Handle the last few bytes of the input array  */
    switch(len) {
    case 3: h ^= data[2] << 16;
    case 2: h ^= data[1] << 8;
    case 1: h ^= data[0]; h *= m;
    };

    /* Do a few final mixes of the hash to ensure the last few
     * bytes are well-incorporated. */
    h ^= h >> 13;
    h *= m;
    h ^= h >> 15;

    return (unsigned int)h;
}

 

 

                                                                           喜欢的朋友可以扫描以下二维码进行关注,公众号将经常更新文章:

                                                                                                                       

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值