# 结构

dict

# 用处

  • 数据库
  • 哈希键
  • 其他

# 定义

typedef struct dict {
    // 类型特定函数
    dictType *type;
    // 私有数据,保存了需要传给那些类型特定函数的可选参数
    void *privdata;
    // 哈希表
    dictht ht[2];
    //rehash 索引,当 rehash 不在进行时,值为 -1
    int rehashidx;
} dict;
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, void *key);
    // 销毁值的函数
    void (*valDestructor)(void *privdata, void *obj);
} dictType;
typedef struct dictht {
    // 哈希数组
    dictEntry **table;
    // 哈希表大小
    unsigned long size;
    // 哈希表大小掩码,用于计算索引值,等于 size - 1
    unsigned long sizemask;
    // 哈希表已有节点数量
    unsigned logn used;
} dictht;
typedef struct dictEntry {
    // 键
    void *key;
    // 值
    union {
        void *val;
        uint64_tu64;
        int64_ts64;
    } v;
    // 下一个节点
    struct dictEntry *next;
} dictEntry;

# rehash

步骤:

  1. 为 ht [1] 分配空间
    • 如果是扩展操作,大小扩为第一个不小于 h [0].used*2 的 2 的倍数
    • 如果是收缩操作,大小为第一个不小于 h [0].used 的 2 的倍数
  2. 移动 ht [0] 的数据到 ht [1]
  3. 释放 ht [0],将 ht [1] 变为 ht [0],并为 h [1] 新建一个空白哈希表

扩展条件:

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

收缩条件:

  • 哈希表的负载因子小于 0.1

# 渐进式 rehash

rehash 的步骤 2 不是一次性完成,是分多次、渐进式的完成的,为了防止哈希表中数据太多影响性能。

步骤:

  1. 为 ht [1] 分配空间
  2. rehashidx 设为 0
  3. rehash 期间,每次对字典执行添加、删除、查找、更新操作时,还要将 ht [0].table [rehashidx] 上的数据移动到 ht [1],并将 rehashidx 加 1,添加操作要添加到 ht [1] 中,保证 ht [0] 上的数据只减不增
  4. 当完成所有数据的移动后,将 rehashidx 设为 -1