keepalived配置文件解析系列之(二)keyword存储的设计与实现

keepalived配置文件解析系列之(二)keyword存储的设计与实现

virHappy(zhuozch@163.com)

  与关键字相关的数据结构和操作主要在lib/parser.c文件中,下面介绍其中的核心内容。

一、 关键字相关数据结构

  作为关键字, 首先需要有一个名字name来区分, 当解析配置文件时遇到该关键字要进行什么操作则由函数handler来表达, 最后单独的一个关键字是作为整个层次关键字中的一员, 需要有相应的成员去关联下一级别的关键字,这个任务由 sub指针完成。具体的关键字定义如下:

1 /* ketword definition */
2 struct keyword {
3 char *string;
4 void (*handler) (vector);
5 vector sub;
6 };

  位于同一层次的关键字构成一个列表(vector,向量), C语言中没有直接的vector定义, keepalived采用定义了自己的列表(vector), 如下:

1 /* vector definition */
2 struct _vector {
3 unsigned int allocated;
4 void **slot;
5 };
6 typedef struct _vector *vector;

上面的定义是很常见的, allocated对应列表的大小, 而slot则对应列表的内容。 留意到slot的类型为void**, 这意味着这样的列表存储的内容可以是任意数据类型的指针(在下方中, 我们将看到, 在层次关键字结构中, 它用来存储指向关键字结构体keyword的指针)。

  关键字的层次是用变量sublevel进行组织的, sublevel初始为0, 表示关键字的层次从0开始, 添加下一层次的关键字之前需要递增sublevel变量, 需要回到上一层关键字之前要递减sublevel变量。

  每层关键字对应一个或多个关键列表(取决于该列表由哪些关键字派生出来)。第零层关键字是必定存在的,所以定义 了一个全局的关键字列表keywords(注意keepalived中以带s或者_vec结尾的名字区分单个关键字和关键字列表)

二、关键字层次组织

  下面分别从check_init_keywords(void) (位于check_parser.c文件中) 和 install_http_check_keyword(void)函数中摘取相关语句组成一个分层的关键字结构。摘取的语句如下:

 1 install_keyword_root("virtual_server_group", &vsg_handler);
2 install_keyword_root("virtual_server", &vs_handler);
3 install_keyword("delay_loop", &delay_handler);
4 install_keyword("real_server", &rs_handler);
5 install_sublevel();
6 install_keyword("weight", &weight_handler);
7 install_keyword("HTTP_GET", &http_get_handler);
8 install_sublevel();
9 install_keyword("connect_timeout", &connect_to_handler);
10 install_keyword("url", &url_handler);
11 install_sublevel();
12 install_keyword("path", &path_handler);
13 install_keyword("digest", &digest_handler);
14 install_sublevel_end();
15 install_sublevel_end();
16 install_sublevel_end();

对应的关键字层次组织图如下:

上图中层次1中的第2个real_server在代码中对应的语句并没有写出来, 在这里画出是为了展现同一层次的关键字如何关联各自的下一层关键字。此外,关键字的sub指针实际上指向一个列表(vector),为了更形象地表达这个点, 图中采用了由sub指针指向列表中的各个元素的记法。 keywords对应全局的关键字列表(即层次0的关键字), delay_loop、real_server等位于层次1, weight, HTTP_GET等位于层次2, connect_timeout, url等位于层次3, path、digest位于层次4。

三、关键字操作介绍

  如上所介绍,keepalived通过install_keyword_root()、 install_keyword()、 Install_sublevel()和install_sublevel_end()等操作构建关键字层次组织。 下面对这些关键字操作及它们内部调用 的函数进行介绍。

  install_keyword_root(char *string, void (*handler) (vector))为层次0(对应全局变量keywords)的关键字列表添加一个名字为string, 处理函数为handler的关键字。 具体的实现是通过调用keyword_alloc(keywords, string, handler)来实现的。

  install_keyword(char *string, void (*handler) (vector))为层次为sublevel的关键字列表添加一个名字为string, 处理函数为handler的关键字。 具体 的实现是通过调用keyword_alloc_sub(keywords, string, handler)来实现的。

  install_ sublevel(void)表示将处理下一层次的关键字列表, 具体的实现是递增sublevel。

  install_sublevel_end(void)表示回到上一层关键字列表, 具体的实现是递减sublevel。

  keyword_alloc(vector keywords_vec, char *string, void (*handler) (vector))为关键字列表keywords_vec添加一个名字为string, 处理函数为handler的关键字。具体的实现是先调用vector_alloc_slot(keywords_vec)为要新增加的关键字分配内存空间,  再用string和handler构造一个关键字, 最后调用vector_set_slot(keywords_vec, keyword)添加新的关键字到关键字列表keywords_vec中。

  keyword_alloc_sub(vector keywords_vec, char *string, void (*handler) (vector))为当前关键字列表keywords_vec的最后 一个关键字的第sublevel层关键字列表的最后一个元素的下一层关键字列表添加一个名字为string, 处理函数为handler的关键字。具体的实现是先判断当前关键字列表keywords_vec的最后 一个关键字的第sublevel层关键字列表的最后一个元素的下一层关键字列表是否存在, 若不存在的话, 调用vector_alloc()分配下一层的关键字列表的内存空间。 最后调用keyword_alloc(keyword->sub, string, handler)为该层添加新的关键字。

四、小结

  如上, keepalived的关键字采用图的方式进行组织, 每层关键字的数量是不限的, 任意一个关键字都可以有下一层次的关键字, 具有很大的灵活性, 所以平时在C类项目中若有解析具有这样特点的配置文件时 , 可以考虑复用keepalived的这一设计。

  下面的文章将会介绍如何根据这些关键字的组织解析配置文件。

                

原文地址:https://www.cnblogs.com/quiet/p/2406606.html