• [redis读书笔记] 第一部分 数据结构与对象 字典


    三 字典

      字典是Hash对象的底层实现,比如用HSET创建一个HASH的对象,底层可能就是用一个字典实现的键值对。

        字典的实现主要设计下面三个结构:

    /*
     * 哈希表节点
     */
    typedef struct dictEntry {
        
        //
        void *key;
    
        //
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
        } v;
    
        // 指向下个哈希表节点,形成链表
        struct dictEntry *next;
    
    } dictEntry;    
    
    /*
     * 哈希表
     *
     * 每个字典都使用两个哈希表,从而实现渐进式 rehash 。
     */
    typedef struct dictht {
        
        // 哈希表数组
        // [JZ]: 即二维数组/链表
        dictEntry **table;
    
        // 哈希表大小
        unsigned long size;
        
        // 哈希表大小掩码,用于计算索引值
        // 总是等于 size - 1
        unsigned long sizemask;
    
        // 该哈希表已有节点的数量
        unsigned long used;
    
    } dictht;
    
    /*
     * 字典类型特定函数
     */
    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 dict { // 类型特定函数 dictType *type; // 私有数据 void *privdata; // 哈希表 dictht ht[2]; // rehash 索引 // 当 rehash 不在进行时,值为 -1 int rehashidx; /* rehashing not in progress if rehashidx == -1 */ // 目前正在运行的安全迭代器的数量 int iterators; /* number of iterators currently running */ } dict;

    他们之间的关系如下图:

     - dict.type里会注册回调函数,用来实现计算哈希值(hashFunction(),redis使用MurmurHash2算法来计算哈希值(dictEncObjHash))等等功能,用dict.sizemask计算索引值,即dictentry[i]的下标值

     - 键冲突:不同的键分配到同一个索引,就在这个dictentry[i]上构成单向链表

     - rehash:哈希表有一个负载因子的概念,load_factor=ht[0].used/ht[0].size,当这个值大于等于1(或者满足以下条件),会进行rehash,也代表了保存的键值过多,进行重新的散列操作,从ht[0]转移所有的hashNode到ht[1]。

                     rehash过程中,dict.rehashidx用来标明是否在rehash(-1为非rehash),每做一个就加1,最终全部做完后,置为-1,然后将ht[1]的所有entry拷贝回ht[0],这样不需要一次性完成所有node的rehash,避免了rehash时的庞大而集中的计算量。

                     rehash过程中,如果有对字典的删除,查找和更新操作,可能会对ht[0]和ht[1]都进行操作,比如查找会先到ht[0]找,找不到会到ht[1]找,如果新建,则会保存到ht[1],ht[0]不做新增,保证ht[0]里的键值对只减不增,并随着rehash最终成为空表

  • 相关阅读:
    吴裕雄--天生自然ANDROID开发学习:2.4.1 ScrollView(滚动条)
    吴裕雄--天生自然ANDROID开发学习:2.3.9 RatingBar(星级评分条)
    吴裕雄--天生自然ANDROID开发学习:2.3.8 SeekBar(拖动条)
    吴裕雄--天生自然ANDROID开发学习:2.3.7 ProgressBar(进度条)
    吴裕雄--天生自然ANDROID开发学习:2.3.6 开关按钮ToggleButton和开关Switch
    吴裕雄--天生自然ANDROID开发学习:2.3.5.RadioButton(单选按钮)&Checkbox(复选框)
    吴裕雄--天生自然ANDROID开发学习:2.3.4 ImageView(图像视图)
    吴裕雄--天生自然ANDROID开发学习:2.3.3 Button(按钮)与ImageButton(图像按钮)
    吴裕雄--天生自然ANDROID开发学习:2.3.2 EditText(输入框)详解
    吴裕雄--天生自然ANDROID开发学习:2.3.1 TextView(文本框)详解
  • 原文地址:https://www.cnblogs.com/jiangz222/p/6423057.html
Copyright © 2020-2023  润新知