zoukankan      html  css  js  c++  java
  • [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最终成为空表

  • 相关阅读:
    delphi 遇到Line too long(more than 1023 characters问题,将原有代码分离出过程来调用,调用使用 过程名字(self) 调用
    sql 从房间号中或从含有几个"-"间隔的字符串中,截取楼层数,或截取第几个"-"后的前几个字符或数字
    delphi mac地址 网卡地址获取,如果有无线网卡连接情况,mac地址随机获取某个本地连接网卡地址,要都写进去判断
    delphi 输入年月判断天数,判断指定年份与月份判断当月有多少天
    在SQL SERVER中查询数据库中第几条至第几条之间的数据SQL语句写法
    手动修改PHP页面返回状态码
    PHPExcel 导出包含图片excel
    windows apache启动报错
    mysql正则查询 模糊查询
    symfony安装总结
  • 原文地址:https://www.cnblogs.com/jiangz222/p/6423057.html
Copyright © 2011-2022 走看看