redis设计与实现总结--简单动态字符串和链表
简单动态字符串(SDS)
struct sdshdr { //记录buf数组中已使用字节的数量 //等于SDS所保存字符串的长度 int len; //记录buf数组中未使用字节的数量 int free; //字节数组,用于保存字符串 char buf[]; }
一般会留最后一个字节来保存'\0',不计算再len中,方便使用c字符串函数
为了防止缓冲区异常,每次SDS扩展会先看预留空间是否够,否则另外申请大空间复制,再扩展。
但如果缩短并不会变,只有free的值变。
为了避免缓冲区溢出(增长)和内存泄露(缩短)
SDS的空间分配策略
1.空间预分配
当需要增加字符串长度时:
修改后SDS长度小于1MB,则程序分配和len属性相同大小的未使用空间,这时len=free。
修改后SDS长度大于1MB,则分配1MB未分配空间。
2.惰性空间释放
但如果缩短并不会变,只有free的值变。而且提供了相应的API(sdsfree,sdsrange)防止内存浪费。
SDSbuf数组内可以保存的是二进制数据,因为不是根据'\0'判断,而是根据len长度来判断。
对比C字符串,SDS有如下优点:
1.常数复杂度获取字符串长度。
2.杜绝缓冲区溢出。
3.减少修改字符串长度时所需的内存重分配次数。
4.二进制安全。
5.兼容部分C字符串函数。
链表
双向无环链表
应用:列表键,发布与订阅,慢查询,监视器等。
typedef struct listNode { //前置节点 struct listNode *prev; //后置节点 struct listNode *next; //节点的值 void *value; }listNode;
typedef struct list { //表头节点 listNode *head; //表尾节点 listNode *tail; //链表所包含的节点数 unsigned long len; //节点复制函数 void *(*dup)(void *ptr); //节点释放函数 void *(free)(void *ptr); //节点对比函数 inr *(*match)(void *ptr,void *key); }list;
三个函数去实现多态。