【redis】基本数据结构简单源码解析

(我贴的代码是本机6.2.1版本)

string:SDS(简单动态字符串)

redis是以c语言编写,但是redis的字符串没有直接使用C语言的以null结尾的字符串,而是采用SDS(Simple Dynamic String:简单动态字符串)

struct SDS<T> {
 T capacity; // 数组容量Redis  字符串的长度不得超过 512M 字节。创建字符串时 len 和 capacity 一样长,不会多分配冗余空间,这是因为绝大多数场景下我们不会使用 append 操作来修改字符串。
 T len; // 数组长度  因为把长度写在头部,不用像C语言一样以\0识别字符串结束符,所以sds是二进制安全的
 byte flags; // sds类型,5 8 16 32 64位
 byte[] content; // 数组内容
}
//追加字符串append
sds sdscatlen(sds s, const void *t, size_t len) {
    size_t curlen = sdslen(s);//原字符串长度
    s = sdsMakeRoomFor(s,len);//空间调整
    if (s == NULL) return NULL;//内存不足
    memcpy(s+curlen, t, len);//追加字符串到当前的content数组中
    sdssetlen(s, curlen+len);//设置追加后的长度值
    s[curlen+len] = '\0';//与C语言字符串一致,可以printf()调试、便于直接使用 glibc 的字符串处理函数
    return s;
}

//按需调整空间
sds 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;
    size_t usable;

    /* 空间足够就直接返回新字符串 */
    if (avail >= addlen) return s;

    //接下来是空间不足的操作
    len = sdslen(s);
    sh = (char*)s-sdsHdrSize(oldtype);
    newlen = (len+addlen);
    assert(newlen > len);   /* Catch size_t overflow */
    if (newlen < SDS_MAX_PREALLOC) //小于SDS_MAX_PREALLOC(1M)时,每次分配的空间加倍
        newlen *= 2;
    else //大于SDS_MAX_PREALLOC后,每次加1M
        newlen += SDS_MAX_PREALLOC;

    type = sdsReqType(newlen);//根据长度划分新字符串所属的SDS数据类型

    /* 不要使用类型5:用户正在追加字符串,而类型5无法记住空格,因此必须在每次追加操作时调用sdsMakeRoomFor() */
    if (type == SDS_TYPE_5) type = SDS_TYPE_8;

    hdrlen = sdsHdrSize(type);//根据所属SDS数据类型计算所占内存
    assert(hdrlen + newlen + 1 > len);  /* Catch size_t overflow */
    if (oldtype==type) {//所属的SDS数据类型不变时
        newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+hdrlen;
    } else {
        /* Since the header size changes, need to move the string forward,
         * and can't use realloc 
如果类型发生变化,地址内容不可复用,所以找新的空间
*/
        newsh = s_malloc_usable(hdrlen+newlen+1, &usable);
        if (newsh == NULL) return NULL;
        memcpy((char*)newsh+hdrlen, s, len+1);//将s复制到(char*)newsh+hdrlen  +1是复制上\0
        s_free(sh);//释放前面的内存空间
        s = (char*)newsh+hdrlen;//调整s开始的位置,即地址空间指向新的buf开始的位置
        s[-1] = type;//flag位置
        sdssetlen(s, len);//分配len的值
    }
    usable = usable-hdrlen-1;
    if (usable > sdsTypeMaxSize(type))//实际占用不能大于所属SDS数据类型最长占用字节
        usable = sdsTypeMaxSize(type);
    sdssetalloc(s, usable);//(根据类型)设置sds字符串容量
    return s;
}<
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值