redis数据结构——字典

redis的字典底层实现是hash表,用来存储K-V对,其中K是唯一的。

了解java中hashmap的话,那么字典就很好理解了,完全可以参照hashmap的结构。

下面是hash表的结构:

typedef struct dictht {
    dictEntry **table; /* hash表数组 */
    unsigned long size; /* hash表大小 */
    unsigned long sizemask; /* 用来计算索引,sizemask=size-1 */
    unsigned long used; /* hash表中已经被使用的节点的数量 */
} dictht;

其中**table是指向dictEntry的指针,dictEntry结构如下:

typedef struct dictEntry {
    void *key; /* 键 */
    union {
        void *val; /* 值 */
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;  /* 指向下一个节点 */
} dictEntry;

下面是hash表存储的示例图,来自《redis设计与实现》一书

以上是hash表的相关结构图。下面来看“字典”的结构图

typedef struct dict {
    dictType *type; /* 类型 */
    void *privdata; /* 私有数据 */
    dictht ht[2]; /* 两个hash表 */
    long rehashidx; /* 通过这个值判断是否需要rehash */
    unsigned long iterators; /* 当前运行的迭代器的数量 */
} dict;

下面一一解释dict结构中的内容:

dictType:

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key); /* 计算hash值的函数 */
    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;

ht[2]:一个字典结构中包含两个hash表,一般情况下字典只会使用ht[0]的hash表,而空余的ht[1]作为备用表,会在rehash的时候使用。

rehashidx:这是一个在rehash操作中至关重要的属性,如果rehashidx=-1,那么不会进行rehash,否则,进行rehash。

在这一版的dict中还有一个dictIterator结构,它的作用也可以参考Java的hashmap中的迭代器

typedef struct dictIterator {
    dict *d; /* 指向一个字典的指针 */
    long index; 
    /* 当safe=1时,说明迭代器安全,那么可以调用有关dict的一系列函数对dict进行CRUD; 
     * 当safe!=1时,说明迭代器不安全,只能调用dictNext()函数,遍历下一个节点
     */
    /* table是字典结构中所包含的两个hash表的下标,用来表示此时是ht[0]还是ht[1] */
    int table, safe; 
    dictEntry *entry, *nextEntry; /* 指向当前元素和下一个元素 */
    long long fingerprint; /* 指纹,当迭代器不安全时,用来检测 */
} dictIterator;

可以看看有关fingerprint的函数:可以看出fingerprint就是一个计算出的hash值。

long long dictFingerprint(dict *d) {
    long long integers[6], hash = 0;
    int j;
    
    /* ht[0]hash表 */
    integers[0] = (long) d->ht[0].table;
    integers[1] = d->ht[0].size;
    integers[2] = d->ht[0].used;
    /* ht[1]hash表 */
    integers[3] = (long) d->ht[1].table;
    integers[4] = d->ht[1].size;
    integers[5] = d->ht[1].used;

    /* 以下是hash算法:Result = hash(hash(hash(int1)+int2)+int3) ...
     * 这种算法的好处在于,即便是两个或多个itegers数组中的数值相同,
     * 但是排序不同,也可能会使得hash的结果不同
     */
    for (j = 0; j < 6; j++) {
        hash += integers[j];
        /* 使用64位整数hash(看不懂算了知道有这个东西就行) */
        hash = (~hash) + (hash << 21); // hash = (hash << 21) - hash - 1;
        hash = hash ^ (hash >> 24);
        hash = (hash + (hash << 3)) + (hash << 8); // hash * 265
        hash = hash ^ (hash >> 14);
        hash = (hash + (hash << 2)) + (hash << 4); // hash * 21
        hash = hash ^ (hash >> 28);
        hash = hash + (hash << 31);
    }
    return hash;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值