1、 redis源码介绍
在(3)中详细介绍了redis的几种持久化模式,接下来就在redis的源码中介绍,其持久化的实现方式。
在详细介绍其代码之前先简单介绍一下redis源码的目录结构。
在官网下载的文件解压后可以得到以下目录:
源码在src目录中,其内容如下:
文件很多,有一百多个,其中与持久化相关的有server.c、aof.c、rdb.c等等。
2、 RDB源码
代码入口
从之前的分析可以知道redis触发RDB的持久化有两种方式,一种是满足save命令设定的条件,还有一种是在客户端输入bgsave命令。
第一种是根据条件触发的,作为读源码的入口来说不是很合适,第二种需要解析客户端与服务器的交互,服务器接收到命令的命令解析过程,然后才是命令的执行。
这里我们首先分析第二种方式,不过我们略过前面的步骤,直接从bgsave的命令执行开始。
首先我们在src目录下找到server.c文件(本文使用的5.0版本,早期版本可能没有这个文件,类似的文件可以找redis.c),在这个文件中定义的一个redisCommandTable数组,这个数组里定义的redis支持的命令与其对应函数的对应关系,在其中找到bgsave命令。如图:
从这里可以看出在执行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已经开始,最后数据库读取到这个值再开始执行持久化。