• 三、Redis数据结构动态字符串SDS(simple dynamic string)


    1、Redis前言

    C语言的传统的字符串(以’\0’结尾的字符数组)表示。

    SDS提升字符串的操作效率,同时也可以保存二进制数据。因为传统C字符串符合ASCII编码,这种编码的操作的特点就是:遇零则止 。即,当读一个字符串时,只要遇到’\0’结尾,就认为到达末尾,就忽略’\0’结尾以后的所有字符。因此,如果传统字符串保存图片,视频等二进制文件,操作文件时就被截断了。举例几个常见命令,直观感受下字符串的操作:

    127.0.0.1:6379> set str1 Redis
    OK
    127.0.0.1:6379> get str1
    "Redis"
    127.0.0.1:6379> type str1
    string
    127.0.0.1:6379> strlen str1
    (integer) 5

    详细的相关数据类型的命令操作可以参考查询如下网址:

    Redis命令中心(Redis commands) -- Redis中国用户组(CRUG)

    2、SDS源码,主要熟悉下sds.c和sds.h文件即可

    typedef char *sds; // sds兼容传统C风格字符串
    struct __attribute__ ((__packed__)) sdshdr8 {  // attribute((packed))作用是取消编译阶段的内存优化对齐功能
    uint8_t len; /* used */ // 字符串的长度
    uint8_t alloc;
    /* excluding the header and null terminator */ // buf指针分配空间的大小
    unsigned
    char flags; /* 3 lsb of type, 5 unused bits */ // 该字符串的类型 s[-1]就是sdshdr中flags变量
    char buf[]; // sds是指向sdshdr结构buf成员的

    SDS内存空间扩容机制:

    sds sdsMakeRoomFor(sds s, size_t addlen) {
        void *sh, *newsh;
        size_t avail = sdsavail(s); // 剩余容量
        size_t len, newlen, reqlen;
        char type, oldtype = s[-1] & SDS_TYPE_MASK;
        int hdrlen;
    
        /* Return ASAP if there is enough space left. */
        if (avail >= addlen) return s; // 长度足够无需扩容
    
        len = sdslen(s); // 字符串长度
        sh = (char*)s-sdsHdrSize(oldtype);
        reqlen = newlen = (len+addlen); // 扩容后的新字符串长度
        assert(newlen > len);   /* Catch size_t overflow */
        if (newlen < SDS_MAX_PREALLOC) // #define SDS_MAX_PREALLOC (1024*1024) 分配内存最大长度为 1MB
            newlen *= 2; // 扩容翻倍
        else
            newlen += SDS_MAX_PREALLOC; // 加一个最大长度
    
        type = sdsReqType(newlen);
       .....return s;
    }

    SDS内存空间释放机制:

    void sdsclear(sds s) {
        sdssetlen(s, 0);
        s[0] = '\0';
    }
    
    
    static inline void sdssetlen(sds s, size_t newlen) { // inline关键字仅仅是建议编译器做内联展开处理,而不是强制
        unsigned char flags = s[-1];
        switch(flags&SDS_TYPE_MASK) {
            case SDS_TYPE_5:
                {
                    unsigned char *fp = ((unsigned char*)s)-1;
                    *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
                }
                break;
            case SDS_TYPE_8:
                SDS_HDR(8,s)->len = newlen; // 字符串空间变为0 
                break;
            case SDS_TYPE_16:
                SDS_HDR(16,s)->len = newlen;
                break;
            ....
        }
    }

    总结一下:本文主要了解下动态字符串的结构和内存空间的扩容和释放机制。针对具体方法函数的使用,有问题时再详细看下源码这里就不做过多的赘述了。

  • 相关阅读:
    java基础 Collections.sort的两种用法
    Mysql常用命令详解
    2、Java并发编程:如何创建线程
    JAR、WAR、EAR的使用和区别
    区分Oracle的数据库,实例,服务名,SID
    Mysql 启动运行
    3、Java并发编程:Thread类的使用
    1、Java多线程基础:进程和线程之由来
    文件上传利器SWFUpload使用指南
    网络矩阵
  • 原文地址:https://www.cnblogs.com/chch213/p/16256143.html
Copyright © 2020-2023  润新知