2.1 SDS的定义
SDS的结构体:
int len//记录buf数组中已使用字节的数列
int free;//记录buf数组中未使用字节的数列
char buf[];//字节数组,用于保存字符串
2.2 SDS与C字符串的区别
2.2.1 常数复杂度获取字符串的长度:
C语言字符串获取长度时间复杂度为O(n)
2.2.2 杜绝缓冲区溢出
C字符串不记录自身长度,会造成缓冲区溢出
在对SDS进行修改时,API会检查SDS对空间是否满足修改所需对有求,如果不满足,API会自动将SDS的空间扩展至执行修改所需的大小,然后才执行所需的修改操作
2.2.3 减少修改字符串时带来的内存重分配次数
1.空间预分配
用于优化SDS字符串增长操作:当一个API对SDS进行修改,并且需要对SDS对空间进行扩展的时候,程序不仅会为SDS分配修改所必须要的空间,还会为SDS分配额外的未使用空间
当SDS的长度小于1MB,程序分配和len属性同样大小的未使用空间
当SDS的长度大于等于1MB,程序会分配1MB的未使用空间。
2.惰性空间释放
用于优化SDS字符串缩短操作:当SDS的API需要缩短SDS保存的字符串时,程序并不立即使用内存重分配来回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,并等待将来使用。
2.2.4 二进制安全
C字符串只能存储文本数据
Redis不是使用buf来保存字符,而是用它来保存一系列二进制数据
2.2.5 兼容部分C字符串函数
可以重用一部分库定义的函数
3.链表
链表提供了高效的节点重排能力,以及顺序性的节点访问方式,并且可以通过增删节点来灵活地调整链表的长度
链表键、发布与订阅、慢查询、监视器等功能也用到来链表
3.1 链表和链表节点的实现
listnode{
listnode *head;
listNode *tail;
unsigned long len;
void *(*dup)(void *ptr);
void (*free)(void *ptr);
int (*match)(void *ptr, void *key);
}
Redis链表实现特性:
双端:prev指针,获取当前节点的前置节点,next指针,用来获取当前节点的后置节点
无环:表头节点的prev指针和next指针都指向NULL,对链表的访问以NULL为终点
带有表头节点和表尾节点指针:通过list的head指针和tail指针,程序获取链表的表头节点和表尾节点的复杂度为O(1)
带链表长度计数器:程序使用list结构的len属性来对list持有的链表节点进行计数,程序获取链表长度的时间复杂度为O(1)
多态:链表节点使用void*指针来保存节点值,可以通过dup,free,match为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值