当前位置: 首页 > news >正文

Redis SDS 源码

底层数据结构的好处:

  1. 杜绝缓冲区溢出。
  2. 减少修改字符串长度时所需的内存重分配次数。
  3. 二进制安全。
  4. 兼容部分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[]; /*字符数组*/
};


相关文章:

  • 开启三层交换机DHCP服务
  • Golang数据类型(字符串)
  • 剑指 Offer(第2版)面试题 18:删除链表的节点
  • [组合数学]LeetCode:2954:统计感冒序列的数目
  • 三、DVP摄像头调试笔记(图片成像质量微调整,非ISP)
  • JavaScript 基础
  • 深入理解指针3
  • 软著项目推荐 深度学习的水果识别 opencv python
  • Hadoop学习笔记(HDP)-Part.14 安装YARN+MR
  • Python自动化——driver.switch_to的用法
  • 免费数据采集软件,多种数据采集方式
  • 混音编曲软件tudio One 6.5.1 保姆级安装教程
  • CopyOnWriteArrayList怎么用
  • Javafx实现浏览器
  • 【UGUI】sprite精灵的创建与编辑
  • 【LeetCode刷题笔记】103. 二叉树的锯齿形层序遍历
  • 基于ssm vue的风景文化管理平台源码和论文
  • Scrum敏捷开发流程及支撑工具
  • 计数问题(数位DP)
  • C/C++内存管理
  • 持续8年仍难终了的纠纷:败诉方因拒执罪被立案,胜诉方银行账户遭冻结
  • 新华时评:中美经贸会谈为全球经济纾压增信
  • 中医的千年传承:网络科学描绘其演化之路|PNAS速递
  • 马上评丨摆摊要交芙蓉王?对吃拿卡要必须零容忍
  • 上海建筑领域绿色发展2025年工作要点发布
  • 中国科学院院士徐春明不再担任山东石油化工学院校长