• Redis设计与实现(3)字典


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

    redis字典所使用的哈希表由dict.h/dictht

    1. typedef struct dictht{
    2. //哈希表数组
    3. dictEntry **table;
    4. //哈希表大小
    5. unsigned long size;
    6. //哈希表大小掩码,用于计算索引值
    7. //总是等于size-1
    8. unsigned long sizemask;
    9. //该哈希表已有节点的数量
    10. unsigned long used;
    11. }dictht;

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

    size 属性记录了哈希表的大小, 也即是 table 数组的大小, 而 used 属性则记录了哈希表目前已有节点(键值对)的数量。

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

    哈希表节点
     

    1. typedef struct dictEntry {
    2. //
    3. void *key;
    4. //
    5. union {
    6. void *val;
    7. uint64_t u64;
    8. int64_t s64;
    9. } v;
    10. // 指向下个哈希表节点,形成链表
    11. struct dictEntry *next;
    12. } dictEntry;

    key 属性保存着键值对中的键, 而 v 属性则保存着键值对中的值, 其中键值对的值可以是一个指针, 或者是一个 uint64_t 整数, 又或者是一个 int64_t 整数。

    next 属性是指向另一个哈希表节点的指针, 这个指针可以将多个哈希值相同的键值对连接在一次, 以此来解决键冲突(collision)的问题。

    举个例子, 图 4-2 就展示了如何通过 next 指针, 将两个索引值相同的键 k1 和 k0 连接在一起。

    字典

    1. typedef struct dict {
    2. // 类型特定函数
    3. dictType *type;
    4. // 私有数据
    5. void *privdata;
    6. // 哈希表
    7. dictht ht[2];
    8. // rehash 索引
    9. // 当 rehash 不在进行时,值为 -1
    10. int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    11. } dict;

    type 属性和 privdata 属性是针对不同类型的键值对, 为创建多态字典而设置的:

    • type 属性是一个指向 dictType 结构的指针, 每个 dictType 结构保存了一簇用于操作特定类型键值对的函数, Redis 会为用途不同的字典设置不同的类型特定函数。
    • 而 privdata 属性则保存了需要传给那些类型特定函数的可选参数。
      1. typedef struct dictType {
      2. // 计算哈希值的函数
      3. unsigned int (*hashFunction)(const void *key);
      4. // 复制键的函数
      5. void *(*keyDup)(void *privdata, const void *key);
      6. // 复制值的函数
      7. void *(*valDup)(void *privdata, const void *obj);
      8. // 对比键的函数
      9. int (*keyCompare)(void *privdata, const void *key1, const void *key2);
      10. // 销毁键的函数
      11. void (*keyDestructor)(void *privdata, void *key);
      12. // 销毁值的函数
      13. void (*valDestructor)(void *privdata, void *obj);
      14. } dictType;

      ht 属性是一个包含两个项的数组, 数组中的每个项都是一个 dictht 哈希表, 一般情况下, 字典只使用 ht[0] 哈希表, ht[1] 哈希表只会在对 ht[0] 哈希表进行 rehash 时使用。

      除了 ht[1] 之外, 另一个和 rehash 有关的属性就是 rehashidx : 它记录了 rehash 目前的进度, 如果目前没有在进行 rehash , 那么它的值为 -1 。

     解决键冲突

    采用的是链地址法

    举个例子, 假设程序要将键值对 k2 和 v2 添加到下图 所示的哈希表里面, 并且计算得出 k2 的索引值为 2 , 那么键 k1 和 k2 将产生冲突, 而解决冲突的办法就是使用 next 指针将键 k2 和 k1 所在的节点连接起来, 如图 下下图所示。

     

  • 相关阅读:
    牛客刷题<11>4位数值比较器电路
    SQL:WHERE子句,LIKE,BETWEEN
    Spring之AOP
    MYSQL高级(二)---索引
    ESP32 AT指令模式连接百度云天工物接入
    FastASR——PaddleSpeech的C++实现
    H41H-40C法兰止回阀型号解析
    c++ 函数重载
    数据治理-数据仓库环境
    java计算机毕业设计ssm+jsp计算机视频学习网站
  • 原文地址:https://blog.csdn.net/qq_62773260/article/details/133966700