Redis源码分析(一)

1. 简介

Redis(Remote Dictionary Server)是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。

1.1 特性

  • 性能高
  • 丰富的数据类型
  • 支持事务
  • 内建replication及集群
  • 支持持久化
  • 单线程,原子性操作

1.2 源码编译与调试

  • 源码下载
    git地址:https://github.com/redis/redis/tree/3.0
  • 执行编译
    • 修改配置文件中的daemon为yes
    • 禁用gcc编译优化,将makefile文件中OPTIMIZATION?=-O2修为-O0,可直接使用源码包下的二进制程序
    • gdb redis-server [conf],配合gdb相关命令
    • 也可以直接开启server.c的main测试函数

2 基本数据结构

2.1 简单动态字符串(SDS)

typedef char *sds;

/*
 * 保存字符串对象的结构
 */
struct sdshdr {
    
    // buf 中已占用空间的长度
    int len;

    // buf 中剩余可用空间的长度
    int free;

    // 数据空间
    char buf[];
};

在这里插入图片描述

2.1.2 空间扩容

  • 当前剩余长度 >= 新增长度, 直接返回
  • 否则
    • 新长度 < 预分配长度(1024 * 1024), 扩大一倍
    • 新长度 >= 预分配长度,每次加预分配长度
sds sdsMakeRoomFor(sds s, size_t addlen) {

    struct sdshdr *sh, *newsh;

    // 获取 s 目前的空余空间长度
    size_t free = sdsavail(s);

    size_t len, newlen;

    // s 目前的空余空间已经足够,无须再进行扩展,直接返回
    if (free >= addlen) return s;

    // 获取 s 目前已占用空间的长度
    len = sdslen(s);
    sh = (void*) (s-(sizeof(struct sdshdr)));

    // s 最少需要的长度
    newlen = (len+addlen);

    // 根据新长度,为 s 分配新空间所需的大小
    if (newlen < SDS_MAX_PREALLOC)
        // 如果新长度小于 SDS_MAX_PREALLOC 
        // 那么为它分配两倍于所需长度的空间
        newlen *= 2;
    else
        // 否则,分配长度为目前长度加上 SDS_MAX_PREALLOC
        newlen += SDS_MAX_PREALLOC;
    // T = O(N)
    newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1);

    // 内存不足,分配失败,返回
    if (newsh == NULL) return NULL;

    // 更新 sds 的空余长度
    newsh->free = newlen - len;

    // 返回 sds
    return newsh->buf;
}

2.1.3 空间缩容

在trim操作时,采用的是惰性空间释放即:不会立即使用内存重分配来回收缩短的字节,只是进行移动和标记,并修改数据长度。可以避免内存多次分配操作。

sds sdstrim(sds s, const char *cset) {
    struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr)));
    char *start, *end, *sp, *ep;
    size_t len;

    // 设置和记录指针
    sp = start = s;
    ep = end = s+sdslen(s)-1;

    // 修剪, T = O(N^2)
    while(sp <= end && strchr(cset, *sp)) sp++;
    while(ep > start && strchr(cset, *ep)) ep--;

    // 计算 trim 完毕之后剩余的字符串长度
    len = (sp > ep) ? 0 : ((ep-sp)+1);
    
    // 如果有需要,前移字符串内容
    // T = O(N)
    if (sh->buf != sp) memmove(sh->buf, sp, len);

    // 添加终结符
    sh->buf[len] = '\0';

    // 更新属性
    sh->free = sh->free+(sh->len-len);
    sh->len = len;

    // 返回修剪后的 sds
    return s;
}

2.1.4 优点

  • 常量获取字符串长度
  • 避免缓冲区溢出
  • 减少字符串修改带来的内存频繁重分配次数
  • 二进制安全:可以保持文本数据,也可以保持任意格式的二进制数据
  • 以’\0’结尾,使兼容兼容部分C字符串函数

2.1.5 其他

  • sds是char *的别名,可以理解为分配的是一块连续内存(表头 + 数据),根据局部性原理可以提高访问速度。

2.2 链表

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值