SDS是simple dynamic string的缩写,是redis定义的字符串的数据结构。根据需要保存的字符串长度的差异,不同结构体定义如下,使用的柔性数组,例如sizeof(struct sdshdr5 )只会计算flags的长度,如果写成:
/* Note: sdshdr5 is never used, we just access the flags byte directly. * However is here to document the layout of type 5 SDS strings. */ /* sdshdr5实际已经不再使用 */ struct __attribute__ ((__packed__)) sdshdr5 { unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ /* 已经使用的内存长度 */ uint8_t alloc; /* excluding the header and null terminator */ /* 为buf申请的长度,不包含最后一个结束符0 */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ /* 使用低3为表示类型,这个字段设计比较巧妙,下面会介绍 */ char buf[]; /* 也可以写成char buf[0],也表示柔性数组。写成char *buf不是柔性数组 */ }; struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; /* used */ uint16_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; };
attribute ((packed)) 是gcc定义的extension,用来告诉编译器不要使用字节对齐,可以节省空间,不过会降低运行效率。
添加flags的定义是为了方便使用Sds,对外指针指向buf就可以使用,buf[-1]就是flags字段,进而得到len和alloc。
#define SDS_TYPE_5 0 #define SDS_TYPE_8 1 #define SDS_TYPE_16 2 #define SDS_TYPE_32 3 #define SDS_TYPE_64 4
typedef char *sds; /* 初始化固定内容的Sds */ sds sdsnewlen(const void *init, size_t initlen) { void *sh; sds s; char type = sdsReqType(initlen); /* 根据长度得到类型,用于确定sds的结构 */ /* Empty strings are usually created in order to append. Use type 8 * since type 5 is not good at this. */ if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8; int hdrlen = sdsHdrSize(type); /* 计算sds的结构长度 */ unsigned char *fp; /* flags pointer. */ sh = s_malloc(hdrlen+initlen+1); /* 申请内存,多申请的1字节用于存放末尾结束符0,所以sds的结构中alloc长度不包含末尾0*/ if (init==SDS_NOINIT) init = NULL; else if (!init) memset(sh, 0, hdrlen+initlen+1); if (sh == NULL) return NULL; s = (char*)sh+hdrlen; fp = ((unsigned char*)s)-1; /* 指向了sds结构中的flags,等价于s[-1] */ switch(type) { case SDS_TYPE_5: { *fp = type | (initlen << SDS_TYPE_BITS); /* 这个一般用不到,先不看 */ break; } case SDS_TYPE_8: { SDS_HDR_VAR(8,s); /* struct sdshdr8 *sh = (void*)((s)-(sizeof(struct sdshdr8))); */ /* 把sh类型强转 */ sh->len = initlen; sh->alloc = initlen; *fp = type; /* flags赋值 */ break; } case SDS_TYPE_16: { SDS_HDR_VAR(16,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } case SDS_TYPE_32: { SDS_HDR_VAR(32,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } case SDS_TYPE_64: { SDS_HDR_VAR(64,s); sh->len = initlen; sh->alloc = initlen; *fp = type; break; } } if (initlen && init) memcpy(s, init, initlen); s[initlen] = '\0'; return s; /* 返回的是buf字段 */ } /* Duplicate an sds string. 拷贝一个 */ sds sdsdup(const sds s) { return sdsnewlen(s, sdslen(s)); } /* Free an sds string. No operation is performed if 's' is NULL. 清除 */ void sdsfree(sds s) { if (s == NULL) return; s_free((char*)s-sdsHdrSize(s[-1])); /* s[-1]找到内存头 */ }