sds(Simple Dynamic String): 它其实就是普通的字符串,只是在每个字符串的前面加了一个管理用的头部,相关类型结构的定义如下

typedef char *sds;/* Note: sdshdr5 is never used, we just access the flags byte directly.* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used */uint8_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};

从定义上看,5种定义对应了最大长度不同的字符串,定义这5种不同的类型可能是为了尽量减少sdshdr占用的空间。
为了分sdshdr是哪一种类型,它在每一种定义中都加上了一个8bit的flags字段,用其中的低3位标识sdshdr的类型。
为了能从buf直接找到到flags,所以在定义时必须用((__packed__))强制不要按字节对齐,这样不管是哪种类型的hdr,都可以用buf[-1]找到对应的flags

相应地,sds内部实现了一些基本的操作,主要看看sdsnewlen和sdsMakeRoomFor这两个函数,大概就能知道sds的内部操作方式以及内存分配的方式。

sdsnewlen是根据指定内容和指定长度创建一个新的sds。这段代码有个bug,见下面的注释

/* Create a new sds string with the content specified by the 'init' pointer* and 'initlen'.* If NULL is used for 'init' the string is initialized with zero bytes.** The string is always null-termined (all the sds strings are, always) so* even if you create an sds string with:** mystring = sdsnewlen("abc",3);** You can print the string with printf() as there is an implicit \0 at the* end of the string. However the string is binary safe and can contain* \0 characters in the middle, as the length is stored in the sds header. */
sds sdsnewlen(const void *init, size_t initlen) {void *sh;sds s;/* 根据要求的长度返回合适的类型 */char type = sdsReqType(initlen);/* Empty strings are usually created in order to append. Use type 8* since type 5 is not good at this. *//* type 5 不太适合动态扩展,默认用8 */if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;/* 不同的type对应的sdshdr的大小不一样 */int hdrlen = sdsHdrSize(type);unsigned char *fp; /* flags pointer. */sh = s_malloc(hdrlen+initlen+1);/* 如果没有指定初始内容,则将新分配的空间清0 */if (!init)memset(sh, 0, hdrlen+initlen+1);/* 这个判断应该放到前面吧,不然上面memset会导致程序挂掉 */if (sh == NULL) return NULL;/* 找到buf的位置,也是要返回给caller的 */s = (char*)sh+hdrlen;/* 填充对应sdshdr的flags字段 */fp = ((unsigned char*)s)-1;switch(type) {case SDS_TYPE_5: {*fp = type | (initlen << SDS_TYPE_BITS);break;}case SDS_TYPE_8: {SDS_HDR_VAR(8,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}case SDS_TYPE_16: {SDS_HDR_VAR(16,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}case SDS_TYPE_32: {SDS_HDR_VAR(32,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}case SDS_TYPE_64: {SDS_HDR_VAR(64,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}}/* 指定了初始内容并且内容非空,填充到新分配的空间当中 */if (initlen && init)memcpy(s, init, initlen);s[initlen] = '\0';return s;
}

sdsMakeRoomFor是在已存在的sds上动态扩展其空间,可以很清楚地看到扩展时使用的策略。

/* 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. */
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;/* Return ASAP if there is enough space left. */if (avail >= addlen) return s;len = sdslen(s);sh = (char*)s-sdsHdrSize(oldtype);newlen = (len+addlen);/* 新长度小于1M就double,否则就增加1M */if (newlen < SDS_MAX_PREALLOC)newlen *= 2;elsenewlen += SDS_MAX_PREALLOC;/* newlen对应的sdshdr的类型 */type = sdsReqType(newlen);/* Don't use type 5: the user is appending to the string and type 5 is* not able to remember empty space, so sdsMakeRoomFor() must be called* at every appending operation. *//* type 5不适合做扩展 */if (type == SDS_TYPE_5) type = SDS_TYPE_8;hdrlen = sdsHdrSize(type);/* 如果前后type不需要变化,则直接使用realloc* 否则,分配新的空间,拷贝原来的内容,释放原来的空间*/if (oldtype==type) {newsh = s_realloc(sh, hdrlen+newlen+1);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(hdrlen+newlen+1);if (newsh == NULL) return NULL;memcpy((char*)newsh+hdrlen, s, len+1);s_free(sh);s = (char*)newsh+hdrlen;s[-1] = type;sdssetlen(s, len);}/* 设置sdshdr的alloc字段(type 5除外) */sdssetalloc(s, newlen);return s;
}

转载于:https://www.cnblogs.com/flypighhblog/p/7748186.html

redis学习笔记(一): sds相关推荐

  1. Redis(学习笔记)

    Redis学习笔记 1.NoSQL数据库 1.1解决的问题 1.1.1解决CPU及内存压力 1.1.2解决IO压力 1.2NoSQL数据库概述 1.2.1什么是NoSQL数据库 1.2.2适用与不适用 ...

  2. Redis学习笔记 - 数据类型与API(1)Key

    Redis学习笔记 - 数据类型与API(1)Key Key相关命令 1. 常用命令 命令 含义 时间复杂度 keys 查找所有符合给定模式 pattern 的 key O(N), N 为数据库中 k ...

  3. Redis学习笔记~Redis在windows环境下的安装

    Redis是一个key-value的存储系统,它最大的特点就是可以将数据序列化到文件中. redis存储在服务器的内存或者文件中,它不是session,不是cookies,它只是个更安全,更稳定,更可 ...

  4. redis学习笔记-持久化

    redis学习笔记-持久化 前言 redis持久化有两种方式:RDB和AOF.分别对应着全量复制和增量复制.深刻理解各自的实现方式及适用场景对redis的使用和运维十分重要.下面就分别介绍. RDB持 ...

  5. StackExchange.Redis学习笔记(五) 发布和订阅

    StackExchange.Redis学习笔记(五) 发布和订阅 原文:StackExchange.Redis学习笔记(五) 发布和订阅 Redis命令中的Pub/Sub Redis在 2.0之后的版 ...

  6. Redis学习笔记~分布式的Pub/Sub模式

    redis的客户端有很多,这次用它的pub/sub发布与订阅我选择了StackExchange.Redis,发布与订阅大家应该很清楚了,首先一个订阅者,订阅一个服务,服务执行一些处理程序(可能是写个日 ...

  7. Redis学习笔记——SpringDataRedis的使用

    与Spring集成 我需要哪些jar包? <dependency><groupId>org.springframework.data</groupId><ar ...

  8. Redis学习笔记(五)——持久化及redis.conf配置文件叙述

    对于日常使用来说,学习完SpringBoot集成Redis就够我们工作中使用了,但是既然学习了,我们就学习一些Redis的配置及概念,使我们可以更深层次的理解Redis,以及增强我们的面试成功概率,接 ...

  9. Redis学习笔记1-理论篇

    目录 1,Redis 数据类型的底层结构 1.1,Redis 中的数据类型 1.2,全局哈希表 1.3,数据类型的底层结构 1.4,哈希冲突 1.5,rehash 操作 2,Redis 的 IO 模型 ...

最新文章

  1. Payment Terms 付款条件
  2. [云炬创业管理笔记]第一章测试1
  3. 有关Quartz.NET,与一线码农大佬对个线?
  4. 训练日志 2019.3.7
  5. 史上最新最全的来自成都的Azure系列文章,助你上云!老少皆宜,童叟无欺!
  6. Flutter 成功在鸿蒙上运行;微信 8.0 发布;支付宝和微信支付达到反垄断标准 | 极客头条...
  7. 想自学python看哪位的视频比较好-python学习视频好的有哪些
  8. python所有软件-如何在Python中列出所有已安装的软件包及其版本?
  9. 语音识别系统市场前景及发展趋势
  10. “咏刚的家”全新改版
  11. Atitit 财政支出学习心得 attilax总结
  12. 谷粒商城--分布式基础篇1
  13. WSJ0中的wv文件如何转换为wav文件
  14. wifi无线破解记录
  15. 华科计算机系教学大纲,《批判性思维》课程教学大纲
  16. 解决浏览器被好123劫持主页的问题。
  17. SOJ4480 Easy Problem IV (并查集)
  18. 【CSS选择器】CSS选择器有哪些?如何选择合适的使用?各类选择器的优劣势是什么?
  19. Rails启动项一些参数的调整
  20. 100个相见恨晚的Python库(建议收藏)

热门文章

  1. 每天一个linux命令(19):find 命令概览
  2. Android模块化面向接口编程,讲的明明白白!
  3. 【迁移学习(Transfer L)全面指南】方差、协方差和Pearson相关系数的关系
  4. Keras【Deep Learning With Python】—Keras基础
  5. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY9-聚类
  6. python二进制相加
  7. linux adb 点击屏幕,ADB 操作命令(二)
  8. apache配置支持mysql_Apache Kylin | 建立 JDBC 数据源
  9. 网络推广营销浅析网站在优化中流量突然减少了是为什么?
  10. 如何通过简化标题来提升核心关键词排名?