zoukankan      html  css  js  c++  java
  • redis 字典

    字典:(符号表)

    字典就是一个存储kv的存储结构,类似与c++的map,redis数据库的底层就是使用字典实现的

    除了数据库,字典也是哈希键的底层实现

    字典使用哈希表实现,哈希表中存储的都是kv结构

    typedef struct dictht {
    
        // 哈希表数组
        dictEntry **table;
    
        // 哈希表大小
        unsigned long size;
    
        // 哈希表大小掩码,用于计算索引值
        // 总是等于 size - 1
        unsigned long sizemask;
    
        // 该哈希表已有节点的数量
        unsigned long used;
    
    } dictht;

    sizemask和哈希值一起决定了这儿节点应该放在哪里,我们每一个哈希表节点都有一个next属性,这个可以解决链表冲突的问题,使得多个键值一样的可以连在一起

    下面我们看一下哈希表节点的定义:

    typedef struct dictEntry {
    
        //
        void *key;
    
        //
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
        } v;
    
        // 指向下个哈希表节点,形成链表
        struct dictEntry *next;
    
    } dictEntry;

    下面是字典的定义:

    type主要是针对不同的类型,private是针对函数的参数

    其中计算哈希值的函数就在type里面指向的

    有个哈希表数组,ht[1]只有rehash的时候使用,rehashindex也是rehash的时候使用

    typedef struct dict {
    
        // 类型特定函数
        dictType *type;
    
        // 私有数据
        void *privdata;
    
        // 哈希表
        dictht ht[2];
    
        // rehash 索引
        // 当 rehash 不在进行时,值为 -1
        int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    
    } dict;
    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;

    当加入一个键值的时候,我们先根据type里面的函数计算出哈希值,&mask计算出索引值,加入哈希表的指定索引中,

    为了解决哈希表的冲突,我们使用拉链发,但是为了考虑效率,我们通常将新加入的节点放在最前面,不yongO(N)掺入

    rehash:

    哈希表的键值会不听的增多减少,为了让负载因子,维持在一个合理的范围,我们需要适当的进行扩展和收缩

    1. 为字典的 ht[1] 哈希表分配空间, 这个哈希表的空间大小取决于要执行的操作, 以及 ht[0] 当前包含的键值对数量 (也即是 ht[0].used属性的值):
      • 如果执行的是扩展操作, 那么 ht[1] 的大小为第一个大于等于 ht[0].used 2 的 2^n (2 的 n 次方幂);
      • 如果执行的是收缩操作, 那么 ht[1] 的大小为第一个大于等于 ht[0].used 的 2^n 2
    2. 将保存在 ht[0] 中的所有键值对 rehash 到 ht[1] 上面: rehash 指的是重新计算键的哈希值和索引值, 然后将键值对放置到 ht[1] 哈希表的指定位置上。
    3. 当 ht[0] 包含的所有键值对都迁移到了 ht[1] 之后 (ht[0] 变为空表), 释放 ht[0] , 将 ht[1] 设置为 ht[0] , 并在 ht[1] 新创建一个空白哈希表, 为下一次 rehash 做准备。

    哈希表的扩展和收缩的条件:

    1:如果没有执行BSAVE或者BGREWRITEAOF,并且负载因子大于等于1

    2:如果执行BSAVE或者BGREWRITEAOF,并且负载因子大于等于5

    这样设计是因为如果执行的话,会fork出新的进程,因为遵循写实复制,为了尽量避免写入内存进行复制,所以将负载因子提高一些

    如果负载因子小0.1执行收缩

    渐进事rehash:

    因为哈希表的数据可能特别的多,所有rehash不是一次完成的,是多次分批完成的,这里就用到了reashindex,最开始rehashindex=0,表示对索引值0指向的复制,结束了,开始索引值1的,rehashindx+1,这个过程中如果查找的话,会先查找ht[0]->ht[1],添加的话都会添加大1里面,这样可能保证服务器正常的运作

  • 相关阅读:
    D. Babaei and Birthday Cake--- Codeforces Round #343 (Div. 2)
    Vijos P1389婚礼上的小杉
    AIM Tech Round (Div. 2) C. Graph and String
    HDU 5627Clarke and MST
    bzoj 3332 旧试题
    codeforces 842C Ilya And The Tree
    codesforces 671D Roads in Yusland
    Travelling
    codeforces 606C Sorting Railway Cars
    codeforces 651C Watchmen
  • 原文地址:https://www.cnblogs.com/13224ACMer/p/7072093.html
Copyright © 2011-2022 走看看