• 1.字典相关的几个结构体
 dict由hash table存储key-value, hash table数组每一个元素存放dictEntry链接的链表头结点,dictEntry节点存放key-value
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry; typedef struct dictht {
dictEntry **table; // 指向dictEntry数组的指针
unsigned long size; //哈希表table的大小,初始化大小为4
unsigned long sizemask; // size - 1 ,用来对hash值求与计算获得index
unsigned long used; // 已经赋值了的数量
} dictht; typedef struct dict {
dictType *type; // 方法
void *privdata; // 保存key和value
dictht ht[]; // hash table
long rehashidx; // 如果rehashidx=-1表示没有进行rehash,如果如果rehashidx>-1,则表示正在进行rehash,搬运的位置是rehashidx
int iterators; /* number of iterators currently running */
} dict;
  • 2.动态扩容方法 int dictRehash(dict *d, int n)

   为了对dictht进行动态扩容,rehash方法将ht[0]中的值搬n个到ht[1]中, 分批次进行搬运,直到ht[0]中的值都搬到ht[1]上,再将ht[1]指针交给ht[0],rehashidx=-1,完成此次rehash过程

int dictRehash(dict *d, int n) {
int empty_visits = n * ; /* Max number of empty buckets to visit. */
if (!dictIsRehashing(d)) return ; // 从ht[0]中搬n个链表到ht[1]中
while (n-- && d->ht[].used != ) {
dictEntry *de, *nextde; /* Note that rehashidx can't overflow as we are sure there are more
* elements because ht[0].used != 0 */
assert(d->ht[].size > (unsigned long) d->rehashidx);
// 通过rehashidx可以接着从上一次搬完的位置开始搬
while (d->ht[].table[d->rehashidx] == NULL) {
d->rehashidx++;
if (--empty_visits == ) return ;
}
de = d->ht[].table[d->rehashidx];
/* Move all the keys in this bucket from the old to the new hash HT */ // 把ht[0]上的一个链表搬到ht[1]上
while (de) {
unsigned int h; nextde = de->next;
/* Get the index in the new hash table */
h = dictHashKey(d, de->key) & d->ht[].sizemask;
de->next = d->ht[].table[h];
d->ht[].table[h] = de;
d->ht[].used--;
d->ht[].used++;
de = nextde;
}
d->ht[].table[d->rehashidx] = NULL;
d->rehashidx++;
} /* Check if we already rehashed the whole table... */
if (d->ht[].used == ) {
zfree(d->ht[].table);
d->ht[] = d->ht[];
_dictReset(&d->ht[]);
d->rehashidx = -;
return ;
} /* More to rehash... */
return ;
}
  • 3.使用到的几个hash算法

    1. 针对int的hash函数

       unsigned int dictIntHashFunction(unsigned int key) {
      key += ~(key << );
      key ^= (key >> );
      key += (key << );
      key ^= (key >> );
      key += ~(key << );
      key ^= (key >> );
      return key;
      }
    2. MurmurHash2算法

        unsigned int dictGenHashFunction(const void *key, int len) {
      /* 'm' and 'r' are mixing constants generated offline.
      They're not really 'magic', they just happen to work well. */
      uint32_t seed = dict_hash_function_seed;
      const uint32_t m = 0x5bd1e995;
      const int r = ; /* Initialize the hash to a 'random' value */
      uint32_t h = seed ^len; /* Mix 4 bytes at a time into the hash */
      const unsigned char *data = (const unsigned char *) key; // 长度大于等于4的情况
      while (len >= ) {
      uint32_t k = *(uint32_t *) data; // 4*8=32, 取4个字节当作uint32 k *= m;
      k ^= k >> r;
      k *= m; h *= m;
      h ^= k; data += ;
      len -= ;
      } /* Handle the last few bytes of the input array */
      // 剩下的长度小于4
      switch (len) {
      case :
      h ^= data[] << ;
      case :
      h ^= data[] << ;
      case :
      h ^= data[];
      h *= m;
      }; /* Do a few final mixes of the hash to ensure the last few
      * bytes are well-incorporated. */
      h ^= h >> ;
      h *= m;
      h ^= h >> ; return (unsigned int) h;
      }
    3. djb hash算法
  unsigned int dictGenCaseHashFunction(const unsigned char *buf, int len) {

      unsigned int hash = (unsigned int) dict_hash_function_seed;
while (len--)
hash = ((hash << ) + hash) + (tolower(*buf++)); /* hash * 33 + c */
return hash;
}   


