深入底层C源码 Redis核心设计原理( 三 )

5)分析是怎么扩容的
代码展示
// 扩容sdssds sdsMakeRoomFor(sds s, size_t addlen) {void *sh, *newsh;//获取剩余可用的空间size_t avail = sdsavail(s);size_t len, newlen;char type, oldtype = s[-1] & SDS_TYPE_MASK;int hdrlen;//如果可用空间大于需要增加的长度 , 那么直接返回if (avail >= addlen) return s;//len 已使用长度len = sdslen(s);//sh 回到指向了这个sds的起始位置 。sh = (char*)s-sdsHdrSize(oldtype);// newlen 代表最小需要的长度newlen = (len+addlen);//Redis认为一旦被扩容了 , 那这个字符串被再次扩容的几率就很大 , 所以会在此基础上多加一些空间 , 防止频繁扩容if (newlen < SDS_MAX_PREALLOC)newlen *= 2;elsenewlen += SDS_MAX_PREALLOC;//获取新长度的类型type = sdsReqType(newlen);//如果是SDS_TYPE_5会被强行转为SDS_TYPE_8if (type == SDS_TYPE_5) type = SDS_TYPE_8;hdrlen = sdsHdrSize(type);if (oldtype==type) {//sh是开始地址 , 在开始地址的基础上 , 分配更多的空间 , 逻辑如同初始化部分 , hdrlen 是head的长度 , 即struct本身大小 。后面newlen 是buf 大小 ,  +1 是为了结束符号 , sds 通常情况下是可以直接打印的newsh = s_realloc(sh, hdrlen+newlen+1);if (newsh == NULL) {s_free(sh);return NULL;}s = (char*)newsh+hdrlen;} else {//如果类型发生变化 , 地址内容不可复用 , 所以找新的空间 。newsh = s_malloc(hdrlen+newlen+1);if (newsh == NULL) return NULL;//复制原来的str到新的sds 上面,newsh+hdrlen 等于sds buf 地址开始的位置 , s 原buf的位置 , len+1 把结束符号也复制进来memcpy((char*)newsh+hdrlen, s, len+1);//释放前面的内存空间s_free(sh);//调整s开始的位置 , 即地址空间指向新的buf开始的位置s = (char*)newsh+hdrlen;//-1 正好到了flag的位置s[-1] = type;//分配len的值sdssetlen(s, len);}sdssetalloc(s, newlen);//返回新的sdsreturn s;}// 给len 设值static inline size_t sdsavail(const sds s) {unsigned char flags = s[-1];switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5: {return 0;}case SDS_TYPE_8: {SDS_HDR_VAR(8,s);return sh->alloc - sh->len;}case SDS_TYPE_16: {SDS_HDR_VAR(16,s);return sh->alloc - sh->len;}case SDS_TYPE_32: {SDS_HDR_VAR(32,s);return sh->alloc - sh->len;}case SDS_TYPE_64: {SDS_HDR_VAR(64,s);return sh->alloc - sh->len;}}return 0;}// 获取当前sds,可用的长度 。static inline void sdssetlen(sds s, size_t newlen) {unsigned char flags = s[-1];switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5:{unsigned char *fp = ((unsigned char*)s)-1;*fp = (unsigned char)(SDS_TYPE_5 | (newlen << SDS_TYPE_BITS));}break;case SDS_TYPE_8:SDS_HDR(8,s)->len = (uint8_t)newlen;break;case SDS_TYPE_16:SDS_HDR(16,s)->len = (uint16_t)newlen;break;case SDS_TYPE_32:SDS_HDR(32,s)->len = (uint32_t)newlen;break;case SDS_TYPE_64:SDS_HDR(64,s)->len = (uint64_t)newlen;break;}}// 获取alloc的长度/* sdsalloc() = sdsavail() + sdslen() */static inline size_t sdsalloc(const sds s) {unsigned char flags = s[-1];switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5:return SDS_TYPE_5_LEN(flags);case SDS_TYPE_8:return SDS_HDR(8,s)->alloc;case SDS_TYPE_16:return SDS_HDR(16,s)->alloc;case SDS_TYPE_32:return SDS_HDR(32,s)->alloc;case SDS_TYPE_64:return SDS_HDR(64,s)->alloc;}return 0;}// 给 alloc 设值static inline void sdssetalloc(sds s, size_t newlen) {unsigned char flags = s[-1];switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5:/* Nothing to do, this type has no total allocation info. */break;case SDS_TYPE_8:SDS_HDR(8,s)->alloc = (uint8_t)newlen;break;case SDS_TYPE_16:SDS_HDR(16,s)->alloc = (uint16_t)newlen;break;case SDS_TYPE_32:SDS_HDR(32,s)->alloc = (uint32_t)newlen;break;case SDS_TYPE_64:SDS_HDR(64,s)->alloc = (uint64_t)newlen;break;}}代码说明
【1】sds内部buf的扩容机制:新buf长度 = (原buf长度 + 添加buf长度)*2 , 如果buf长度大于1M后 , 每次扩容也只会增大1M

经验总结扩展阅读