Redis server启动源码

入口main函数

src/redis.c文件main函数

int main(int argc, char **argv) {struct timeval tv;/* We need to initialize our libraries, and the server configuration. */// 初始化库
#ifdef INIT_SETPROCTITLE_REPLACEMENTspt_init(argc, argv);
#endif//设置本地时间setlocale(LC_COLLATE,"");zmalloc_enable_thread_safeness();zmalloc_set_oom_handler(redisOutOfMemoryHandler);srand(time(NULL)^getpid());gettimeofday(&tv,NULL);//设置随机数种子dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());// 检查服务器是否以 Sentinel 模式启动server.sentinel_mode = checkForSentinelMode(argc,argv);// 初始化服务器initServerConfig();/* We need to init sentinel right now as parsing the configuration file* in sentinel mode will have the effect of populating the sentinel* data structures with master nodes to monitor. */// 如果服务器以 Sentinel 模式启动,那么进行 Sentinel 功能相关的初始化// 并为要监视的主服务器创建一些相应的数据结构if (server.sentinel_mode) {initSentinelConfig();initSentinel();}// 检查用户是否指定了配置文件,或者配置选项if (argc >= 2) {int j = 1; /* First option to parse in argv[] */sds options = sdsempty();char *configfile = NULL;/* Handle special options --help and --version */// 处理特殊选项 -h 、-v 和 --test-memoryif (strcmp(argv[1], "-v") == 0 ||strcmp(argv[1], "--version") == 0) version();if (strcmp(argv[1], "--help") == 0 ||strcmp(argv[1], "-h") == 0) usage();if (strcmp(argv[1], "--test-memory") == 0) {if (argc == 3) {memtest(atoi(argv[2]),50);exit(0);} else {fprintf(stderr,"Please specify the amount of memory to test in megabytes.\n");fprintf(stderr,"Example: ./redis-server --test-memory 4096\n\n");exit(1);}}/* First argument is the config file name? */// 如果第一个参数(argv[1])不是以 "--" 开头// 那么它应该是一个配置文件if (argv[j][0] != '-' || argv[j][1] != '-')configfile = argv[j++];/* All the other options are parsed and conceptually appended to the* configuration file. For instance --port 6380 will generate the* string "port 6380\n" to be parsed after the actual file name* is parsed, if any. */// 对用户给定的其余选项进行分析,并将分析所得的字符串追加稍后载入的配置文件的内容之后// 比如 --port 6380 会被分析为 "port 6380\n"while(j != argc) {if (argv[j][0] == '-' && argv[j][1] == '-') {/* Option name */if (sdslen(options)) options = sdscat(options,"\n");options = sdscat(options,argv[j]+2);options = sdscat(options," ");} else {/* Option argument */options = sdscatrepr(options,argv[j],strlen(argv[j]));options = sdscat(options," ");}j++;}if (configfile) server.configfile = getAbsolutePath(configfile);// 重置保存条件resetServerSaveParams();// 载入配置文件, options 是前面分析出的给定选项loadServerConfig(configfile,options);sdsfree(options);// 获取配置文件的绝对路径if (configfile) server.configfile = getAbsolutePath(configfile);} else {redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis");}// 将服务器设置为守护进程if (server.daemonize) daemonize();// 创建并初始化服务器数据结构initServer();// 如果服务器是守护进程,那么创建 PID 文件if (server.daemonize) createPidFile();// 为服务器进程设置名字redisSetProcTitle(argv[0]);// 打印 ASCII LOGOredisAsciiArt();// 如果服务器不是运行在 SENTINEL 模式,那么执行以下代码if (!server.sentinel_mode) {/* Things not needed when running in Sentinel mode. */// 打印问候语redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION);#ifdef __linux__// 打印内存警告linuxOvercommitMemoryWarning();#endif// 从 AOF 文件或者 RDB 文件中载入数据loadDataFromDisk();// 启动集群?if (server.cluster_enabled) {if (verifyClusterConfigWithData() == REDIS_ERR) {redisLog(REDIS_WARNING,"You can't have keys in a DB different than DB 0 when in ""Cluster mode. Exiting.");exit(1);}}// 打印 TCP 端口if (server.ipfd_count > 0)redisLog(REDIS_NOTICE,"The server is now ready to accept connections on port %d", server.port);// 打印本地套接字端口if (server.sofd > 0)redisLog(REDIS_NOTICE,"The server is now ready to accept connections at %s", server.unixsocket);} else {sentinelIsRunning();}/* Warning the user about suspicious maxmemory setting. */// 检查不正常的 maxmemory 配置if (server.maxmemory > 0 && server.maxmemory < 1024*1024) {redisLog(REDIS_WARNING,"WARNING: You specified a maxmemory value that is less than 1MB (current value is %llu bytes). Are you sure this is what you really want?", server.maxmemory);}// 运行事件处理器,一直到服务器关闭为止aeSetBeforeSleepProc(server.el,beforeSleep);aeMain(server.el);// 服务器关闭,停止事件循环aeDeleteEventLoop(server.el);return 0;
}

