【redis源码学习】redis启动并读取配置文件的过程

redis-server [configfile] [options]

configfile 参数指定配置文件,options 参数指定启动配置项,可以覆盖配置文件中的配置项。

举个栗子:

redis-server ./redis.conf --port 6380 --protected-mode no


redisServer


关于配置信息,存储在如下结构体中:

//结构体稍微有点庞大(接近2W字),所以我稍微缩写一点哈,具体后面有用到再拿出来

struct redisServer {

/* General */

pid_t pid; /* Main process pid. */

char configfile; / Absolute config file path, or NULL */

char executable; / Absolute executable file path. */

char *exec_argv; / Executable argv vector (copy). */

···

}


main函数


这是一个极长的函数,不过没有那个结构体长,而我们此次要学的技法也主要是在这里面,所以还是能接受的。

int main(int argc, char **argv) {

struct timeval tv;

int j;

#ifdef REDIS_TEST

//这里略去

#endif

/* We need to initialize our libraries, and the server configuration. */

#ifdef INIT_SETPROCTITLE_REPLACEMENT

spt_init(argc, argv); //修改进程名

#endif

//此处略去一批

server.sentinel_mode = checkForSentinelMode(argc,argv); // 检查服务器是否以 Sentinel 模式启动

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. */

if (server.sentinel_mode) { //今天不讲哨兵,所以不管它

initSentinelConfig();

initSentinel();

}

//略

//开始了

if (argc >= 2) {

j = 1; /* First option to parse in argv[] */

sds options = sdsempty();

char *configfile = NULL;

/* Handle special options --help and --version */

if (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? */

if (argv[j][0] != ‘-’ || argv[j][1] != ‘-’) { //如果不是 --开头,那就是配置文件

configfile = argv[j];

server.configfile = getAbsolutePath(configfile);

/* Replace the config file in server.exec_argv with

  • its absolute path. */

zfree(server.exec_argv[j]);

server.exec_argv[j] = zstrdup(server.configfile);

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. */

while(j != argc) { //读取启动配置项,并存储到一个字符串中

if (argv[j][0] == ‘-’ && argv[j][1] == ‘-’) {

/* Option name */

if (!strcmp(argv[j], “–check-rdb”)) {

/* Argument has no options, need to skip for parsing. */

j++;

continue;

}

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++;

}

//略

resetServerSaveParams();

loadServerConfig(configfile,options); //从配置文件中加载所有配置项,见下文

sdsfree(options);

}

//略

initServer();

//略

redisSetCpuAffinity(server.server_cpulist);

aeMain(server.el);

aeDeleteEventLoop(server.el);

return 0;

}


initServerConfig

学习一下,毕竟不是每次启动都非得带上配置文件不是?

void initServerConfig(void) {

int j;

updateCachedTime(1);

getRandomHexChars(server.runid,CONFIG_RUN_ID_SIZE);

server.runid[CONFIG_RUN_ID_SIZE] = ‘\0’;

changeReplicationId();

clearReplicationId2();

server.hz = CONFIG_DEFAULT_HZ; /* Initialize it ASAP, even if it may get

updated later after loading the config.

This value may be used before the server

is initialized. */

server.timezone = getTimeZone(); /* Initialized by tzset(). */

server.configfile = NULL;

//略

/* Replication related */

server.masterauth = NULL;

server.masterhost = NULL;

server.masterport = 6379;

server.master = NULL;

//略

/* By default we want scripts to be always replicated by effects

  • (single commands executed by the script), and not by sending the

  • script to the slave / AOF. This is the new way starting from

  • Redis 5. However it is possible to revert it via redis.conf. */

server.lua_always_replicate_commands = 1;

initConfigValues();

}


loadServerConfigFromString

void loadServerConfigFromString(char *config) {

char *err = NULL;

int linenum = 0, totlines, i;

int slaveof_linenum = 0;

sds *lines;

lines = sdssplitlen(config,strlen(config),“\n”,1,&totlines);

for (i = 0; i < totlines; i++) {

sds *argv;

int argc;

linenum = i+1;

lines[i] = sdstrim(lines[i]," \t\r\n");

/* Skip comments and blank lines */

if (lines[i][0] == ‘#’ || lines[i][0] == ‘\0’) continue;

/* Split into arguments */

argv = sdssplitargs(lines[i],&argc);

if (argv == NULL) {

err = “Unbalanced quotes in configuration line”;

goto loaderr;

}

/* Skip this line if the resulting command vector is empty. */

if (argc == 0) {

sdsfreesplitres(argv,argc);

continue;

}

sdstolower(argv[0]);

/* Iterate the configs that are standard */

int match = 0;

for (standardConfig *config = configs; config->name != NULL; config++) {

if ((!strcasecmp(argv[0],config->name) ||

(config->alias && !strcasecmp(argv[0],config->alias))))

{

if (argc != 2) {

err = “wrong number of arguments”;

goto loaderr;

}

if (!config->interface.set(config->data, argv[1], 0, &err)) {

goto loaderr;

}

match = 1;

break;

}

}

if (match) {

sdsfreesplitres(argv,argc);

continue;

}

/* Execute config directives */

if (!strcasecmp(argv[0],“bind”) && argc >= 2) {

int j, addresses = argc-1;

if (addresses > CONFIG_BINDADDR_MAX) {

err = “Too many bind addresses specified”; goto loaderr;

}

/* Free old bind addresses */

for (j = 0; j < server.bindaddr_count; j++) {

zfree(server.bindaddr[j]);

}

for (j = 0; j < addresses; j++)

server.bindaddr[j] = zstrdup(argv[j+1]);

server.bindaddr_count = addresses;

} else if (!strcasecmp(argv[0],“unixsocketperm”) && argc == 2) {

errno = 0;

server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);

if (errno || server.unixsocketperm > 0777) {

err = “Invalid socket file permissions”; goto loaderr;

}

} else if (!strcasecmp(argv[0],“save”)) {

if (argc == 3) {

int seconds = atoi(argv[1]);

int changes = atoi(argv[2]);

if (seconds < 1 || changes < 0) {

err = “Invalid save parameters”; goto loaderr;

}

appendServerSaveParams(seconds,changes);

} else if (argc == 2 && !strcasecmp(argv[1],“”)) {

resetServerSaveParams();

}

} else if (!strcasecmp(argv[0],“dir”) && argc == 2) {

if (chdir(argv[1]) == -1) {

serverLog(LL_WARNING,“Can’t chdir to ‘%s’: %s”,

argv[1], strerror(errno));

exit(1);

}

} else if (!strcasecmp(argv[0],“logfile”) && argc == 2) {

FILE *logfp;

zfree(server.logfile);

server.logfile = zstrdup(argv[1]);

if (server.logfile[0] != ‘\0’) {

/* Test if we are able to open the file. The server will not

  • be able to abort just for this problem later… */

logfp = fopen(server.logfile,“a”);

if (logfp == NULL) {

err = sdscatprintf(sdsempty(),

“Can’t open the log file: %s”, strerror(errno));

goto loaderr;

}

fclose(logfp);

}

} else if (!strcasecmp(argv[0],“include”) && argc == 2) {

loadServerConfig(argv[1],NULL);

} else if ((!strcasecmp(argv[0],“client-query-buffer-limit”)) && argc == 2) {

server.client_max_querybuf_len = memtoll(argv[1],NULL);

} else if ((!strcasecmp(argv[0],“slaveof”) ||

!strcasecmp(argv[0],“replicaof”)) && argc == 3) {

slaveof_linenum = linenum;

server.masterhost = sdsnew(argv[1]);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
host = sdsnew(argv[1]);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-6obITyX7-1715151113679)]

[外链图片转存中…(img-tIRee3vT-1715151113680)]

[外链图片转存中…(img-85wus57J-1715151113680)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 12
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值