当前位置: 首页 > article >正文

Redis hash表源码解析

 整体数据结构:链式hash解决hash冲突、采用渐进式hash来完成扩容过程。

/*
 * 哈希表节点
 */
typedef struct dictEntry {
    
    // 键
    void *key;

    // 值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;

    // 指向下个哈希表节点,形成链表
    struct dictEntry *next;

} dictEntry;


/*
 * 字典类型特定函数
 */
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;


/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
/*
 * 哈希表
 *
 * 每个字典都使用两个哈希表,从而实现渐进式 rehash 。
 */
typedef struct dictht {
    
    // 哈希表数组
    dictEntry **table;

    // 哈希表大小
    unsigned long size;
    
    // 哈希表大小掩码,用于计算索引值
    // 总是等于 size - 1
    unsigned long sizemask;

    // 该哈希表已有节点的数量
    unsigned long used;

} dictht;

/*
 * 字典
 */
typedef struct dict {

    // 类型特定函数
    dictType *type;

    // 私有数据
    void *privdata;

    // 哈希表:两个Hash表,里面存储的是键值对,交替使用,用于rehash操作
    dictht ht[2];

    // rehash 索引
    // 当 rehash 不在进行时,值为 -1
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */

    // 目前正在运行的安全迭代器的数量
    int iterators; /* number of iterators currently running */

} dict;

 2、扩容函数 static int _dictExpandIfNeeded(dict *d)

触发该函数的三个操作:添加修改场景下会触发。

dictAdd:用来往 Hash 表中添加一个键值对。 

dictRelace:用来往 Hash 表中添加一个键值对,或者键值对存在时,修改键值对。

dictAddorFind:间接调用 dictAddRaw。_dictExpandIfNeeded->_dictKeyIndex->dictAddRaw

 static int _dictExpandIfNeeded(dict *d) 里面的代码片段截取
    //扩容两个条件
    // 1)字典已使用节点数趋近用完,并且没有开启aof和rdb两个操作
    // 2)Hash表承载的元素个数已是当前大小的5倍
    if (d->ht[0].used >= d->ht[0].size &&
        (dict_can_resize ||
         d->ht[0].used/d->ht[0].size > dict_force_resize_ratio))
    {
        // 新哈希表的大小至少是目前已使用节点数的两倍
        // T = O(N)
        return dictExpand(d, d->ht[0].used*2);
    }

//以下代码可以发现,但凡开启rdb和aof两个操作,必定禁止rehash。
void dictEnableResize(void) {
    dict_can_resize = 1;
}
 
void dictDisableResize(void) {
    dict_can_resize = 0;
}

void updateDictResizePolicy(void) {
    if (server.rdb_child_pid == -1 && server.aof_child_pid == -1)
        dictEnableResize();
    else
        dictDisableResize();
}

http://www.kler.cn/a/154662.html

相关文章:

  • Python酷库之旅-第三方库Pandas(218)
  • C++map和set(二)
  • 嵌入式硬件电子电路设计(五)MOS管详解(NMOS、PMOS、三极管跟mos管的区别)
  • 【包教包会】CocosCreator3.x框架——带翻页特效的场景切换
  • c#————委托Action使用例子
  • 创建vue插件,发布npm
  • 物联网开发(一)新版Onenet 基础配置
  • Hdoop学习笔记(HDP)-Part.16 安装HBase
  • C++11 类的新功能
  • 实验8 图的操作
  • LangChain(0.0.339)官方文档四:Prompts下——prompt templates的存储、加载、组合和部分格式化
  • 肖sir__mysql之单表练习题2__(2)
  • 吉利展厅 | 透明OLED拼接2x2:科技与艺术的完美融合
  • 西南科技大学模拟电子技术实验四(集成运算放大器的线性应用)预习报告
  • Java Web——动态Web开发核心-Servlet
  • TA-Lib学习研究笔记(八)——Momentum Indicators 中
  • TLS、对称/非对称加密、CA认证
  • Zabbix HA高可用集群搭建
  • Node.js 事件循环:定时任务、延迟任务和 I/O 事件的艺术
  • 编程实战:类C语法的编译型脚本解释器(五)
  • HarmonyOS——解决本地模拟器无法选择设备的问题
  • 编程实战:类C语法的编译型脚本解释器(三)
  • 2312skia,15vulkan及技巧
  • Go语言实现深度学习的正向传播和反向传播
  • 深入理解Servlet(上)
  • 深度学习记录--计算图(前向后向传播)