1、 redis源码介绍

在(3)中详细介绍了redis的几种持久化模式,接下来就在redis的源码中介绍,其持久化的实现方式。
在详细介绍其代码之前先简单介绍一下redis源码的目录结构。

在官网下载的文件解压后可以得到以下目录:

redis和CDH集成_redis和CDH集成

源码在src目录中,其内容如下:

redis和CDH集成_redis和CDH集成_02

文件很多,有一百多个,其中与持久化相关的有server.c、aof.c、rdb.c等等。

2、 RDB源码

代码入口

从之前的分析可以知道redis触发RDB的持久化有两种方式,一种是满足save命令设定的条件,还有一种是在客户端输入bgsave命令。

第一种是根据条件触发的,作为读源码的入口来说不是很合适,第二种需要解析客户端与服务器的交互,服务器接收到命令的命令解析过程,然后才是命令的执行。

这里我们首先分析第二种方式,不过我们略过前面的步骤,直接从bgsave的命令执行开始。

首先我们在src目录下找到server.c文件(本文使用的5.0版本,早期版本可能没有这个文件,类似的文件可以找redis.c),在这个文件中定义的一个redisCommandTable数组,这个数组里定义的redis支持的命令与其对应函数的对应关系,在其中找到bgsave命令。如图:

redis和CDH集成_nosql_03

从这里可以看出在执行bgsave命令的时候实际是会执行bgsaveCommand函数,这个函数我们可以在rdb.c中找到,其内容如下:

/* BGSAVE [SCHEDULE] */
void bgsaveCommand(client *c) {
    int schedule = 0;

    /* The SCHEDULE option changes the behavior of BGSAVE when an AOF rewrite
     * is in progress. Instead of returning an error a BGSAVE gets scheduled. */
    if (c->argc > 1) {
        if (c->argc == 2 && !strcasecmp(c->argv[1]->ptr,"schedule")) {
            schedule = 1;
        } else {
            addReply(c,shared.syntaxerr);
            return;
        }
    }

    rdbSaveInfo rsi, *rsiptr;
    rsiptr = rdbPopulateSaveInfo(&rsi);

    if (server.rdb_child_pid != -1) {
        addReplyError(c,"Background save already in progress");
    } else if (server.aof_child_pid != -1) {
        if (schedule) {
            server.rdb_bgsave_scheduled = 1;
            addReplyStatus(c,"Background saving scheduled");
        } else {
            addReplyError(c,
                "An AOF log rewriting in progress: can't BGSAVE right now. "
                "Use BGSAVE SCHEDULE in order to schedule a BGSAVE whenever "
                "possible.");
        }
    } else if (rdbSaveBackground(server.rdb_filename,rsiptr) == C_OK) {
        addReplyStatus(c,"Background saving started");
    } else {
        addReply(c,shared.err);
    }
}

仔细分析上述代码会发现:他实际没有执行持久化操作,他只是将 server.rdb_bgsave_scheduled的值设置为1了。其他的代码都打印错误信息之类的。那么bgsave的执行方式就很明显了,他只是更改rdb_bgsave_scheduled的值,然后快速返回,告诉用bgsave已经开始,最后数据库读取到这个值再开始执行持久化。