Redis数据结构_1.字典

redis字典使用哈希表作为底层实现,一个哈希表里面可以有多个哈希表节点,而每个哈希表节点就保存了字典中的一个键值对

哈希表

哈希表的结构

typedef struct dictht {

    //哈希表数组
    dictEntry **table;

    //哈希表大小
    unsigned long size;

    //哈希表大小掩码,用于计算索引值,总等于size-1
    unsigned long sizemask;

    //哈希表以有节点的数量
    unsigned long used;
}dictht;

table属性是一个数组,数组中的每一个元素都是一个指向dictEntry的指针,每个dictEntry都保存着一个键值对

size属性记录了哈希表的大小,也就是table数组的大小

sizemask属性的值总等于size-1,这个属性和key的哈希值一起决定一个键将被放到table数组的哪一个索引上

used属性记录了哈希表中已有的节点数量

哈希表节点的结构

typedef struct dictEntry {
    
    //键
    void *key;

    //值
    union {
        void *val;
        uint_64tu64;
        int_64ts64;
    }v;

    //指向下一个哈希表节点形成链表
    struct dictEntry *next;
}dictEntry;

key属性记录了键值对的键值

v属性记录键值对的值,可以是一个指针,一个uint64的整数或者int64的整数

next指向另一个哈希表节点的指针,以此来形成链表解决键哈希冲突的问题

字典

字典的结构

typedef struct dict {
    
    //类型特定函数
    dictType *type;
    
    //私有数据
    void *privdata;
    
    //哈希表
    dictht ht[2];
    
    //rehash索引,当rehash不在进行时值为-1
    int rehashidx;
}dict;

type和privdata属性是针对不同类型的键值对,为创建多态字典而设置的,type是一个指向dictType的指针,每个dictType结构保存了一个用于操作特定类型键值对的函数
而privdata属性则保存了需要传给那些特定类型函数的参数

typedef struct dictType {
    
    //计算哈希值的函数
    unsigned int (*hashFunction)(const void *key);
    
    //复制键的函数
    void *(*keyDup)(void privdata,const void *key);
    
    //复制值的函数
    void *(*valDup)(void privdata,const void *obj);
    
    //对比键的函数
    int (*keyCompare)(void privdata,const void *key1,const void *key2);

    //销毁键的函数
    void (*keyDestructor)(void privdata,const void *key);

    //销毁值的函数
    void (*valDestructor)(void privdata,const void *obj);
}dictType;

ht属性是一个包含两个项的数组,数组中的每个项都是一个dictht哈希表,一般情况下,字典只使用ht[0]哈希表,ht[1]哈希表只会在对ht[0]进行rehash时使用。
rehashidx属性记录了目前rehash的进度,如果目前没有进行rehash,那么她的值为-1。

哈希算法

redis计算哈希值和索引值的方法如下:

hash = dict->type->hashFunction(key);

根据情况不同,ht[x]可以是ht[0]或者ht[1]

index = hash & dict->ht[x].sizemask;

哈希冲突

当两个或两个以上的键被分配到哈希数组的同一个索引上面时,这些键就发生了冲突。
redis使用链地址法来解决冲突,程序总是将新节点添加到表头的位置

rehash

为了让哈希表的负载因子维持在一个合理的范围内,当哈希表的节点数太多或者太少时,程序将对哈希表进行扩展和收缩

当哈希表的负载因子小于0.1时程序会对哈希表进行收缩操作

负载因子 = 哈希表已保存的节点数量 / 哈希表大小
load_factor = ht[0].use / ht[0].size

当hash表满足一下条件的任意一个时,程序会自动对哈希表进行扩展操作:

  • 服务器目前没有在执行BGSAVE命令或者是BGREWRITEAOF命令,并且哈希表负载因子大于等于1
  • 哈希表负载因子大于等于5

渐进式rehash

rehash的动作不是一次性、集中式的完成的,因为当hash表很大时,一次性的rehash可能会让服务器停止工作一段时间,所以rehash是分多次、渐进式的将ht[0]上的数据rehash到ht[1]上的。
在此期间字典的删除、查找、更新等操作会在两个哈希表上进行,另外新的键值会被保存到ht[1]上,而ht[0]不会在进行任何添加操作,保证ht[0]上的数据只会减少不会增加

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值