RedisSDS源码
- 创业
- 2025-07-21 19:20:13

底层数据结构的好处:
杜绝缓冲区溢出。减少修改字符串长度时所需的内存重分配次数。二进制安全。兼容部分C字符串函数。常用命令: set key value、get key 等
应用场景:共享 session、分布式锁,计数器、限流。
1、给char*定义了个别名。 typedef char *sds; 2、创建sds字符串并且分配空间 sds.c sds结构体 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空间的长度 int len; // buf 中剩余可用空间的长度 int free; // 数据空间 char buf[]; }; //好处之一:创建sds字符串的时候会优先分配空间并且预留下一次分配空间。 sds sdsnewlen(const void *init, size_t initlen) { 定义sds结构体指针 struct sdshdr *sh; if (init) { //创建sds结构体并且分配空间 sh = zmalloc(sizeof(struct sdshdr)+initlen+1); } else { sh = zcalloc(sizeof(struct sdshdr)+initlen+1); } if (sh == NULL) return NULL; sh->len = initlen; sh->free = 0; if (initlen && init) memcpy(sh->buf, init, initlen); sh->buf[initlen] = '\0'; return (char*)sh->buf; } 3、sds字符串的追加 /* Append the specified binary-safe string pointed by 't' of 'len' bytes to the * end of the specified sds string 's'. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */ //s目标字符串 //t源字符串 //len追加的长度 sds sdscatlen(sds s, const void *t, size_t len) { struct sdshdr *sh; //计算目标字符串的长度 size_t curlen = sdslen(s); //根据要追加的长度len和目标字符串s的现有长度,判断是否要增加新的空间 s = sdsMakeRoomFor(s,len); if (s == NULL) return NULL; sh = (void*) (s-(sizeof(struct sdshdr))); //将源字符串t中len长度的数据拷贝到目标字符串结尾 memcpy(s+curlen, t, len); sh->len = curlen+len; sh->free = sh->free-len; //追加\0作为本次追加的结尾。 s[curlen+len] = '\0'; return s; } 3-1、扩容详细。,这是一个相对耗时的操作,这里尽量在使用的时候做好计算。
/* Enlarge the free space at the end of the sds string so that the caller * is sure that after calling this function can overwrite up to addlen * bytes after the end of the string, plus one more byte for nul term. * * Note: this does not change the *length* of the sds string as returned * by sdslen(), but only the free buffer space we have. * 当计算后的新的长度小于1MB,则分配两倍空间 * 当计算后的新的长度大于1MB,则在原来基础上加多1MB。 */ #define SDS_MAX_PREALLOC (1024*1024) sds sdsMakeRoomFor(sds s, size_t addlen) { struct sdshdr *sh, *newsh; // 获取 s 目前的空余空间长度 size_t free = sdsavail(s); size_t len, newlen; // s 目前的空余空间已经足够,无须再进行扩展,直接返回 if (free >= addlen) return s; // 获取 s 目前已占用空间的长度 len = sdslen(s); sh = (void*) (s-(sizeof(struct sdshdr))); // s 最少需要的长度 newlen = (len+addlen); // 根据新长度,为 s 分配新空间所需的大小 if (newlen < SDS_MAX_PREALLOC) // 如果新长度小于 SDS_MAX_PREALLOC // 那么为它分配两倍于所需长度的空间 newlen *= 2; else // 否则,分配长度为目前长度加上 SDS_MAX_PREALLOC newlen += SDS_MAX_PREALLOC; // T = O(N) newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1); // 内存不足,分配失败,返回 if (newsh == NULL) return NULL; // 更新 sds 的空余长度 newsh->free = newlen - len; // 返回 sds return newsh->buf; } 4、SDS 类型sdshdr5、sdshdr8、sdshdr16、sdshdr32、sdshdr64
5种结构体类型,设计是一样的,字符数组现有长度 len 和分配空间长度 alloc是不一样的。
以sdshdr8结构体为例,
__attribute__ ((__packed__))的作用: //告诉编译器,在编译 sdshdr8 结构时,不要使用字节对齐的方式,而是采用紧凑的方式分配内存。这是因为在默认情况下,编译器会按照 8 字节对齐的方式,给变量分配内存。也就是说,即使一个变量的大小不到 8 个字节,编译器也会给它分配 8 个字节。
struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* 字符数组现有长度*/ uint8_t alloc; /* 字符数组的已分配空间,不包括结构体和\0结束字符*/ unsigned char flags; /* SDS类型*/ char buf[]; /*字符数组*/ };RedisSDS源码由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“RedisSDS源码”
上一篇
C++作业5
下一篇
JavaScript基础