1、本地配置基本初始化

包括设置 server 运行的时区、设置哈希函数的随机种子。

    //设置本地时间setlocale(LC_COLLATE,"");zmalloc_enable_thread_safeness();zmalloc_set_oom_handler(redisOutOfMemoryHandler);srand(time(NULL)^getpid());gettimeofday(&tv,NULL);//设置随机数种子dictSetHashFunctionSeed(tv.tv_sec^tv.tv_usec^getpid());

2、检查哨兵模式

检查是不是以哨兵模式启动
/* Returns 1 if there is --sentinel among the arguments or if* argv[0] is exactly "redis-sentinel". */
int checkForSentinelMode(int argc, char **argv) {int j;if (strstr(argv[0],"redis-sentinel") != NULL) return 1;for (j = 1; j < argc; j++)if (!strcmp(argv[j],"--sentinel")) return 1;return 0;
}/* We need to init sentinel right now as parsing the configuration file* in sentinel mode will have the effect of populating the sentinel* data structures with master nodes to monitor. */// 如果服务器以 Sentinel 模式启动,那么进行 Sentinel 功能相关的初始化// 并为要监视的主服务器创建一些相应的数据结构if (server.sentinel_mode) {initSentinelConfig();initSentinel();}

3、运行参数解析

解析options,加载配置文件

    // 检查用户是否指定了配置文件,或者配置选项if (argc >= 2) {int j = 1; /* First option to parse in argv[] */sds options = sdsempty();char *configfile = NULL;/* Handle special options --help and --version */// 处理特殊选项 -h 、-v 和 --test-memoryif (strcmp(argv[1], "-v") == 0 ||strcmp(argv[1], "--version") == 0) version();if (strcmp(argv[1], "--help") == 0 ||strcmp(argv[1], "-h") == 0) usage();if (strcmp(argv[1], "--test-memory") == 0) {if (argc == 3) {memtest(atoi(argv[2]),50);exit(0);} else {fprintf(stderr,"Please specify the amount of memory to test in megabytes.\n");fprintf(stderr,"Example: ./redis-server --test-memory 4096\n\n");exit(1);}}/* First argument is the config file name? */// 如果第一个参数(argv[1])不是以 "--" 开头// 那么它应该是一个配置文件if (argv[j][0] != '-' || argv[j][1] != '-')configfile = argv[j++];/* All the other options are parsed and conceptually appended to the* configuration file. For instance --port 6380 will generate the* string "port 6380\n" to be parsed after the actual file name* is parsed, if any. */// 对用户给定的其余选项进行分析,并将分析所得的字符串追加稍后载入的配置文件的内容之后// 比如 --port 6380 会被分析为 "port 6380\n"while(j != argc) {if (argv[j][0] == '-' && argv[j][1] == '-') {/* Option name */if (sdslen(options)) options = sdscat(options,"\n");options = sdscat(options,argv[j]+2);options = sdscat(options," ");} else {/* Option argument */options = sdscatrepr(options,argv[j],strlen(argv[j]));options = sdscat(options," ");}j++;} 
loadServerConfig(configfile,options);

4、初始化 server

初始化数据库数据结构和pool,网络交互初始化(线程初始化、工作队列初始化)

