【源码】Redis Server启动过程

1、 初始化参数配置
//设置时区
setlocale(LC_COLLATE,"");
//设置随机种子
char hashseed[16];
getRandomHexChars(hashseed,sizeof(hashseed));
dictSetHashFunctionSeed((uint8_t*)hashseed);
//初始化module
void initServerConfig(void) {
    //serverCron函数执行频率,默认10ms
    server.hz = CONFIG_DEFAULT_HZ;
    //监听端口,默认6379
    server.port = CONFIG_DEFAULT_SERVER_PORT;
    server.tcp_backlog = CONFIG_DEFAULT_TCP_BACKLOG;
    server.dbnum = CONFIG_DEFAULT_DBNUM;
    ......
    //初始化命令表
    server.commands = dictCreate(&commandTableDictType,NULL);
    server.orig_commands = dictCreate(&commandTableDictType,NULL);
    populateCommandTable();
    server.delCommand = lookupCommandByCString("del");
    server.multiCommand = lookupCommandByCString("multi");
    server.lpushCommand = lookupCommandByCString("lpush");
    server.lpopCommand = lookupCommandByCString("lpop");
    server.rpopCommand = lookupCommandByCString("rpop");
    server.sremCommand = lookupCommandByCString("srem");
    server.execCommand = lookupCommandByCString("exec");
    server.expireCommand = lookupCommandByCString("expire");
    server.pexpireCommand = lookupCommandByCString("pexpire");
    ......
}2、 加载并解析配置文件
//filename表示配置文件全路径名称;
//options表示命令行输入的配置参数,如port=4000
void loadServerConfig(char *filename, char *options) {
    sds config = sdsempty();
    char buf[CONFIG_MAX_LINE+1];
    /* 加载配置文件到内存 */
    if (filename) {
        FILE *fp;
        if (filename[0] == '-' && filename[1] == '\0') {
            fp = stdin;
        } else {
            if ((fp = fopen(filename,"r")) == NULL) {
                serverLog(LL_WARNING,
                    "Fatal error, can't open config file '%s'", filename);
                exit(1);
            }
        }
        while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)
            config = sdscat(config,buf);
        if (fp != stdin) fclose(fp);
    }
    /* Append the additional options */
    if (options) {
        config = sdscat(config,"\n");
        config = sdscat(config,options);
    }
    //解析配置
    loadServerConfigFromString(config);
    sdsfree(config);
}3、 初始化服务器内部变量
void initServer(void) {
    /* 初始化需要的各种资源 */
    server.clients = listCreate();//初始化客户端链表
    server.pid = getpid();
    server.current_client = NULL;
    server.clients = listCreate();
    server.clients_to_close = listCreate();
    server.slaves = listCreate();
    server.monitors = listCreate();
   server.clients_pending_write = listCreate();
   server.slaveseldb = -1; /* Force to emit the first SELECT command. */
   server.unblocked_clients = listCreate();
   server.ready_keys = listCreate();
   server.clients_waiting_acks = listCreate();
   server.get_ack_from_slaves = 0;
   server.clients_paused = 0;
   server.system_memory_size = zmalloc_get_memory_size();
   createSharedObjects();
    //调用aeCreateEventLoop函数创建aeEventLoop结构体,并赋值给server结构的el变量
    //maxclients 变量的值大小,可以在 Redis 的配置文件 redis.conf 中进行定义,默认值是 1000
    server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
    if (server.el == NULL) {
        serverLog(LL_WARNING,
            "Failed creating the event loop. Error message: '%s'",
            strerror(errno));
        exit(1);
    }
    ......
    /* 创建数据库结构*/
    for (j = 0; j < server.dbnum; j++) {
        server.db[j].dict = dictCreate(&dbDictType,NULL);
        server.db[j].expires = dictCreate(&keyptrDictType,NULL);
        server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
        server.db[j].ready_keys = dictCreate(&objectKeyPointerValueDictType,NULL);
        server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
        server.db[j].id = j;
        server.db[j].avg_ttl = 0;
    } 
    ......
    //创建事件循环框架
    server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
    …
    //开始监听设置的网络端口
    if (server.port != 0 &&
            listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
            exit(1);
    …
    //为server后台任务创建定时事件
    if (aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
            serverPanic("Can't create event loop timers.");
            exit(1);
    }
    …
    //为每一个监听的IP设置连接事件的处理函数acceptTcpHandler
    for (j = 0; j < server.ipfd_count; j++) {
            if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
                acceptTcpHandler,NULL) == AE_ERR)
           { … }
    }
}
4、执行事件驱动框架
aeSetBeforeSleepProc(server.el,beforeSleep);
aeSetAfterSleepProc(server.el,afterSleep);
aeMain(server.el);
aeDeleteEventLoop(server.el);【源码】Redis Server启动过程的更多相关文章
- 曹工说Redis源码(3)-- redis server 启动过程完整解析(中)
		文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ... 
