• 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. C和C++中的volatile、内存屏障和CPU缓存一致性协议MESI

    目录 1. 前言2 2. 结论2 3. volatile应用场景3 4. 内存屏障(Memory Barrier)4 5. setjmp和longjmp4 1) 结果1(非优化编译:g++ -g -o ...

  2. java 定时执行

    Timer和TimerTask CountDownTimer (android)

  3. idea操作快捷键

    Ctrl+Shift + Enter,语句完成“!”,否定完成,输入表达式时按 “!”键Ctrl+E,最近的文件Ctrl+Shift+E,最近更改的文件Shift+Click,可以关闭文件Ctrl+[ ...

  4. (转)Log4Net 全方位跟踪程序运行

    转自:http://www.cnblogs.com/qingyuan/archive/2011/05/13/2045616.html 前端日子自己写了一个简单的日志跟踪程序,现在目前正在做的一个项目中 ...

  5. noip第34课作业

    1.    信息加密 [问题描述] 在传递信息的过程中,为了加密,有时需要按一定规则将文本转换成密文发送出去.有一种加密规则是这样的:1. 对于字母字符,将其转换成其后的第3个字母.例如:A→D,a→ ...

  6. nodeclub models

    之前看过keystone的结构,所以现在看nodeclub时,总会和keystone进行比较. nodeclub models会有一个index来作为facade,通过它连接mongodb,expor ...

  7. hive-内部表和外部表 对比

    建表时,需要考虑究竟建内部表还是外部表,内部表和外部表都有哪些不同? 内部表: 1. 数据存储位置:数据最终会被移动到 hive.metastore.warehouse.dir指定的路径下,以表名创建 ...

  8. 背水一战 Windows 10 (53) - 控件(集合类): ItemsControl 的布局控件 - ItemsStackPanel, ItemsWrapGrid

    [源码下载] 背水一战 Windows 10 (53) - 控件(集合类): ItemsControl 的布局控件 - ItemsStackPanel, ItemsWrapGrid 作者:webabc ...

  9. Javascript如何避免连续调用中取到不存在的属性而导致报TypeError错?

    背景: 在最近的 NODEJS 项目中,涉及到数据库的查询,回调函数里返回了查询结果,我这样做处理然后返回给前端: return results.collect_coupon[0].count 但是这 ...

  10. Java - 集成开发环境Eclipse的使用方法和技巧

    00 - Eclipse教程 Eclipse 教程 01 - Eclipse设置编译和运行的环境 建议编译和运行的版本保持一致,否则请特别注意: 低编译,高运行 ---> 可行. 高编译,低运行 ...