设为首页 收藏本站
查看: 1219|回复: 0

[经验分享] Redis源码解析(十六)--- config配置文件

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-11-5 09:19:17 | 显示全部楼层 |阅读模式
      每个系统都会有类似一个config配置文件,config文件里的内容想想都知道,一定就是那么一些固定的一行行的属性代码了,今天在看redis代码中的config属性,那拉下来的一笔,的确多,目测在50至100个属性左右。如果就此将config每个属性代表什么意思不是我的风格,也一定是很乏味的,所以我的特点就是在代码中去理解程序员在写这类代码时的思路,和茫茫代码中的亮点。我们知道,redis运行的环境包括很多种的,windows,Linux,mac os等等,不同的操作系统,当然有些属性就不能支持了,所以在redis中的config.h头文件中跟据计算机所属于的操作系统,做了很多的预处理,比如说,在Linux等系统上,是可以支持修改进程名称的:



    /* Check if we can use setproctitle().
     * BSD systems have support for it, we provide an implementation for
     * Linux and osx. */  
    /* 检查是否能调用setproctitle(),这个方法是Linux上修改进程名称的方法 */  
    /* 这里通过判断是否是BSD系统,BSD是Berkeley Systems Distrobution的缩写,是一种UNIX版本 */  
    #if (defined __NetBSD__ || defined __FreeBSD__ || defined __OpenBSD__)  
    #define USE_SETPROCTITLE  
    #endif  
      
    #if (defined __linux || defined __APPLE__)  
    #define USE_SETPROCTITLE  
    #define INIT_SETPROCTITLE_REPLACEMENT  
    void spt_init(int argc, char *argv[]);  
    void setproctitle(const char *fmt, ...);  
    #endif  

当然这只是我提到的一点,也就是说,redis在异构系统的处理上,考虑的还是非常周全的。我们主要看看config主要的操作文件,先看看里面的一些API:



     /* Config file API */  
    int yesnotoi(char *s) /* 判断字符是否为yes */  
    void appendServerSaveParams(time_t seconds, int changes) /* 追加server save参数 */  
    void resetServerSaveParams(void) /* 重置server的save参数,即释放server的serverParams */  
    void loadServerConfigFromString(char *config) /* 从字符串中加载server属性配置 */  
    void loadServerConfig(char *filename, char *options) /* 从文件中加载server配置 */  
    void configSetCommand(redisClient *c) /* 根据redisClient中的参数设置server的配置 */  
    #define config_get_string_field(_name,_var) /* 宏定义了获取字符串值域的方法 */  
    #define config_get_bool_field(_name,_var) /* 宏定义了获取布尔值域的方法,值在这里值为yes或no */  
    #define config_get_numerical_field(_name,_var) /* 宏定义了获取数字类型值域的方法 */  
    void configGetCommand(redisClient *c) /* 获取配置信息命令,以Replay给客户端的方式 */  
    void rewriteConfigAppendLine(struct rewriteConfigState *state, sds line) /* 添加配置字符串行 */  
    void rewriteConfigAddLineNumberToOption(struct rewriteConfigState *state, sds option, int linenum) /* 添加字典line-option */  
    void rewriteConfigMarkAsProcessed(struct rewriteConfigState *state, char *option) /* rewriteConfigState重写option选项 */  
    struct rewriteConfigState *rewriteConfigReadOldFile(char *path) /* 读取老配置文件信息,文件如果不可读或不存在,返回NULL */  
    void rewriteConfigRewriteLine(struct rewriteConfigState *state, char *option, sds line, int force) /* 是否覆盖configline */  
    int rewriteConfigFormatMemory(char *buf, size_t len, long long bytes) /* 格式化byte大小的显示,避免long long 类型超长的显示 */  
    void rewriteConfigBytesOption(struct rewriteConfigState *state, char *option, long long value, long long defvalue) /* 往config中写入某类型配置,后面的几个方法类似 */  
    void rewriteConfigYesNoOption(struct rewriteConfigState *state, char *option, int value, int defvalue) /* 同上 */  
    void rewriteConfigStringOption(struct rewriteConfigState *state, char *option, char *value, char *defvalue) /* 同上 */  
    void rewriteConfigNumericalOption(struct rewriteConfigState *state, char *option, long long value, long long defvalue) /* 同上 */  
    void rewriteConfigOctalOption(struct rewriteConfigState *state, char *option, int value, int defvalue) /* 同上 */  
    void rewriteConfigEnumOption(struct rewriteConfigState *state, char *option, int value, ...) /* 同上 */  
    void rewriteConfigSyslogfacilityOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigSaveOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigDirOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigSlaveofOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigNotifykeyspaceeventsOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigClientoutputbufferlimitOption(struct rewriteConfigState *state) /* 同上 */  
    void rewriteConfigBindOption(struct rewriteConfigState *state) /* 同上 */  
    sds rewriteConfigGetContentFromState(struct rewriteConfigState *state) /* confifstate中获取配置信息字符串 */  
    void rewriteConfigReleaseState(struct rewriteConfigState *state) /* configstate释放空间 */  
    void rewriteConfigRemoveOrphaned(struct rewriteConfigState *state) /* 置空state 的line配置 */  
    int rewriteConfigOverwriteFile(char *configfile, sds content) /* 字符串属性写入覆盖源文件 */  
    int rewriteConfig(char *path) /* 将当前的属性读入到文件中,步骤:(1).将当前server属性读入configstate(2).configstate属性变为字符串(3).将字符串写入文件 */  
    void configCommand(redisClient *c) /* 客户端config命令调用方法 */  

