最近突然一时兴起,开始看redis的源代码实现。《redis源码阅读笔记》系列将记录下我阅读redis源码的一些笔记和心得。
第一篇我们从最简单的sds(Simple Dynamic String,简单动态字符串)开始啦。
网上已经有一些很好的代码解析的文章了,所以我们可以参考一下
1.高层视角解读
SDS 的定义
SDS 与 C 字符串的区别
比起C字符串,SDS具有以下优点:
- 常数复杂度获取字符串长度。
- 杜绝缓冲区溢出。
- 减少修改字符串长度时所需的内存重分配次数。
- 二进制安全。
- 兼容部分C字符串函数。
2.底层视角解读
接下来就可以阅读源码了(sds.h,sds.c两个文件)。
然后结合这篇文章看,
Redis String类型实现原理
3.疑难点解惑
Q:为何代码中是int,解释中说long型。原文:“巧合的是两个long型的长度加起来正好是struct sdshdr的长度。”
A:好吧,其实C语言里,32位系统上,int和long是一样的,这两个都是32位,而long long型才是64位的。
sizeoftest.c运行结果
sizeof(int) = 4
sizeof(long) = 4
sizeof(long long) = 8
sizeof(size_t) = 4
sizeof(char *) = 4
Q:size_t什么意思
A:size_t 类型定义在cstddef头文件中,它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。
看一下在stddef.h中的定义
#define __SIZE_TYPE__ long unsigned int
在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。换句话说,一个指针可以被安全地放进为size_t类型。
C函数库中strlen的定义
size_t strlen (const char *s)
这样定义意思是返回的数肯定是大于等于0的,所以一般都用size_t这个类型。所以还是习惯,大师都这么用,所以就这么写。
Q:sdslen函数的定义里inline什么意思
A:内联函数用来建议编译器将指定的函数代码插入并取代每一处调用该函数的地方,从而节省了调用函数带来的额外开销。类似于写程序时将同样的代码复制粘贴到多处。好处是减少执行时间,坏处就是增加了重复代码占用的空间。
Q:static什么意思
A:static意味着该函数只在这个文件中可见,还意味着可以在其他文件中定义同名函数。
Q:为什么static inline一起用
A:这个我查了几篇文章,解释的比较复杂,看不大懂。简单的说,这个成了C99里的一个习惯了吧,大家都这么写,你就这么写吧,而且static inline函数一般都是定义在头文件(h)中。这样包含这个h文件的c文件都将拥有这个函数定义。
Q:数据空间的char buf[]什么意思,能改成char* buf吗?
A:有区别。这个比较复杂了,char buf[]是flexible array member,是一个编程技巧,
http://c-faq.com/struct/structhack.html
不是一句话能讲明白的。请耐心看完下面的解释。
c99之 柔性数组成员 flexible array member
请参考这篇文章,我不重复复制了。
c99之 柔性数组成员
我做了一个试验,将原来的代码片段改用char* buf的形式重写了。
比较一下和原来的不同
sds1test.c
memcpy(sh->buf, str1, strlen(str1));
sh->buf[initlen] = '\0';
sds2test.c
strcpy(sh + 1, str1);
sh->buf = sh + 1;
sds1test.c运行结果
sizeof(struct sdshdr) = 8
strlen(str2) = 5
address of sh = 537335688
address of str2 = 537335696
str2 - sh = 8
sdslen = 5
sds2test.c运行结果
sizeof(struct sdshdr) = 12
strlen(str2) = 5
address of sh = 537335688
address of str2 = 537335700
str2 - sh = 12
sdslen = 5
可以看到改成char* buf的形式后,struct体占用空间多了4个字节,而且给buf的赋值要用sh->buf = sh + 1这种古怪的形式,不方便。
这个技巧用的真是令人拍案叫绝哪!
上图左边是原来redis的实现,struct体只占用8个字节,右边是改成char* buf的形式后,struct体占用12个字节。
到此,相信读者对“巧合的是两个long型的长度加起来正好是struct sdshdr的长度。” 这句话就可以理解了。
最后看一下这个网页的解释,可以看到这是一个经常用到的技巧。
comp.lang.c FAQ list · Question 2.6
附件是我的测试代码,可以下载下来运行,细细体会flexible array member的精妙。
- 大小: 31 KB
分享到:
相关推荐
`bitfieldtest.c`可能是Redis源码中用于测试位字段(bitfield)功能的代码。位字段允许在单个字符串对象中高效存储和操作单个比特,这对于节省内存和执行位操作非常有用。测试文件通常包含了各种边界条件和异常情况...
这份“redis阅读笔记.zip”压缩包很可能是某位开发者在深入研究Redis源码后整理的心得体会,以Windows画图的形式记录下来,便于理解和记忆。 Redis的核心知识点包括: 1. 数据结构:Redis中的数据类型非常丰富,如...
长期更新Redis6.0原始阅读笔记 目前进度: 内存管理,源文件为zmalloc.h,zmalloc.c SDS(简单动态字符串),源文件为sdsalloc.h,sds.h,sds.c 链表,源文件为adlist.h,adlist.c 字典,源文件为dict.h,dict....
"reading-redis:redis原始注解和阅读笔记"很可能是一份详细解析Redis源码的文档,帮助开发者深入理解其内部机制和工作原理。在Redis的源代码中,我们可以找到关于数据结构、网络通信、命令处理等方面的知识点。 1. ...
1,redis选主结束后,是否添加新主节点数据恢复流程(新主例程数据并非所有从例程中数据更新,是否需要与最新的从异步进行数据同步),而不是直接将主数据同步到从基线。 阅读计划和进度: 第一阶段: 阅读redis的...
`read-redis-src`项目是一个旨在帮助开发者深入理解Redis源码的学习资源,通过阅读和分析源代码,可以提升对Redis工作原理的理解。 在开始阅读Redis源码之前,我们需要了解一些基础知识: 1. **Redis的数据结构**...