标签:SDS void Redis 笔记 链表 API 字符串 数据结构 节点
Redis笔记1-数据结构
1、简单动态字符串
Redis不直接使用C传统的字符串表示,构建了简单动态字符串(Simple Dynamic String, SDS)的抽象类型,并将SDS作为Redis的默认字符串表示
SDS定义
struct sdshdr{
int len; //记录buf数组已使用字节的数量,等于SDS所保存字符串长度
int free; //记录buf数组未使用字节的数量
char buf[]; //字节数组,用于保存字符串
}
SDS优点
重用C库函数
SDS遵循C字符串以空字符结尾的惯例,因此可以重用一部分C库的函数
常数复杂度获取字符串长度
获取字符串长度时间复杂度为O(1)。(访问SDS.len属性)
杜绝缓冲区溢出
当SDS的API需要对SDS进行修改,API会先检查SDS的空间释放满足修改要求,如果不满足会自动扩充
减少修改字符串时内存重分配次数
内存重分配解释:
对于一个包含N个字符的C字符串,其底层实现是一个N+1字符长的数组,每次增加或缩短一个字符串都要对字符串数组进行内存重分配
- 增长字符串:先通过内存重分配扩展底层数组空间大小,否则造成缓冲区溢出
- 缩短字符串:需通过内存重分配释放不再使用的空间,否则造成内存泄露
通过free属性记录的未使用空间,实现空间预分配和惰性空间释放
Redis作为数据库,需频繁增删字符串,太多内存重分配的操作会影响性能,因此通过free属性解除字符串长度和底层数组长度的关联。
二进制安全
C字符串的字符必须符合某种编码(如ASCII),并且除了末尾,不能包含空字符,会被误认为结尾。因此C字符串只能保存文本数据,而不能保存二进制数据(如图片,音频)。
SDS的API会以处理二进制的方式处理buf数组的数据,这也是buf属性称为字节数组的原因
并且使用len属性判断字符串是否结束。
SDS API
2、链表
Redis也构建了自己的链表实现,列表键的实现之一就是链表。
当列表键包含数量较多的元素,或包含的元素都是比较长的字符串,就会使用链表作为列表键的底层实现。
发布与订阅,慢查询,监视器等功能也用到链表,Redis服务器本身还使用链表保存多个客户端的状态信息,以及使用链表构建客户端输出缓冲区。
链表和链表节点实现
链表节点:ListNode
typedef struct listNode{
struct listNode *prev;
struct listNode *next;
void *value;
}
多个ListNode可以组成双链表。
链表: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); //节点值对比函数
}
dup、free、match成员是用于实现多态链表所需的类型特定函数
特性总结
- 双端:prev和next指针获取前置和后置节点,复杂度O(1)
- 无环:表头的prev和表尾的next指向NULL
- 带表头指针和表尾指针:head和tail获取表头和表尾节点,复杂度O(1)
- 带链表长度计数器:len属性
- 多态:用void*指针保存节点值,可以保存不同类型的值
链表和链表节点API
3、字典
4、跳表
5、集合
6、压缩列表
7、对象
(待补充)
标签:SDS,void,Redis,笔记,链表,API,字符串,数据结构,节点 来源: https://blog.csdn.net/MinutkiBegut/article/details/115235915
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。