- 曹工说Redis源码(5)-- redis server 启动过程解析,以及EventLoop每次处理事件前的前置工作解析(下)
		曹工说Redis源码(5)-- redis server 启动过程解析,eventLoop处理事件前的准备工作(下) 文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis ... 
- 曹工说Redis源码(2)-- redis server 启动过程解析及简单c语言基础知识补充
		文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ... 
- workerman源码分析之启动过程
		PHP一直以来以草根示人,它简单,易学,被大量应用于web开发,非常可惜的是大部分开发都在简单的增删改查,或者加上pdo,redis等客户端甚至分布式,以及规避语言本身的缺陷.然而这实在太委屈PHP了 ... 
- 跟着大彬读源码 - Redis 1 - 启动服务,程序都干了什么?
		一直很羡慕那些能读 Redis 源码的童鞋,也一直想自己解读一遍,但迫于 C 大魔王的压力,解读日期遥遥无期. 相信很多小伙伴应该也都对或曾对源码感兴趣,但一来觉得自己不会 C 语言,二来也不知从何入 ... 
- Nimbus<三>Storm源码分析--Nimbus启动过程
		Nimbus server, 首先从启动命令开始, 同样是使用storm命令"storm nimbus”来启动看下源码, 此处和上面client不同, jvmtype="-serv ... 
- 【Kafka源码】KafkaController启动过程
		[TOC] 之前聊过了很多Kafka启动过程中的一些加载内容,也知道了broker可以分为很多的partition,每个partition内部也可以分为leader和follower,主从之间有数据的 ... 
- 【Kafka源码】Kafka启动过程
		一般来说,我们是通过命令来启动kafka,但是命令的本质还是调用代码中的main方法,所以,我们重点看下启动类Kafka.源码下下来之后,我们也可以通过直接运行Kafka.scala中的main方法( ... 
- spark源码阅读--SparkContext启动过程
		##SparkContext启动过程 基于spark 2.1.0 scala 2.11.8 spark源码的体系结构实在是很庞大,从使用spark-submit脚本提交任务,到向yarn申请容器,启 ... 
随机推荐
- uniapp医院预约挂号微信小程序
			开头感言:最近看小程序很火,也想弄一个看看,用了一些时间从0开始写,也记录了一些笔记,自己用框架写的模板,不是很精美,后面会慢慢优化,功能也是后面慢慢加上去的, 其中功能这块,起初只是一些简单的功能, ... 
- Codeforces 567D:One-Dimensional Battle Ships(二分)
			time limit per test : 1 second memory limit per test : 256 megabytes input : standard input output : ... 
- Obfuscated Gradients Give a False Sense of Security: Circumventing Defenses to Adversarial Examples
			目录 概 主要内容 Obfuscated Gradients BPDA 特例 一般情形 EOT Reparameterization 具体的案例 Thermometer encoding Input ... 
- Android物联网应用程序开发(智慧城市)—— 用户注册界面开发
			效果: 布局代码: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns: ... 
- ssm项目使用过滤器出现4040错误
			目录 问题 解决方法 (1)方法一 (2)方法二 问题 过滤器处理乱码问题 public class CharFilter implements Filter { @Override public v ... 
- SpringCloud创建Eureka模块集群
			1.说明 本文详细介绍Spring Cloud创建Eureka模块集群的方法, 基于已经创建好的Spring Cloud Eureka Server模块, 请参考SpringCloud创建Eureka ... 
- RESTful测试工具RESTClient
			1.简介 RESTClient是一个用于测试RESTful Web服务的客户端, 是用Java Swing编写的基于Http协议的接口测试工具, 它可以向服务器发送各种Http请求,并显示服务器响应. ... 
- linux 之 误删openssl文件夹重装openssl
			背景 使用 scp.ssh 都报错 error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared objec ... 
- 初识python: 多态
			多态:允许你将父对象设置成为,与一个或更多其子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作. 简单讲就是:允许将子类类型的指针赋值给父类类型的指针. 多态 ... 
- Selenium_环境安装(1)
			Selenium是一个用于Web应用程序自动化测试工具.Selenium测试直接运行在浏览器中,就像真正的用户在操作一样. Selenium基本上支持主流的浏览器,包括IE,Mozilla Firef ... 
