redis中的数据结构—字典

Posted by CHuiL on March 18, 2019

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]新创建一个空白的哈希表;

执行的条件

  • 在没有执行BGSAVEBGREWRITEAOF时,如果负载因子大于等于1,执行rehash
  • 在执行BDGSAVE和BGREWRITEAOF时,如果负载因子大于等于5,执行rehash

另外:在执行rehash操作时,查找是先在ht[0]中查找,没有再去ht[1]中找;新添加的节点直接存在ht[1]中;