redis源码解析(三)——dict

版本:redis - 5.0.4
参考资料:redis设计与实现
文件:src下的dict.c dict.h

一、dict.h

dict(字典),又称为符号表,关联数组或映射。用于保存键值对。

  • 字典使用哈希表作为底层实现。
  • 使用两张表来进行大小的扩展。
  • 用链接的方式处理冲突。新节点头插。
数据结构
//节点:key, v, next
typedef struct dictEntry {
   
    void *key;
    union {
   
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

//hash表
typedef struct dictht {
   
    dictEntry **table;//dictEntry数组
    unsigned long size;//表大小
    unsigned long sizemask;//表的掩码,等于size-1
    unsigned long used;//已有的节点数量
} dictht;

//字典
typedef struct dict {
   
    dictType *type;
    void *privdata;
    dictht ht[2];//两张表
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

hash表的存储结构
在这里插入图片描述

rehash(扩展/收缩)

字典中存储了两张hash表,先使用ht[0],rehash时:

  • 为ht[1]分配空间:若是扩展,ht[1]的大小等于ht[0].used * 2的第一个2^n;若是收缩,ht[1]的大小等于第一个ht[0].used 的2^n
  • 将ht[0]中的全部键值对rehash,存放到ht[1]中。
  • 当ht[0]为空时,释放ht[0],将ht[1]设为ht[0],并在ht[1]创建一个空白hash表。

渐进式rehash:当键值对很多时,rehash很慢,甚至需要服务器在一段时间内停止服务,为了避免这样的事情,所以需要渐进式的,分多次rehash到ht[1]。

  • 为ht[1]分配空间后,将字典中的rehashidx设为0,说明正在rehash。
  • rehash期间,每次对字典增删改查时,除了执行指定操作,还要顺带把ht[0]在rehashidx索引上的全部键值对rehash到ht[1]。完成后,rehashidx加一。
  • 当ht[0]为空时,设rehashidx为-1,表示rehash结束。

缺点是,rehash期间同时使用两张表,所以许多操作都需要执行两遍,在ht[0]没有找到的节点在ht[1]上还要再找一次。

操作
//迭代器
typedef struct dictIterator {
   
    dict *d;
    long index;
    int table, safe;
    dictEntry *entry, *nextEntry;
    /* unsafe iterator fingerprint for misuse detection. */
    long long fingerprint;
} dictIterator;

//参数为 (void *privdata, const dictEntry *de) ,返回值为 void 的函数建立别名 dictScanFunction。
typedef void (dictScanFunction)(void *privdata, const dictEntry *de);
typedef void (dictScanBucketFunction)(void *privdata, dictEntry **bucketref);

typedef的高级应用

/* API */
dict *dictCreate(dictType *type, void *privDataPtr);//生成
int dictExpand(dict *d, unsigned long size);//扩展
int dictAdd(dict *d, void *key, void *val);//添加节点
dictEntry *dictAddRaw(dict *d, void *key, dictEntry **existing);//生成一个空节点,加到dict中
dictEntry *dictAddOrFind(dict *d, void *key);//得到指定节点
int dictReplace(dict *d, void *key, void *val);//替换值
int dictDelete(dict *d, const void *key);//删除给定键的节点
dictEntry *dictUnlink(dict *ht, const void *key);//移除节点 但不释放
void dictFreeUnlinkedEntry(dict *d, dictEntry *he);//释放那个移除的节点
void dictRelease(dict *d);//释放d
dictEntry * dictFind(dict *d, const void *key);//查找
void *dictFetchValue(dict *d, const void *key);//得到值
int dictResize(dict *d);//重新设置大小

dictIterator *dictGetIterator(dict *d);//生成一个不安全的迭代器
dictIterator 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值