细节前往

    (https://github.com/fangwendong/redis-learning/tree/master/struct/dict)
 

redis源码学习-dict的更多相关文章

  1. Redis源码学习:字符串

    Redis源码学习:字符串 1.初识SDS 1.1 SDS定义 Redis定义了一个叫做sdshdr(SDS or simple dynamic string)的数据结构.SDS不仅用于 保存字符串, ...

  2. Redis源码学习:Lua脚本

    Redis源码学习:Lua脚本 1.Sublime Text配置 我是在Win7下,用Sublime Text + Cygwin开发的,配置方法请参考<Sublime Text 3下C/C++开 ...

  3. redis源码学习之slowlog

    目录 背景 环境说明 redis执行命令流程 记录slowlog源码分析 制造一条slowlog slowlog分析 1.slowlog如何开启 2.slowlog数量限制 3.slowlog中的耗时 ...

  4. 柔性数组(Redis源码学习)

    柔性数组(Redis源码学习) 1. 问题背景 在阅读Redis源码中的字符串有如下结构,在sizeof(struct sdshdr)得到结果为8,在后续内存申请和计算中也用到.其实在工作中有遇到过这 ...

  5. __sync_fetch_and_add函数(Redis源码学习)

    __sync_fetch_and_add函数(Redis源码学习) 在学习redis-3.0源码中的sds文件时,看到里面有如下的C代码,之前从未接触过,所以为了全面学习redis源码,追根溯源,学习 ...

  6. redis源码学习之工作流程初探

    目录 背景 环境准备 下载redis源码 下载Visual Studio Visual Studio打开redis源码 启动过程分析 调用关系图 事件循环分析 工作模型 代码分析 动画演示 网络模块 ...

  7. redis源码学习之lua执行原理

    聊聊redis执行lua原理 从一次面试场景说起   "看你简历上写的精通redis" "额,还可以啦" "那你说说redis执行lua脚本的原理&q ...

  8. redis源码之dict

    大家都知道redis默认是16个db,但是这些db底层的设计结构是什么样的呢? 我们来简单的看一下源码,重要的字段都有所注释 typedef struct redisDb { dict *dict; ...

  9. Redis源码学习-Master&Slave的命令交互

    0. 写在前面 Version Redis2.2.2 Redis中可以支持主从结构,本文主要从master和slave的心跳机制出发(PING),分析redis的命令行交互. 在Redis中,serv ...

随机推荐

  1. GetWindowRect

    示例代码: CRect rect; GetDlgItem(IDC_STATIC_VIEW)->GetWindowRect(&rect); int width=rect.Width(); ...

  2. Java网络技术-待续

    TCP Sockets基础     Sockets,是用户程序与TCP/IP协议的中介.     实现TCP Sockets通信,需要本地IP和端口,对方IP和端口.客户端发通信请求,发送或接收流,关 ...

  3. Java输入输出技术

    输入输出分类     输入流,相对计算机来说是输入的,例如鼠标键盘操作,设备给计算机的信息     输出流,相对计算机来说是输出的,例如屏幕显示,计算机给设备的信息.   具体分类     基本流,I ...

  4. (转)php语法(符号用法)

    转自:http://blog.unvs.cn/archives/php-equal-bracket.html 学习PHP过程中,会常碰到一些特殊的符号,比如:=.==.===.->.=>. ...

  5. centos常用命令--备份

    端口打开 命令如下:/sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT #8080为指定端口 /etc/rc.d/init.d/iptables ...

  6. unigui 设置单元格颜色

    procedure TF_Resource2.UniDBGrid1DrawColumnCell(Sender: TObject; ACol,  ARow: Integer; Column: TUniD ...

  7. cxGrid单元格获得输入焦点

    cxGrid单元格获得输入焦点   cxGrid单元格获得输入焦点 cxGrid1.SetFocus;cxGrid1DBTableView1.Controller.EditingController. ...

  8. wpf根据X与Y轴获取内部值

    效果图: 环境 Visual Studio ,.Net Framework 4.0 SDK 支持Windows XP,Windows Win7.. 实现方法: 创建ListBox设置ListBox.I ...

  9. 探究Entity Framework如何在多个仓储层实例之间工作单元的实现及原理(2018-05-31修改部分严重错误代码)

    前言 1.本文的前提条件:EF上下文是线程唯一,EF版本6.1.3. 2.网上已有相关API的详细介绍,本文更多的是作为我自己的个人学习研究记录. 3.2018-05-31修改DbSession.cs ...

  10. Ubuntu修改apt-get源

    1.背景 服务器上安装了最新的Ubuntu Server 17.04,代号为zesty.使用apt-get命令安装软件时,有时候速度比较慢,有时候会失败.因此考虑用国内的镜像源更换下apt-get的默 ...