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 ...
随机推荐
- js constructor 和 instanceof
说到这两个属性,那不得不说一下_proto_这个属性,通常这个属性是隐藏属性,是不允许被暴露的,而某些浏览器为了开发者能够很好的理解,而将这个属性暴露出来,比如Mozilla FireFox,这就是为 ...
- python面向对象中类对象、实例对象、类变量、实例变量、类方法、实例方法、静态方法
1. 类对象和实例对象 Python中一切皆对象,Python类本身也是一种对象,类定义完成后,会在当前作用域中定义一个以类名为名字的命名空间.类对象具有以下两种操作: 可以通过“类名()”的方式实例 ...
- JAVAEE——宜立方商城04:图片服务器FastDFS、富文本编辑器KindEditor、商品添加功能完成
1. 学习计划 1.图片上传 a) 图片服务器FastDFS b) 图片上传功能实现 2.富文本编辑器的使用KindEditor 3.商品添加功能完成 2. 图片服务器的安装 1.存储空间可扩展. 2 ...
- [java] java中的初始化顺序
先看程序: package init_cls; class A{ {System.out.println("i am in the class A!");} static { Sy ...
- mysql查询语句 和 多表关联查询 以及 子查询
原文地址: http://blog.csdn.net/github_37767025/article/details/67636061 1.查询一张表: select * from 表名: 2.查询指 ...
- 算法转AI平台工程师记录-0
--- vim源码安装: 1. git clone https://github.com/vim/vim.git 2. cd vim && ./configure --prefix=x ...
- 【POJ】2151:Check the difficulty of problems【概率DP】
Check the difficulty of problems Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8903 ...
- 拆分Cocos2dx渲染部分代码
纹理实现 思想 这个是Cocos2dx的渲染部分的最基本的实现,被我拆分到mac上,但是并不是用的EGLContext,而是搭配glfw,还有soil第三方图形库. 实现 // // main.cpp ...
- Java中日期类型和mysql中日期类型进行整合
1. java与mysql中日期.时间类型总结: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mysql(版本:5.1.50)的时间日期类型如下: da ...
- Codeforces Round #361 (Div. 2) B. Mike and Shortcuts bfs
B. Mike and Shortcuts 题目连接: http://www.codeforces.com/contest/689/problem/B Description Recently, Mi ...