zoukankan      html  css  js  c++  java
  • 《Redis设计与实现》阅读笔记(四)--字典

    字典

    字典,map,是用于保存键值对的抽象数据结构,是hash表实现。字典中的键唯一,通过键来操作值。Redis的数据库使用字典来作为底层实现。

    定义

    Redis的字典使用哈希表作为底层实现,一个哈希表里面由多个哈希表节点,哈希表节点保存着键值对。

    哈希表

    哈希表结构定义包含:哈希表数组,哈希表大小,哈希表掩码,哈希表已有节点数。

    1 typedef struct dictht {
    2     dicEntry **table;
    3     unsigned long size;
    4     unsigned long sizemask;
    5     unsigned long used;
    6 }dictht;

    table就是哈希表数组,每个元素就是一个哈希表节点的指针。

    size记录了哈希表的大小,也就是table的大小。

    sizemask是哈希表的掩码,用于计算索引值,值总是size-1。

    used就是哈希表已有节点数,注意与size进行区分哈希表大小并不等于节点数。

    哈希表节点

    哈希表节点结构包含:键,值,下一哈希表节点的指针(用于解决冲突)

    1 typedef struct dictEntry {
    2     void *key
    3     union {
    4         void *val
    5         uint64_t u64;
    6         int64_t s64;
    7     } v;
    8     struct dictEntry *next;
    9 } dictEntry;

    next指针将哈希值相同的键值对连接在一起,形成链表,解决冲突。

    字典

    字典包含:一个大小为2的哈希表数组(方便rehash),rehash索引,特定类型的函数,复制键的函数。

    1 typedef struct dict {
    2     dictType *type;
    3     void *privdata;
    4     dictht ht[2];
    5     int trehashidx;
    6 } dict;

    type 和privdata的作用具体并不清楚,书上介绍“针对不同类型的键值对,为创建多态字典而设置”。

    ht即hashtable平时的哈希表节点在ht[0],rehash的时候用到ht[1]。

    哈希方式

    插入键值对时,先根据键计算出哈希值。再根据哈希值和哈希表的掩码计算出应放在哈希表的哪个索引上。哈希函数为Murmurhash算法,然而并不知道具体是怎么个实现,给自己挖个坑,有空学习下。

    hash = dict->type->hashFunction(key);
    index = hash & dict->ht[x].sizemask;(x为0或1,取决于实际情况)

    提到哈希肯定要考虑冲突的解决方法。在上面的哈希表节点中就已经看到,在这里使用链地址法解决冲突。

    单向链表而且没有记录尾节点,所以插入链表时使用头插入。如果插入到末尾的话还需要遍历到链表末尾,消耗时间。

    rehash

    负载因子 = 哈希表已保存的节点数量/哈希表大小

    很显然负载因子大说明哈希表太小,为了避免冲突就要增大。而负载因子太小说明哈希表过大,浪费了空间。

    我们要对哈希表进行扩展或者收缩。这个工作通过rehash来完成。

    1. 为ht[1]分配空间。
    2. 将ht[0]的键值对rehash到ht[1]
    3. 当ht[0]全部迁移到ht[1],释放ht[0],让ht[1]成为新ht[0]

    从上面的过程中我们发现有三个问题:

    • 在什么情况下我们需要对哈希表进行扩展或收缩?
    • 新空间分配策略是怎样的?
    • rehash迁移的过程如何完成?

    第一个问题:if 负载因子大于1且没有执行BGSAVE,BGREEWRITEAOF 或者 负载因子大于5 (具体为啥这么定我也不知道。。。第二个坑)

            执行扩展

          else if 负载因子小于0.1

            执行收缩      

    第二个问题:扩展的大小为:大于等于(ht[0].used*2)的最小2的整数幂

          缩小的大小为:大于等于(ht[0].used)的最小2的整数幂

    第三个问题:渐进式rehash

    rehash的过程为了不堵住服务,将分成几次完成。

    1. 为ht[1]分配空间,将rehashidx设为0(不进行rehash的时候值为-1)
    2. 每次对字典进行增删查改,程序将同时将rehashidx索引上的所有键值对rehash到ht[1] ,完成后rehashidx加一。
    3. 当ht[0]上的所有键值对全部完成rehash,将rehashidx设为-1。rehash完成

    在rehash过程中,字典的删查改将在两个hashtable上进行,而增加操作只会在ht[1]进行。

  • 相关阅读:
    Rational工具介绍(转)
    MySQL表的存储引擎
    2009 年度最佳 jQuery 插件
    09年关门歇业的15大网站 雅虎旗下4网站上榜
    [转载]windows2003上IIS+PyISAPIe1.1..0部署成功
    安装IronPythonStudio出错:已解决
    C# 开源项目
    Cassandra在windows平台下安装布署,对No SQL感兴趣的朋友可以进来看看
    【转载】开发人员用的一些好网站
    [转载]用来武装Firebug的十三款Firefox插件
  • 原文地址:https://www.cnblogs.com/Star-Dust-/p/10347117.html
Copyright © 2011-2022 走看看