暗淡青春|Redis1.0源码阅读笔记一、总体流程

Redis介绍Redis 由C语言实现 , 是完全开源免费的 , 遵守BSD协议 , 是一个高性能的key-value数据库 。 Redis-1.0是第一个稳定版 , 并且代码量只有8k多行 。 虽然代码量不大 , 但实现的功能并不少:

  • 支持数据持久化
  • 支持master/slave 功能
  • Value支持String、List、Set数据结构
因为代码量少 , 结构清晰 , 功能丰富等特点 , Redis-1.0被很多网友推荐 , 适合新手阅读学习 。
Redis各版本的源码下载地址如下:
下载redis-1.0.tar.gz后 , 用命令tar -zxvf redis-1.0.tar.gz解压缩 。 在解压的文件夹中 , 有一个doc文件夹 , 里面介绍了redis的安装、每个命令的使用等 。 建议首先阅读README.html , 按照里面的步骤 , 编译安装运行 , 并用telnet连接redis服务器 , 使用SET、GET等指令 , 对Redis有一个初步了解 。
Redis1.0的总体流程main函数阅读Redis1.0时 , 可以从main函数开始 , 在文件redis.c中 。
int main(int argc, char **argv) {initServerConfig();if (argc == 2) {ResetServerSaveParams();loadServerConfig(argv[1]);} else if (argc > 2) {fprintf(stderr,"Usage: ./redis-server [/path/to/redis.conf]\n");exit(1);} else {redisLog(REDIS_WARNING,"Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'");}initServer();if (server.daemonize) daemonize();redisLog(REDIS_NOTICE,"Server started, Redis version " REDIS_VERSION);#ifdef __linux__linuxOvercommitMemoryWarning();#endifif (rdbLoad(server.dbfilename) == REDIS_OK)redisLog(REDIS_NOTICE,"DB loaded from disk");if (aeCreateFileEvent(server.el, server.fd, AE_READABLE,acceptHandler, NULL, NULL) == AE_ERR) oom("creating file event");redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);aeMain(server.el);aeDeleteEventLoop(server.el);return 0;}首先由函数initServerConfig用默认值初始化服务器配置 , 如DB数量16个、端口号6379等 。 当然 , redis支持在启动时指定配置文件 。 具体可配置项见文件redis.conf 。若指定配置文件 , 则启动脚本修改为./redis-server ./redis.conf 。 指定配置文件时 , 由函数loadServerconfig负责读取文件 , 并设置信息 , 如端口号等 。 函数initServer建立socket监听 , 初始化时间驱动的事件 。 函数rdbLoad读取db数据到内存 。 接着 , 调用aeCreatFileEvent函数 , 向全局变量server的el字段添加socket的aceeptHandler 。 最后 , 调用aeMain函数 , 进行while (1)loop 循环 。
在继续阅读每个函数的实现前 , 可以先看一下Redis中一个重要的全局变量:server, 其类型是一个名为redisServer的结构体 。 port保存了Redis监听的端口号 ,fd保存Redis打开的socket , 在initServer中被赋值 。 clients保存连接的客户端 , 是一个双向链表 。 el保存了各类事件 , 包括了文件事件(aeFileEvent)和时间事件(aeTimeEvent) , 两类事件都是用单向链表维护 。 结构体redisServer还包括了其他字段 , 不在这里一一展开介绍 , 将在后面介绍到具体功能时再做说明 。 redisServer截取定义如下:
/* Global server state structure */struct redisServer {int port;int fd;list *clients;aeEventLoop *el;};initServerredis配置设置完成后 , 调用initServer初始化服务器 。 initServer函数负责的初始化工作 , 包括创建客户端连接的链表、slaves链表、监听端口、初始化时间驱动事件等 。 server.el = aeCreateEventLoop() 创建事件管理结构 , server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr) 建立socket监听 。aeCreateTimeEvent(server.el, 1000, serverCron, NULL, NULL) 创建时间事件链表 。


推荐阅读