Redis源码阅读——SDS

Redis源码阅读——SDS

参考Redis设计与实现 以及网上博客阅读Redis源码。

SDS相关知识点见读书笔记。

创建和销毁

为了能够对sds进行相关API的测试,因此把sds模块单独提出来。阅读Redis的Makefile发现,编译sds模块需要的源文件包括sds.c, sds.h zmalloc.c

test-sds: sds.c sds.h
        $(REDIS_CC) sds.c zmalloc.c -DSDS_TEST_MAIN $(FINAL_LIBS) -o /tmp/sds_test
        /tmp/sds_test

但是实际编译后会发现会报很多函数未定义的错。原因是redis源码里面sds的内存分配、释放、重分配这些函数是封装成zmalloc,zfee这些函数的,只单纯的把zmalloc.c提取出来是远远不够的。后面发现redis的作者已经把sds给单独提出来了。包括三个源文件sds.c,sds.h,sdsalloc.h 因此执行如下操作即可单独把redis的sds模块提取出来。

提取sds模块

  1. 新建redis_sds测试目录

    选择合适的目录下新建

    mkdir redis_sds

  2. 复制源文件至redis_sds目录下

    在redis源码的src目录下执行:

    cp sds.c ~/redis_sds/

    cp sds.h ~/redis_sds/

    cp sdsalloc.h ~/redis_sds/

  3. 修改sdsalloc.h

    复制过来的sdsalloc.h 将sds模块的内存函数封装为使用zmalloc函数。为了简化处理直接使用libc的malloc函数来进行内存管理,同时将zmalloc.h给注释掉。

    //#include "zmalloc.h"
    #define s_malloc malloc
    #define s_realloc realloc
    #define s_free free
    
  4. 新建主函数

    新建主函数sds_test.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "sds.c"
    //#include "sds.h"
    int main(int argc, char *argv[]) {
         
        sds s = sdsnew("Hello World!");
        printf("Length:%d, Type:%d\n", sdslen(s), sdsReqType(sdslen(s)));
    
        s = sdscat(s, "The length of this sentence is greater than 32 bytes");
        printf("Length:%d, Type:%d\n", sdslen(s), sdsReqType(sdslen(s)));
    
        sdsfree(s);
        return 0;
    }
    

    直接include sds.c 即可,因为如果#include “sds.h” 的话,sdsReqType这个函数并没有在sds.h里面声明,而且因为sdsReqType的申明是:

    static inline char sdsReqType(size_t string_size) { 有static限制所以不能在sds.h中先声明,所以为了简单就直接#include 了sds.c了

  5. 编译

    为了方便重复编译,所以写了个简单的Makefile。

    test : sds_test.c sds.h sds.c sdsalloc.h
            gcc -o sdstest sds_test.c
    

    只需要编译sds_test.c 即可。因为sds_test.c 里面是直接#include sds.c 了所以再

    gcc -o sdstest sds_test.c sds.c 会将sds.c 里面的函数重复编译两次,造成Multiple definition 问题。

    之后只需要执行make命令就可以生成可执行文件sdstest。

    执行后输出为:

    ./sdstest 
    Length:12, Type:0
    Length:64, Type:1
    

    sds的创建

    通过sdsnew 来创建了一个sds。sdsnew源码为:

    /* Create a new sds string starting from a null terminated C string. */
    sds sdsnew(const char *init) {
         
        //使用?条件判断符来简化if语句对NULL的判断,直接使用strlen来返回字符指针的长度。
        size_t initlen = (init == NULL) ? 0 : strlen(init); 
        return sdsnewlen(init, initlen);
    }
    

    需要注意的是字符数组和字符指针是有区别的:字符指针的数据是存放在进程的虚拟地址空间的程序代码和数据段,是只读的不能修改。字符数组存放的字符串数据是存放在用户栈的,是可以更改的。且字符指针的数据没有"\0"这个结束符。

    参考博客讲的很好:https://blog.csdn.net/on_1y/article/details/13030439

    sdsnew 通过把字符串长度和字符串传递给sdsnewlen,来完成创建。

    
    /* 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 = n("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 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值