Redis学习日志(一)

这篇博客主要介绍了Redis中的一些核心数据结构,包括String、链表、字典、哈希算法、渐进式rehash、跳跃表、HyperLogLog、整数集合和压缩列表。通过深入解析这些数据结构,读者可以更好地理解Redis的内部工作原理及其高效存储和操作数据的方式。
摘要由CSDN通过智能技术生成

底层数据结构:sds、list、dict、ziplist、intset、skiplist

1.String

Redis构建了简单动态字符串SDS来作为默认字符串表示,属于可修改字符串的值。
当一些如打印日志等不需被修改的字符串则用C语言传统字符串表示。
sds用于存储字符串、AOF缓冲区、客户端状态中的输入缓冲区等。
sds实际是char型指针,即C语言的字符串表述形式
sdshdr是redis中的简单动态字符串结构,而实际上在使用字符串时,
依旧是使用char* 而不是sdshdr,在C中可根据地址偏移,
得到该char* (sds)所在的sdshdr的地址,借用指针进行操作。

sds定义:
        struct sdshdr{
            int len;//记录buf数组中已使用字节长度,等于SDS保存的字符串长度
            int free;//记录buf数组中未使用的字节长度
            char buf[];//字符数组,用于保存字符串
        }

buf[]保存字符,最后一个字节保存空字符’\0’结尾,这1字节空间不计算在len属性中。
遵循空字符结尾惯例,可对C字符串函数库中进行一些重用。

        /* 根据给定的初始化字符串 init 和字符串长度 initlen
         * 创建一个新的 sds
         * 参数
         *  init :初始化字符串指针
         *  initlen :初始化字符串的长度
         * 返回值
         *  sds :创建成功返回 sdshdr 相对应的 sds
         *        创建失败返回 NULL
         * 复杂度
         *  T = O(N) */
        sds sdsnewlen(const void *init, size_t initlen) {
            struct sdshdr *sh;
            // 根据是否有初始化内容,选择适当的内存分配方式
            // T = O(N)
            if (init) {
                // zmalloc 不初始化所分配的内存
                sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
            } else {
                // zcalloc 将分配的内存全部初始化为 0
                sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
            }
            // 内存分配失败,返回
            if (sh == NULL) return NULL;
            // 设置初始化长度
            sh->len = initlen;
            // 新 sds 不预留任何空间
            sh->free = 0;
            // 如果有指定初始化内容,将它们复制到 sdshdr 的 buf 中
            // T = O(N)
            if (initlen && init)
                memcpy(sh->buf, init, initlen);
            // 以 \0 结尾
            sh->buf[initlen] = '\0';
            // 返回 buf 部分,而不是整个 sdshdr
            return (char*)sh->buf;
        }    

SDS与C字符串相比:
①SDS结构的len属性记录了字符串长度,当要获取时,复杂度仅为O(1),无需进行O(n)的遍历;
②杜绝缓冲区溢出:在对SDS字符串进行修改时,会检查SDS剩余空间(free属性)是否充足,
若不足则先进行扩展。
③减少修改字符串时的内存重分配次数
④可保存二进制数据
⑤兼容部分C字符串函数

2.链表

Redis链表结构(adlist.h/listNode)

            typedef struct listNode{
                struct listNode *prev;//前置节点
                struct listNode *next;//后置节点
                void *value;//节点值
            }listNode;

对listNode进行一层包装(adlist/list)

            typedef struct list{
                listNode *head//表头节点
                listNode *tail;//表尾结点
                unsigned long len;//链表包含的节点数量
                void *(*dup)(void *ptr);//节点值复制函数
                void (*free)(void *ptr);//节点值释放函数
                int (*match)(void *ptr,void *key);//节点值对比函数
            }list;

|list listNode <– listNode <–listNode
|head –> value=.. –> value=..–> value=.. –>null
|tail —————————————↑
|len=3
|dup –>…..list结构中的3个listNode
|free –>….
|match –>…
Redis链表特性:
双端:链表节点有prev和next指针
无环:表头节点的prev和表尾节点的next指向null 不循环
带头指针和尾指针:list结构的head指针和tail指针
计数器:list结构的len属性保存节点个数
多态:链表节点使用void*指针保存节点值,
可通过list结构的dup、free、match属性为节点值设置类型特定函数
因此链表可保存各种不同类型的值。
(①void指针可以指向任意类型的数据,亦即可用任意数据类型的指针对void指针赋值
②可以用void指针来作为函数形参,就可以接受任意数据类型的指针作为参数)

3.字典

(map映射,用于保存键值对 key-value)
Redis哈希表结构(dict.h/dictht)

            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值