void initServer() {int j;// 设置信号处理函数signal(SIGHUP, SIG_IGN);signal(SIGPIPE, SIG_IGN);setupSignalHandlers();// 设置 syslogif (server.syslog_enabled) {openlog(server.syslog_ident, LOG_PID | LOG_NDELAY | LOG_NOWAIT,server.syslog_facility);}// 初始化并创建数据结构server.current_client = NULL;server.clients = listCreate();server.clients_to_close = listCreate();server.slaves = listCreate();server.monitors = 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;// 创建共享对象createSharedObjects();adjustOpenFilesLimit();server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);server.db = zmalloc(sizeof(redisDb)*server.dbnum);/* Open the TCP listening socket for the user commands. */// 打开 TCP 监听端口,用于等待客户端的命令请求if (server.port != 0 &&listenToPort(server.port,server.ipfd,&server.ipfd_count) == REDIS_ERR)exit(1);/* Open the listening Unix domain socket. */// 打开 UNIX 本地端口if (server.unixsocket != NULL) {unlink(server.unixsocket); /* don't care if this fails */server.sofd = anetUnixServer(server.neterr,server.unixsocket,server.unixsocketperm, server.tcp_backlog);if (server.sofd == ANET_ERR) {redisLog(REDIS_WARNING, "Opening socket: %s", server.neterr);exit(1);}anetNonBlock(NULL,server.sofd);}/* Abort if there are no listening sockets at all. */if (server.ipfd_count == 0 && server.sofd < 0) {redisLog(REDIS_WARNING, "Configured to not listen anywhere, exiting.");exit(1);}/* Create the Redis databases, and initialize other internal state. */// 创建并初始化数据库结构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(&setDictType,NULL);server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);server.db[j].eviction_pool = evictionPoolAlloc();server.db[j].id = j;server.db[j].avg_ttl = 0;}// 创建 PUBSUB 相关结构server.pubsub_channels = dictCreate(&keylistDictType,NULL);server.pubsub_patterns = listCreate();listSetFreeMethod(server.pubsub_patterns,freePubsubPattern);listSetMatchMethod(server.pubsub_patterns,listMatchPubsubPattern);server.cronloops = 0;server.rdb_child_pid = -1;server.aof_child_pid = -1;aofRewriteBufferReset();server.aof_buf = sdsempty();server.lastsave = time(NULL); /* At startup we consider the DB saved. */server.lastbgsave_try = 0;    /* At startup we never tried to BGSAVE. */server.rdb_save_time_last = -1;server.rdb_save_time_start = -1;server.dirty = 0;resetServerStats();/* A few stats we don't want to reset: server startup time, and peak mem. */server.stat_starttime = time(NULL);server.stat_peak_memory = 0;server.resident_set_size = 0;server.lastbgsave_status = REDIS_OK;server.aof_last_write_status = REDIS_OK;server.aof_last_write_errno = 0;server.repl_good_slaves_count = 0;updateCachedTime();/* Create the serverCron() time event, that's our main way to process* background operations. */// 为 serverCron() 创建时间事件if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {redisPanic("Can't create the serverCron time event.");exit(1);}/* Create an event handler for accepting new connections in TCP and Unix* domain sockets. */// 为 TCP 连接关联连接应答(accept)处理器// 用于接受并应答客户端的 connect() 调用for (j = 0; j < server.ipfd_count; j++) {if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,acceptTcpHandler,NULL) == AE_ERR){redisPanic("Unrecoverable error creating server.ipfd file event.");}}// 为本地套接字关联应答处理器if (server.sofd > 0 && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,acceptUnixHandler,NULL) == AE_ERR) redisPanic("Unrecoverable error creating server.sofd file event.");/* Open the AOF file if needed. */// 如果 AOF 持久化功能已经打开,那么打开或创建一个 AOF 文件if (server.aof_state == REDIS_AOF_ON) {server.aof_fd = open(server.aof_filename,O_WRONLY|O_APPEND|O_CREAT,0644);if (server.aof_fd == -1) {redisLog(REDIS_WARNING, "Can't open the append-only file: %s",strerror(errno));exit(1);}}/* 32 bit instances are limited to 4GB of address space, so if there is* no explicit limit in the user provided configuration we set a limit* at 3 GB using maxmemory with 'noeviction' policy'. This avoids* useless crashes of the Redis instance for out of memory. */// 对于 32 位实例来说,默认将最大可用内存限制在 3 GBif (server.arch_bits == 32 && server.maxmemory == 0) {redisLog(REDIS_WARNING,"Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.");server.maxmemory = 3072LL*(1024*1024); /* 3 GB */server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;}// 如果服务器以 cluster 模式打开,那么初始化 clusterif (server.cluster_enabled) clusterInit();// 初始化复制功能有关的脚本缓存replicationScriptCacheInit();// 初始化脚本系统scriptingInit();// 初始化慢查询功能slowlogInit();// 初始化 BIO 系统bioInit();
}

