设为首页 收藏本站
查看: 947|回复: 0

[经验分享] redis源码笔记-sds

[复制链接]

尚未签到

发表于 2015-7-20 09:14:09 | 显示全部楼层 |阅读模式
  sds和adlist一样,是redis的基础数据结构之一,是其为自身实现的字符串类型。A C dynamic strings library
  sds.h



1 #ifndef __SDS_H
2 #define __SDS_H
3
4 #define SDS_MAX_PREALLOC (1024*1024)       //字符串最大的预分配长度是1M
5
6 #include
7 #include
8
9 typedef char *sds;          //sds本身被typedef为char*,是后续绝大部分函数的参数(之一)
10
11 struct sdshdr {
12     int len;
13     int free;
14     char buf[];
15 };      //字符串的数据结构,记录了字符串长度、空闲字节,以及指向实际存储数据buf的指针
16
17 static inline size_t sdslen(const sds s) {
18     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
19     return sh->len;
20 }       //尽管在不考虑typedef的前提下,但从函数参数来看,非引用/指针类型,但毕竟底层实现是char*,因此作者也将所有函数内不改变的参数标记为了const
           //传的参数指向实际字符串,因此需要先取得数据结构头的位置,然后返回字符串长度;
21
22 static inline size_t sdsavail(const sds s) {
23     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
24     return sh->free;
25 }       //同上,返回的是空闲字节数
26
27 sds sdsnewlen(const void *init, size_t initlen);
28 sds sdsnew(const char *init);
29 sds sdsempty(); //三个初始化函数
30 size_t sdslen(const sds s);    //上述内联函数的函数声明
31 sds sdsdup(const sds s);       //字符串复制函数
32 void sdsfree(sds s);           
33 size_t sdsavail(sds s);
34 sds sdsgrowzero(sds s, size_t len);
35 sds sdscatlen(sds s, void *t, size_t len);
36 sds sdscat(sds s, char *t);
37 sds sdscatsds(sds s, sds t);
38 sds sdscpylen(sds s, char *t, size_t len);
39 sds sdscpy(sds s, char *t);
40
41 sds sdscatvprintf(sds s, const char *fmt, va_list ap);
42 #ifdef __GNUC__
43 sds sdscatprintf(sds s, const char *fmt, ...)
44     __attribute__((format(printf, 2, 3)));
45 #else
46 sds sdscatprintf(sds s, const char *fmt, ...);
47 #endif     //为啥这么写,没看懂。。非重点,暂且略过
48
49 sds sdstrim(sds s, const char *cset);
50 sds sdsrange(sds s, int start, int end);
51 void sdsupdatelen(sds s);
52 void sdsclear(sds s);
53 int sdscmp(sds s1, sds s2);
54 sds *sdssplitlen(char *s, int len, char *sep, int seplen, int *count);
55 void sdsfreesplitres(sds *tokens, int count);
56 void sdstolower(sds s);
57 void sdstoupper(sds s);
58 sds sdsfromlonglong(long long value);
59 sds sdscatrepr(sds s, char *p, size_t len);
60 sds *sdssplitargs(char *line, int *argc);
61
62 #endif
对libc的string.h库熟悉的同学,根据上述函数名也大概能猜出来函数的作用,就不一一写了,具体参见sds.c的实现部分。
  sds.c



看似很长,但绝大部分代码都很通俗易懂,大家不要恐惧。
  1 #define SDS_ABORT_ON_OOM     //在内存不够时的默认动作是终止进程(abort)
  2
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include "sds.h"
  8 #include "zmalloc.h"     //同样用na个简单封装的内存分配库
  9
