Redis设计与实现读书笔记——简单动态字符串
前言
数据类型定义
- // 字符串类型的别名
- typedef char *sds;
另一个是 sdshdr:
- // 持有sds的结构
- struct sdshdr {
- // buf中已经被使用的字符串空间数量
- int len;
- // buf中预留字符串的空间数量
- int free;
- // 实际存储字符串的地方
- char buf[];
- };
其中,sds只是字符串数组类型char*的别名,而sdshdr用于持有和保存sds的信息
将sdshdr用作sds
- sds sdsnewlen(const void *init, size_t initlen)
- {
- struct sdshdr *sh;
- if (init) {
- // 创建
- sh = malloc(sizeof(struct sdshdr) + initlen + 1);
- } else {
- // 重分配
- sh = calloc(1, sizeof(struct sdshdr) + initlen + 1);
- }
- if (sh == NULL) return NULL;
- sh->len = initlen;
- sh->free = 0; // 刚开始free为0
- if (initlen && init) {
- memcpy(sh->buf, init, initlen);
- }
- sh->buf[initlen] = '\0';
- // 只返回sh->buf这个字符串部分
- return (char *)sh->buf;
- }
通过使用变量持有一个sds的值,在遇到那些只处理sds值本身的函数时,可以直接将sds传给它们。比如说,sdstoupper 函数就是其中的一个例子:
- static inline size_t sdslen(const sds s)
- {
- // 从sds中计算出相应的sdshdr结构
- struct sdshdr *sh = (void *)(s - (sizeof(struct sdshdr)));
- return sh->len;
- }
- void sdstoupper(sds s)
- {
- int len = sdslen(s), j;
- for (j = 0; j < len; j ++)
- s[j] = toupper(s[j]);
- }
这里有一个技巧,通过指针运算,可以从sds值中计算出相应的sdshdr结构:
- static inline size_t sdsavail(const sds s)
- {
- struct sdshdr *sh = (void *)(s - (sizeof(struct sdshdr)));
- return sh->free;
- }
内存分配函数实现
- sds sdsMakeRoomFor(sds s, size_t addlen)
- {
- struct sdshdr *sh, *newsh;
- size_t free = sdsavail(s);
- size_t len, newlen;
- // 预留空间可以满足本地拼接
- if (free >= addlen) return s;
- len = sdslen(s);
- sh = (void *)(s - (sizeof(struct sdshdr)));
- // 设置新sds的字符串长度
- // 这个长度比完成本次拼接实际所需的长度要大
- // 通过预留空间优化下次拼接操作
- newlen = (len + addlen);
- if (newlen < 1024 * 1024)
- newlen *= 2;
- else
- newlen += 1024;
- // 重新分配sdshdr
- newsh = realloc(sh, sizeof(struct sdshdr) + newlen + 1);
- if (newsh == NULL) return NULL;
- newsh->free = newlen - len;
- // 只返回字符串部分
- return newsh->buf;
- }
这种内存分配策略表明,在对sds 值进行扩展(expand)时,总会预留额外的空间,通过花费更多的内存,减少了对内存进行重分配(reallocate)的次数,并优化下次扩展操作的处理速度
- /**
- * 按长度len扩展sds,并将t拼接到sds的末尾
- */
- sds sdscatlen(sds s, const void *t, size_t len)
- {
- struct sdshdr *sh;
- size_t curlen = sdslen(s);
- // O(N)
- s = sdsMakeRoomFor(s, len);
- if (s == NULL) return NULL;
- // 复制
- memcpy(s + curlen, t, len);
- // 更新len和free属性
- sh = (void *)(s - (sizeof(struct sdshdr)));
- sh->len = curlen + len;
- sh->free = sh->free - len;
- // 终结符
- s[curlen + len] = '\0';
- return s;
- }
- /**
- * 将一个char数组拼接到sds 末尾
- */
- sds sdscat(sds s, const char *t)
- {
- return sdscatlen(s, t, strlen(t));
- }
Redis设计与实现读书笔记——简单动态字符串的更多相关文章
- 【笔记】《Redis设计与实现》chapter2 简单动态字符串
------------恢复内容开始------------ 2.1 SDS的定义 struct sdshdr{ // 记录buf数组中已使用字节的数量 // 等于SDS所保存字符串的长度(不含'\0 ...
- 小白的Redis学习(一)-SDS简单动态字符串
本文为读<Redis设计与实现>的记录.该书以Redis2.9讲解Redis相关内容.请注意版本差异. Redis使用C语言实现,他对C语言中的char类型数据进行封装,构建了一种简单动态 ...
- Redis源码解析:01简单动态字符串SDS
Redis没有直接使用C字符串(以'\0'结尾的字符数组),而是构建了一种名为简单动态字符串( simple dynamic string, SDS)的抽象类型,并将SDS用作Redis的默认字符 ...
- Redis 设计与实现读书笔记一 Redis字符串
1 Redis 是C语言实现的 2 C字符串是 /0 结束的字符数组 3 Redis具体的动态字符串实现 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空 ...
- Redis设计与实现读书笔记(二) 链表
链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...
- Redis设计与实现读书笔记(一) SDS
作为redis最基础的底层数据结构之一,SDS提供了许多C风格字符串所不具备的功能,为之后redis内存管理提供了许多方便.它们分别是: 二进制安全 减少字符串长度获取时间复杂度 杜绝字符串溢出 减少 ...
- <<redis设计和实现>>读书笔记
redis如何实现主从同步的高效率?? 主从复制的同步有一个命令数据的同步文本,然后利用两个不同服务器的偏移量来进行进行同步,避免每次都是全部同步(并非会保存所有的命令数据,而是会有一个缓冲区(比如1 ...
- Redis设计与实现读书笔记——双链表
前言 首先,贴一下参考链接: http://www.redisbook.com/en/latest/internal-datastruct/adlist.html, 另外真赞文章的作者,一个90后的小 ...
- Redis 设计与实现读书笔记一 Redis List
list结构体 adlist.h/list(源码位置) /* * 双端链表结构 */ typedef struct list { // 表头节点 listNode *head; // 表尾节点 lis ...
随机推荐
- thinkphp _complex 复合查询 where多个子组实现
SELECT * FROM `user` WHERE ( `mobile` = '13824653465' OR `nickname` = 'evan' OR `openid` = '14545-fd ...
- poj3624 Charm Bracelet(DP,01背包)
题目链接 http://poj.org/problem?id=3624 题意 有n个手镯,每个手镯有两个属性:重量W,需求因子D.还有一个背包,它能装下总重量不超过M的手镯.现在将一些镯子装入背包,求 ...
- hdoj1233 还是畅通工程(Prime || Kruskal)
题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=1233 思路 最小生成树问题,使用Prime算法或者Kruskal算法解决. 代码 Prime算法: # ...
- Python 学习之list和Tuple类型
1.创建list L = ['Adam', 95.5, 'Lisa', 85, 'Bart', 59] print(L) print(L[1],L[3],L[5])#索引 不能越界 正向访问 #95. ...
- servlet文件下载实例剖析
package mypack; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; ...
- idea导入或打开项目配置问题
learn项目遇到问题: 1.IntelliJ Idea编译报错:请使用 -source 7 或更高版本以启用 diamond 运算符 file - project structure或者直接快捷键: ...
- 使用命令行管理virtualBox
最近在鼓捣hadoop,装了几台虚拟机,,总感觉gui启动很别扭,后来发现virtualBox有个headless模式,只想说舒服! 常用命令 VBoxManage startvm name|id - ...
- java UTF8 HEX
private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); public static Str ...
- apache 监控
当前加载模块 [root@controller01 ~]# httpd -lCompiled in modules: core.c mod_so.c http_core.c 当前版本[root@con ...
- BZOJ 4520 [Cqoi2016]K远点对(KD树)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4520 [题目大意] 求K远点对距离 [题解] 修改估价函数为欧式上界估价,对每个点进行 ...