redis数据结构 - SDS

简单动态字符串
有5种类型,分别对应不同长度的sds: sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64
使用__attribute__ ((__packed__))定义sdshdr,告诉编译器取消字节对齐,结构体成员在内存空间上都是连续的,使用sds的小标可以直接指向sdshdr中的其他成员

sdshdr 
len :sds已使用的长度
alloc:包括头部与已使用+未使用的空间占用的大小
flags:标识sdshdr类型
char buf[]:sds,柔性数组,起到标记的作用,标识在flags字段后边是一个字符数组,在sdshdr分配内存的时候,柔性数组并不会占用内存
因为buf指向sda,所以通过sds和sizeof(sdshdr)可以获得sdshdr结构体首地址
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))

sds[-1] :flags & 7 :sds_type
SDS_HDR(sds_type, sds): sdshdr结构体首地址
SDS_HDR(sds_type, sds)->len: 获得sds长度

SDS的一些基础函数
sdslen(const sds s): 获取sds字符串长度。
sdssetlen(sds s, size_t newlen): 设置sds字符串长度。
sdsinclen(sds s, size_t inc): 增加sds字符串长度。
sdsalloc(const sds s): 获取sds字符串容量。
sdssetalloc(sds s, size_t newlen): 设置sds字符串容量。
sdsavail(const sds s): 获取sds字符串空余空间(即alloc - len)。
sdsHdrSize(char type): 根据header类型得到header大小。
sdsReqType(size_t string_size): 根据字符串数据长度计算所需要的header类型。

sds sdsnewlen(const void *init, size_t initlen):sds创建
一次性进行分配需要的内存空间,包含三部分:header、数据、最后的多余字节(hdrlen+initlen+1)
初始化的sds字符串数据最后要追加一个NULL结束符s[initlen] = '\0'

void sdsfree(sds s):sds释放
需要注意的是:内存要整体释放,所以要先计算出header起始指针,把它传给s_free函数。
(char*)s-sdsHdrSize(s[-1]) 这个指针也正是在sdsnewlen中调用s_malloc返回的那个地址

sds sdscatlen(sds s, const void *t, size_t len):sds追加
将t指向的长度为len的任意二进制数据追加到sds字符串s的后面。

sds sdsMakeRoomFor(sds s, size_t addlen):
保证字符串s有足够的空间来追加长度为len的数据,可能会分配新的内存,也可能不会
按分配后的空间大小,可能需要更换header类型(原来header的alloc字段太短,表达不了增加后的容量)
如果不需要更换header,调用s_realloc,试图在原来的地址上重新分配空间,尽量在原来分配好的地址位置重新分配,如果原来的地址位置有足够的空余空间完成重新分配,那么它返回的新地址与传入的旧地址相同;否则,它分配新的地址块,并进行数据搬迁
如果需要更换header,那么整个字符串空间(包括header)都需要重新分配(s_malloc),并拷贝原来的数据到新的位置

调用sdscatlen的时候,传入一个旧的sds变量,然后它返回一个新的sds变量。由于它的内部实现可能会造成地址变化,因此调用者在调用完之后,原来旧的变量就失效了,而都应该用新返回的变量来替换。sds中的其它函数(比如sdscpy、sdstrim、sdsjoin等),还有Redis中其它一些能自动扩展内存的数据结构(如ziplist),也都是同样的使用模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值