10 static void sdsOomAbort(void) {
11     fprintf(stderr,"SDS: Out Of Memory (SDS_ABORT_ON_OOM defined)\n");
12     abort();
13 }                        //abort前作的唯一的善后工作是告诉大家自己是由于在SDS时内存不够挂掉的
14
15 sds sdsnewlen(const void *init, size_t initlen) {
16     struct sdshdr *sh;
17
18     sh = zmalloc(sizeof(struct sdshdr)+initlen+1); //所分配的长度是头的长度sizeof(struct sdshdr)+字符串长度initlen+‘\0’的一个字节
                                                       //注意这里的sizeof(struct sdshdr)长度为8,剩下的都直接存在了sh->buf上
19 #ifdef SDS_ABORT_ON_OOM
20     if (sh == NULL) sdsOomAbort();
21 #else
22     if (sh == NULL) return NULL;  //如果没有定义SDS_ABORT_ON_OOM,简单的返回NULL
23 #endif
24     sh->len = initlen;
25     sh->free = 0;                 //创建字符串时free的长度是0
26     if (initlen) {
27         if (init) memcpy(sh->buf, init, initlen);   //若参数init不等于NULL,则拷贝initlen长度给sh->buf
28         else memset(sh->buf,0,initlen);             //否则这块缓冲区被赋值为0
29     }
30     sh->buf[initlen] = '\0';       //用'\0'为字符串结尾
31     return (char*)sh->buf;         //返回的是实际字符串的指针
32 }
33
34 sds sdsempty(void) {
35     return sdsnewlen("",0);         //注意""字符串常量并不代表空,但0表示空了   
36 }
37
38 sds sdsnew(const char *init) {
39     size_t initlen = (init == NULL) ? 0 : strlen(init);
40     return sdsnewlen(init, initlen);
41 }
42
43 sds sdsdup(const sds s) {
44     return sdsnewlen(s, sdslen(s));
45 }                                    //dup复制函数也是调用newlen实现的
46
47 void sdsfree(sds s) {
48     if (s == NULL) return;
49     zfree(s-sizeof(struct sdshdr));
50 }                                    //释放链接要先找到sds的header
51
52 void sdsupdatelen(sds s) {
53     struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
54     int reallen = strlen(s);
55     sh->free += (sh->len-reallen);
56     sh->len = reallen;
57 }                                    //更新长度是更新header的len和free两个字段
58
59 void sdsclear(sds s) {
60     struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
61     sh->free += sh->len;
62     sh->len = 0;
63     sh->buf[0] = '\0';
64 }                                     //将所有的len都给free,但并未释放内存空间
65
66 static sds sdsMakeRoomFor(sds s, size_t addlen) {
67     struct sdshdr *sh, *newsh;
68     size_t free = sdsavail(s);
69     size_t len, newlen;
70
71     if (free >= addlen) return s;         //如果剩余空间仍足够,则直接将传进来的参数s返回
72     len = sdslen(s);
73     sh = (void*) (s-(sizeof(struct sdshdr)));
74     newlen = (len+addlen);
75     if (newlen < SDS_MAX_PREALLOC)
76         newlen *= 2;
77     else
78         newlen += SDS_MAX_PREALLOC;        //在为newlen增加了addlen这么长的空余空间的同时,也在这次操作中额外申请了内存空间,当newlen小于系统定义的单次最大分配内存时,额外分配的长度是newlen,负责多分配SDS_MAX_PREALLOC这么大的空间。熟悉std::vector实现的同学对这种分配机制一定似曾相识。这里基于这样一种假设,这次make room的sds,也很有可能在不久的将来再次make room,所以预先分配了空间
79     newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);  //realloc保证原来分配空间的数据会拷贝过去,但执行此操作后,sh指针就失效了
80 #ifdef SDS_ABORT_ON_OOM
81     if (newsh == NULL) sdsOomAbort();
82 #else
83     if (newsh == NULL) return NULL;
84 #endif
85
86     newsh->free = newlen - len;
87     return newsh->buf;
88 }
89
90 /* Grow the sds to have the specified length. Bytes that were not part of
91  * the original length of the sds will be set to zero. */
92 sds sdsgrowzero(sds s, size_t len) {   //len是一个to 参数,表示增长到
93     struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
94     size_t totlen, curlen = sh->len;
95
96     if (len = '0' && c = 'a' && c = 'A' && c  0)
618
619         sdsfree(y);
620         sdsfree(x);
621         x = sdsnew("bar");
622         y = sdsnew("bar");
623         test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0)
624
625         sdsfree(y);
626         sdsfree(x);
627         x = sdsnew("aar");
628         y = sdsnew("bar");
629         test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0)
630     }
631     test_report()
632 }
633 #endif

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-88467-1-1.html 上篇帖子: C++ Redis mset 二进制数据接口封装方案 下篇帖子: 在多台服务器上简单实现Redis的数据主从复制
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表