上面的API的数量确实有点恐怖,我大体总结一下,在config.c中的主要操作:

1.从config配置文件中读取配置到server属性中

2.将当前server的设置的属性写入配置中

上面的其他方法都是为上面的2个要求服务的。所以redis在这里设计一个叫rewriteConfigState的结构体角色,里面保存了属性配置的字符串数组,一个字符串数组代表一种属性设置。比如现在要把当前的配置读入配置文件中操作:



    int rewriteConfig(char *path) /* 将当前的属性读入到文件中,步骤:(1).将当前server属性读入configstate(2).configstate属性变为字符串(3).将字符串写入文件 */  

下面看看redis代码中的这个configstate结构体的构造:



    /* The config rewrite state. */  
    struct rewriteConfigState {  
        //这里存放着option-line的映射  
        dict *option_to_line; /* Option -> list of config file lines map */  
        dict *rewritten;      /* Dictionary of already processed options */  
        //当前配置文件中的行数  
        int numlines;         /* Number of lines in current config */  
        //当前行字符串  
        sds *lines;           /* Current lines as an array of sds strings */  
        int has_tail;         /* True if we already added directives that were
                                 not present in the original config file. */  
    };  

其中的lines就是具体的属性,第一个opition-line的映射指的是哪行对应什么属性名称。在config操作文件中,还提到了一个“maxmemory”的概念,中文意思可以了解为“最大记忆‘:



    /* We use the following dictionary type to store where a configuration
     * option is mentioned in the old configuration file, so it's
     * like "maxmemory" -> list of line numbers (first line is zero). */  
    /* 下面定义了几个字典类型用来保存老的配置文件中的一些信息,像历史记录类似,like "maxmemory" */  

也就是在redis文件中,可以存在老的配置文件,旧的属性可以通过老文件读入再次写入新配置中,达到了记录历史配置记录的作用。老配置文件读出的属性同样是存在于中间的configstate结构体中:



    /* Read the old file, split it into lines to populate a newly created
     * config rewrite state, and return it to the caller.
     *
     * If it is impossible to read the old file, NULL is returned.
     * If the old file does not exist at all, an empty state is returned. */  
    /* 读取老配置文件信息,文件如果不可读或不存在,返回NULL */  
    struct rewriteConfigState *rewriteConfigReadOldFile(char *path) {  
        FILE *fp = fopen(path,"r");  
        struct rewriteConfigState *state = zmalloc(sizeof(*state));  
        char buf[REDIS_CONFIGLINE_MAX+1];  
        int linenum = -1;  
      
        if (fp == NULL && errno != ENOENT) return NULL;  
      
        state->option_to_line = dictCreate(&optionToLineDictType,NULL);  
        state->rewritten = dictCreate(&optionSetDictType,NULL);  
        state->numlines = 0;  
        state->lines = NULL;  
        state->has_tail = 0;  
        if (fp == NULL) return state;  
      
        /* Read the old file line by line, populate the state. */  
        while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL) {  
            int argc;  
            sds *argv;  
            sds line = sdstrim(sdsnew(buf),"\r\n\t ");  
      
            linenum++; /* Zero based, so we init at -1 */  
      
            /* Handle comments and empty lines. */  
            //处理注释和空行  
            if (line[0] == '#' || line[0] == '\0') {  
                if (!state->has_tail && !strcmp(line,REDIS_CONFIG_REWRITE_SIGNATURE))  
                    state->has_tail = 1;  
                rewriteConfigAppendLine(state,line);  
                continue;  
            }  
      
            /* Not a comment, split into arguments. */  
            argv = sdssplitargs(line,&argc);  
            if (argv == NULL) {  
                /* Apparently the line is unparsable for some reason, for
                 * instance it may have unbalanced quotes. Load it as a
                 * comment. */  
                sds aux = sdsnew("# ??? ");  
                aux = sdscatsds(aux,line);  
                sdsfree(line);  
                //将老的配置属性读入configstate结构体  
                rewriteConfigAppendLine(state,aux);  
                continue;  
            }  
      
            sdstolower(argv[0]); /* We only want lowercase config directives. */  
      
            /* Now we populate the state according to the content of this line.
             * Append the line and populate the option -> line numbers map. */  
            rewriteConfigAppendLine(state,line);  
            rewriteConfigAddLineNumberToOption(state,argv[0],linenum);  
      
            sdsfreesplitres(argv,argc);  
        }  
        fclose(fp);  
         
        //返回configstate,里面记录了一些老的配置文件中的配置行信息  
        return state;  
    }  

又一次用到了configstate的结构体。小小config文件也存在我们意想不到的的设计。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-27095-1-1.html 上篇帖子: Redis源码解析(十五)--- aof-append only file解析 下篇帖子: Redis源码分析(十七)--- multi事务操作 配置文件
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表