Redis数据结构(一)字符串SDS、双端链表、字典

SDS

在这里插入图片描述
特性
1、常数时间获取长度
2、杜绝缓冲区溢出,当连接字符串后长度超过buf实际长度,会预先扩展空间。
3、空间预分配。当对SDS修改并且需要扩展空间时,SDS为预分配双倍字符串长度的空间(len < 1MB)。例如,当前sds长度为13,修改后len = 13,free = 13,buf实际长度为13 + 13 + 1 = 27(包括\0)。如果sds修改后len大于等于1MB,程序则分配1MB的未使用空间。例如,修改后len = 30MB,则buf的时间长度为30MB + 1MB + 1byte。
4、二进制安全,不以\0区分是否字符串结尾,而以len判断
5、兼容部分C字符串函数
在这里插入图片描述

Linked List

每个链表节点使用adlist.h/listNode表示。

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

多个listNode组成链表list:

typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
    unsigned long len;
} list;

其中,dup函数用于复制链表节点所保存的值,free函数用于释放链表节点所保存的值,match函数用于对比链表节点所保存值是否与另一输入值相等。

Dict

Redis字典所使用的哈希表由dict.h/dictht结构定义:

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

table属性是一个数组,每个元素都是指向dict.h/dictEntey结构的指针。

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

由结构可知,redis使用拉链法处理冲突。

Redis字典由dict.h/dict表示

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;

type属性和privdata属性是针对不同类型的键值对,为创建多态字典而设置的:

  • type是指向dictType结构的指针,每个dictType保存一簇用于操作特定类型键值对的函数,Redis会为用途不同的字典设置不同的类型特定函数。
  • privdata保存需要传给那些特定类型特定函数的可选参数。
typedef struct dictType {
    uint64_t (*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;

ht属性是一个包含两个哈希表的数组,一般情况下,字典只是用ht[0],ht[1]只在rehash时使用。
rehashidx记录rehash进度,未在rehash时,值为-1。

rehash

随着操作的不断执行,哈希表保存的键值对会逐渐地增多或者减少,为了让哈希表的负载因子维持一个合理范围,当哈希表保存的kv太多或者太少时,程序需要对哈希表进行相应扩展或收缩。
rehash步骤如下:

  1. 为字典ht[1]分配空间,空间大小取决于要执行的操作以及ht[0]当前的kv数量。如果是
    • 如果执行的是扩展操作,ht[1]大小为第一个大于等于ht[0].used * 2的2^n;
    • 如果执行的是收缩操作,ht[1]大小为第一个大于等于ht[0].used的2^n;
  2. 将保存在ht[0]中所有键值对reshash到ht[1]上面;rehash指的是重新计算键的哈希值和索引值,然后将 键值对放置到ht[1]哈希表指定位置。
  3. 所有kv迁移完毕后,释放ht[0],将ht[1]设置为ht[0]。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值