redis数据结构之字典

字典就相当于一个hashmap,了解字典需要从下面几个问题开始

1.字典的结构
2. 字典的扩容的机制
3. 扩容时的请求处理
4. 字典是怎么添加值的

字典的结构
typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

typedef struct dictType {
    uint64_t (*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, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

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

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];  //之所以有两个dictht是为了rehash
    long rehashidx; //表示当前rehash的位置,-1表示当前没有进行rehash
    unsigned long iterators; /* number of iterators currently running */
} dict;

看上面结构可以知道字典和hashMap结构很相似,其中dictEntry 就对应着一个key-value, dictht 中的**table就是一个dictEntry 数组的引用。dictht有一个used表示当前dictht中key-value对的个数。另外
dict有两个dictht ,dictht[0], dictht[1],正常情况下只会用到dictht[0],rehash时才会用到dictht[1]. 字典是开链法解决键值冲突。

字典的扩容的机制

1、字典的什么时候进行扩宽?
当负载因子等于 1的时候,如果没在执行BGSAVE和BGREWRITEAOP时,就会进行扩容。如果在 在执行BGSAVE和BGREWRITEAOP,当负载因子达到5时,也会进行扩容。
另外说下一,当负载因子等于0.1时会进行收缩

2、字典扩容后的size
字典是2倍扩容,如果扩容后的大小min(2*size,DICT_HT_INITIAL_SIZE),即扩容后至少为DICT_HT_INITIAL_SIZE,DICT_HT_INITIAL_SIZE等于4是字典初始化默认大小

3、扩容大概流程

  • 扩容时dictht[1].size = min(2*dictht[0].size,DICT_HT_INITIAL_SIZE)为dictht[1]分配空间
  • dictht[0]的数据迁移到dictht[1]
  • 迁移完成后dictht[0]=dictht[1], dictht[1]=null

4、渐进式扩容
dictht[0]的数据迁移到dictht[1]这个过程不是一次完成的,而是分为多次,渐进式的完成的。其中有一个rehashidx表示当前字典正在迁移的位置table[rehashidx]之前的都已经迁移完成了

5、扩容后链表的顺序问题
字典扩容rehash过程是把值加到链表的头部,所以会是的中值的顺序和原来的不一样。

扩容时的请求处理

当前进行rehash扩容时,维持着两个dictht。请求操作分为读和写。写的操作都在dictht[1]上执行。
读操作会先读dictht[0],再读dictht[1]。

字典添加值过程

1、判断是否正在执行rehash过程,如果是则对dictht[1]操作,否则对dictht[0]操作
2、先通过hash找到在table中 对应的位置
3、如果对应的位置位null,则直接放入
4、否则遍历链表,如果没有在链表里面,则放到链表的最开头位置。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值