redis中字典结构的源码
哈希节点
typedef struct dictEntry { 
    void *key; 
    union {//v可以是不同类型的,
        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;//表大小
    //用来跟计算出的哈希值与求出存放索引,大小为size-1,因为size是2的倍数,所以&计算相当于对size求模
    unsigned long sizemask;
    unsigned long used;//节点个数
} dictht;
//字典,map
typedef struct dict {
    dictType *type; //对应类型,使用他来调用对应的函数
    void *privdata; //私有数据????
    dictht ht[2];//两个哈希表,使用两个表来实现重新散列
    //当rehashidx不为-1时,表示整在重新散列
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;
哈希算法使用MurmurHash2
解决哈希冲突,使用链式地址法,每个节点都有个next指针,相同哈希值的节点依次链接起来; 负载因子=已有节点数量/表大小
渐进式rehash
- 为ht[1]分配空间
- 持有rehashidx,当开始rehash时,该值不为-1,然后每次对字典执行一次操作时,会将rehashidx索引上的所有节点rehash到ht[1]上,当全部完成后,rehashidx=0;
- 释放ht[0],将ht[1]设置为ht[0],并为ht[1]新创建一个空白的哈希表;
执行的条件
- 在没有执行BGSAVE和BGREWRITEAOF时,如果负载因子大于等于1,执行rehash
- 在执行BDGSAVE和BGREWRITEAOF时,如果负载因子大于等于5,执行rehash
另外:在执行rehash操作时,查找是先在ht[0]中查找,没有再去ht[1]中找;新添加的节点直接存在ht[1]中;