5、执行事件驱动框架(Reactor模型)

   // 运行事件处理器,一直到服务器关闭为止aeSetBeforeSleepProc(server.el,beforeSleep);//事件处理的入口函数aeMain(server.el);// 服务器关闭,停止事件循环aeDeleteEventLoop(server.el);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/211055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

翻译: 生成式人工智能的经济潜力 第3部分工作和生产力的影响 The economic potential of generative AI

麦肯锡报告 翻译: 生成式人工智能的经济潜力 第一部分商业价值 The economic potential of generative AI翻译: 生成式人工智能的经济潜力 第2部分行业影响 The economic potential of generative AI 1. 工作和生产力的影响 技术几十年来一直在改变工作的解剖学。多年来&…

vue全屏事件与关闭全屏事件

首先&#xff0c;在 Vue 组件中&#xff0c;可以使用 click 或者 v-on 来监听点击事件&#xff0c;然后通过调用相应的方法来触发全屏或关闭全屏。 执行requestFullscreen事件 <template><div><button click"enterFullScreen">进入全屏</butt…

前端知识(十二)———ES6迭代器

ES6中的迭代器是一种新的对象&#xff0c;它具有一个next()方法。next()方法返回一个对象&#xff0c;这个对象包含两个属性&#xff1a;value和done。value属性是迭代器中的下一个值&#xff0c;done属性是一个布尔值&#xff0c;表示迭代器是否已经遍历完所有的值。迭代器是一…

js实现在线预览(PC)图片(jpg、png)、pdf、excel(xlsx)、docx

js实现图片预览 参考&#xff1a;添加链接描述 图片预览 本来用的是element-plus自带的组件el-image&#xff0c;但是去不掉缩略图&#xff0c;所以换成了el-imag-viewer组件&#xff08;图片可拖拽&#xff09;&#xff0c;由于用的vite没有require方法&#xff0c;需要自己处…

c++新经典模板与泛型编程:const修饰符的移除与增加

const修饰符的移除 让你来写移除const修饰符&#xff0c;你会怎么样来写&#xff1f; &#x1f602;&#x1f602;trait类模板&#xff0c;如下 #include <iostream>// 泛化版本 template<typename T> struct RemoveConst {using type T; };// 特化版本 template…

docker-compose 常用命令和指令

目录 1. 概要 2. 常用的docker-compose命令 2.1、image 2.2、build 2.3、command 2.4、links 2.5、external_links 2.6、ports 1.7、expose 1.8、volumes 1.9、volumes_from 1.10、environment 1.11、networks 1. 概要 默认的模板文件是 docker-compose.yml&…

阿里云(云服务器)上搭建项目部署环境

目录 安装docker docker安装MySQL5.7.37 安装MySQL 方式一&#xff1a;docker中MySQL时区调整 方式二&#xff1a;docker中MySQL时区调整 docker安装MySQL8.0.27 docker安装redis5.0.14 云服务器上安装jdk1.8 安装docker 1、先卸载docker&#xff0c;因为有一些服务器…

西南科技大学C++程序设计实验十(函数模板与类模板)

一、实验目的 1. 掌握函数模板与类模板; 2. 掌握数组类、链表类等线性群体数据类型定义与使用; 二、实验任务 1. 分析完善以下程序,理解模板类的使用: (1)补充类模板声明语句。 (2)创建不同类型的类对象,使用时明确其数据类型? _template<typename T>__…

c-语言->数据在内存的存储

