redis源码分析----main函数

本文深入分析Redis的源码,主要聚焦在`main`函数中,包括初始化过程、配置文件处理、哨兵模式的检测及启动、内存管理、哨兵系统的初始化、守护进程设置以及数据加载等关键步骤。
int main(int argc, char **argv) {
    struct timeval tv;


    /* We need to initialize our libraries, and the server configuration. */
#ifdef INIT_SETPROCTITLE_REPLACEMENT
    spt_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());
	/* 检查是否开启哨兵 */
    server.sentinel_mode = checkForSentinelMode(argc,argv);
	/* 初始化server变量 */
    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) {
		/* 设置哨兵相关配置,目前只有一个port选项,默认值为26379 */
        initSentinelConfig();
		/*该函数把普通的命令删除,然后将哨兵相关参数设置到server.commands中,然后初始化哨兵相关的数据结构 */
        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 */
        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++];
        /* 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 (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 (server.sentinel_mode && configfile && *configfile == '-') {
            redisLog(REDIS_WARNING,
                "Sentinel config from STDIN not allowed.");
            redisLog(REDIS_WARNING,
                "Sentinel needs config file on disk to save state.  Exiting...");
            exit(1);
        }
		/* getAbsolutePath该函数的目的是得到配置文件的绝对路径 */
        if (configfile) server.configfile = getAbsolutePath(configfile);
		/* 清空server.saveparams,该数据成员存储的是save规则的内容,save规则模式如下:
		     秒  	最少写次数
		save 900 	1		900秒内,最少执行一次写操作
		save 300 	10		300秒内,最少执行十次写操作
		save 60 	10000	60秒内,最少执行一千次写操作
		*/
        resetServerSaveParams();
		/* 分析配置文件,options是当命令行参数个数大于2时,得到的*/
        loadServerConfig(configfile,options);
        sdsfree(options);
    } 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();
	/* 如果打开了守护进程选项,则在配置选项pidfile指定的文件中写入该进程的pid */
    if (server.daemonize) createPidFile();
	/* 以下两个函数用作打印提示信息,在server.daemonize == 1时,该函数相当于什么都不做 */
    redisSetProcTitle(argv[0]);
    redisAsciiArt();


    if (!server.sentinel_mode) {
        /* Things not needed when running in Sentinel mode. */
        redisLog(REDIS_WARNING,"Server started, Redis version " REDIS_VERSION);
    #ifdef __linux__
		/* 读取/proc/sys/vm/overcommit_memory文件内容,该文件指定了内核针对内存分配的策略,其值可以是0、1、2:
			0 表示内核将检查是否有足够的可用内容供应用程序进程使用;如果有,内存申请允许;否则,内存申请失败,并把错误返回给应用进程
			1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何
			2 表示内核允许分配超过所有物理内核和交换空间总和的内存 */
        linuxMemoryWarnings();
    #endif
        checkTcpBacklogSettings();
		/* 通过AOF或RDB方式从磁盘读取持久化的数据 */
        loadDataFromDisk();
        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. */
    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);
	/* redis核心函数 */
    aeMain(server.el);
    aeDeleteEventLoop(server.el);
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值