美文网首页Redis源码学习笔记
Redis源码学习基本数据结构之动态字符串sds

Redis源码学习基本数据结构之动态字符串sds

作者: lixin_karl | 来源:发表于2019-04-02 17:04 被阅读0次
    一、sds是什么

    字符串是Redis中最为常见的数据存储类型,其底层实现是简单动态字符串sds(simple dynamic string),是可以修改的字符串。它的内存管理模式类似于c++中的vector,它采用预分配冗余空间的方式来减少内存的频繁分配。关联源码sds.c/sds.h

    typedef char *sds 
    

    sds实际上就是一个char指针。它来自于跟它相关的结构体的一部分,其中一共有5个结构体相关根据以下5个值判断属于哪个结构体

    #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
    

    其中,SDS_TYPE_5 目前没有用,会用SDS_TYPE_8来代替。它是根据数据的长度来决定使用什么结构体的,对于SDS_TYPE_8 对应的结构体为

    struct sdshdr8{
        uint8_t len; /*使用了多少 即数据长度 类似vector size()*/
        uint8_t alloc; /* 申请了多少内存 类似于vector capacity()*/
        unsigned char flags; /* 具体的sdshdr类型 可以节省内存*/
        char buf[];/* 实际数据也是sds开始的地址 */
    }
    

    二、sds特点

    • SDS是在C字符串的基础上进行了一些包装,使得它更符合Redis的使用场景。sds获取长度的时间复杂度为O(1)。
    • 减少修改字符串时内存重分配的次数,其内存增加模式类似与c++的vector每次增长两倍但是每次最多增长1024*1024字节。
    • SDS对于存储的数据没有任何限制,二进制安全。 普通的c字符串与到'\0'则结束。所以sds是可以存储任意类型的数据的。
      三 sds.h/sds.c源码
    sds sdsnewlen(const void *init, size_t initlen);//申请内存申请内存的长度为(对应结构体的长度+1+initlen) 最后一个字节会赋值'\0',这点可以保证对普通字符串的兼容
    sds sdsnew(const char *init);//根据一个普通字符串在创建sds
    sds sdsempty(void);//创建一个空的sds
    sds sdsdup(const sds s);//复制一个sds 重新申请内存
    
    void sdsfree(sds s);//释放申请出来的内存
    
    sds sdsgrowzero(sds s, size_t len);//sds动态空间增加到特定的长度,最多申请SDS_MAX_PREALLOC
    sds sdscatlen(sds s, const void *t, size_t len);//字符串拼接
    sds sdscat(sds s, const char *t);//字符串拼接
    sds sdscatsds(sds s, const sds t);//sds拼接
    sds sdscpylen(sds s, const char *t, size_t len);//sds复制
    sds sdscpy(sds s, const char *t);//sds复制
    sds sdscatvprintf(sds s, const char *fmt, va_list ap);//字符串拼接
    sds sdscatfmt(sds s, char const *fmt, ...);//字符串拼接
    
    sds sdstrim(sds s, const char *cset);//移除s中是 cset中的字符
    
    void sdsrange(sds s, ssize_t start, ssize_t end);//sds子字符串
    
    void sdsupdatelen(sds s);//字符串实际长度
    
    void sdsclear(sds s);//字符串清理,相关数据赋值为0
    
    int sdscmp(const sds s1, const sds s2);//字符串比较
    sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);//s中以sep为分隔标志,返回分隔后的sds数组
    
    void sdsfreesplitres(sds *tokens, int count);//将分隔出来的字符串数组释放掉内存
    
    void sdstolower(sds s);//都变成小写字符
    void sdstoupper(sds s);//都变成大写字符
    
    sds sdsfromlonglong(long long value);//longlong变成sds
    
    sds sdscatrepr(sds s, const char *p, size_t len);//一些特殊字符的拼接
    sds *sdssplitargs(const char *line, int *argc);//将line分割argc个sds数组
    
    sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);//把sds中出现在from中的字符替换为to中的对应位置的字符
    sds sdsjoin(char **argv, int argc, char *sep);//字符串连接
    sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);//字符串连接
    
    /* 底层用户调用api */
    sds sdsMakeRoomFor(sds s, size_t addlen);//重新申请内存
    void sdsIncrLen(sds s, ssize_t incr);
    sds sdsRemoveFreeSpace(sds s);//移除冗余的空间,增加内存的效率
    size_t sdsAllocSize(sds s);//返回总的申请的内存
    void *sdsAllocPtr(sds s);//返回最初申请的一段内存的起始位置
    
    
    void *sds_malloc(size_t size);///申请内存
    void *sds_realloc(void *ptr, size_t size);//重新申请内存
    void sds_free(void *ptr);//释放内存
    

    相关文章

      网友评论

        本文标题:Redis源码学习基本数据结构之动态字符串sds

        本文链接:https://www.haomeiwen.com/subject/eguwbqtx.html