系列文章目录 文章目录 系列文章目录前言 前言 目的&#xff1a;学习整数在内存的储存&#xff0c;什么是大小端&#xff0c;浮点数的储存。 1. 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们就讲过了下⾯的内容&#xff1a; 整数的2进制表⽰⽅法有三种&#xff0…

设计模式之观察者模式(主题对象发生变化,通知各个观察者)

当涉及到电商场景时&#xff0c;观察者模式可以用于处理多种情况&#xff0c;比如订单状态更新、库存变化、用户积分变化等。下面是一个简化的订单状态更新的观察者模式案例。 1.首先&#xff0c;定义一个主题接口 OrderSubject /*** Description:主题&#xff0c;用于管理观察…

基于Java会员管理系统

基于Java会员管理系统 功能需求 1、会员信息管理&#xff1a;该系统需要提供会员信息管理功能&#xff0c;包括会员的姓名、性别、年龄、联系方式等基本信息。同时&#xff0c;还需要提供会员的消费记录、积分、优惠券等信息的管理。 2、会员注册和登录&#xff1a;系统需要…

动手学习深度学习-跟李沐学AI-自学笔记(3)

一、深度学习硬件-CPU和GPU 芯片&#xff1a;Intel or AMD 内存&#xff1a;DDR4 显卡&#xff1a;nVidia 芯片可以和GPU与内存通信 GPU不能和内存通信 1. CPU 能算出每一秒能运算的浮点运算数&#xff08;大概0.15左右&#xff09; 1.1 提升CPU利用率 1.1.1 提升缓存…

自动驾驶学习笔记(十六)——目标跟踪

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo 社区开发者圆桌会》免费报名—>传送门 文章目录 前言 匹配关联 轨迹记录 状态预测 总结 前…

【文件上传系列】No.2 秒传(原生前端 + Node 后端)

上一篇文章 【文件上传系列】No.1 大文件分片、进度图展示&#xff08;原生前端 Node 后端 & Koa&#xff09; 秒传效果展示 秒传思路 整理的思路是&#xff1a;根据文件的二进制内容生成 Hash 值&#xff0c;然后去服务器里找&#xff0c;如果找到了&#xff0c;说明已经…

【智能家居】七、人脸识别 翔云平台编程使用(编译openSSL支持libcurl的https访问、安装SSL依赖库openSSL)

一、翔云 人工智能开放平台 API文档开发示例下载 二、编译openSSL支持libcurl的https访问 安装SSL依赖库openSSL(使用工具wget)libcurl库重新配置&#xff0c;编译&#xff0c;安装运行&#xff08;运行需添加动态库为环境变量&#xff09; 三、编程实现人脸识别 四、Base6…

12.4每日一题(备战蓝桥杯顺序结构程序设计)

12.4每日一题&#xff08;备战蓝桥杯顺序结构程序设计&#xff09; 题目1000: 【入门】AB Problem题目描述输入输出样例输入样例输出来源/分类 题解 1000: 【入门】AB Problem题目 2124: 计算(ab)c的值题目描述输入输出样例输入样例输出来源/分类 题解 2124: 计算(ab)c的值题目…

UML案例分析

首先需要花大约20分钟来思考解决这个问题&#xff0c;如果对问题不是很熟悉&#xff0c;也可以在完成题目之后&#xff0c;找相关的资料翻阅&#xff08;例如看UML类图的基本情况&#xff0c;UML状态图的基本情况&#xff0c;然后结合这些信息 做一个自我评价&#xff0c;看这个…

matlab 最小二乘拟合空间直线(方法三)

目录 一、算法原理1、算法过程2、参考文献二、代码实现三、结果展示四、相关链接博客长期更新,GPT与爬虫自重,你也未必能爬到最新版本。 一、算法原理 1、算法过程 空间直线的点向式方程为:

poe与chatgpt那个功能更强大

在当前的人工智能领域&#xff0c;Poe Al Chat以其卓越的聊天能力和实用的功能&#xff0c;受到了大家的广泛关注和喜爱。本文好为您个绍Poe Al Chat的功能&#xff0c;以及我们国内用户如何进行充值订阅。Poe Al Chat是一个基于OpenAl的GPT模型开发的人工智能聊天工具。它能够…

基于Springboot的校园失物招领系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园失物招领系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…