config: Speed up config template lookup

ast_category_get() has an (undocumented) implementation detail where it
tries to match the category name first by an explicit pointer comparison
and if that fails falls back to a normal match.

When initially building an ast_config during ast_config_load, this
pointer comparison can never succeed, but we will end up iterating all
categories twice. As the number of categories using a template
increases, this dual looping becomes quite expensive. So we pass a flag
to category_get_sep() indicating if a pointer match is even possible
before trying to do so, saving us a full pass over the list of current
categories.

In my tests, loading a file with 3 template categories and 12000
additional categories that use those 3 templates (this file configures
4000 PJSIP endpoints with AOR & Auth) takes 1.2 seconds. After this
change, that drops to 22ms.

Change-Id: I59b95f288e11eb6bb34f31ce4cc772136b275e4a
This commit is contained in:
Sean Bright
2017-12-01 11:01:01 -05:00
parent 5de9754313
commit d9fdeae6a4

View File

@@ -986,13 +986,15 @@ struct ast_category *ast_category_new_template(const char *name, const char *in_
}
static struct ast_category *category_get_sep(const struct ast_config *config,
const char *category_name, const char *filter, char sep)
const char *category_name, const char *filter, char sep, char pointer_match_possible)
{
struct ast_category *cat;
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
return cat;
if (pointer_match_possible) {
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == category_name && does_category_match(cat, category_name, filter, sep)) {
return cat;
}
}
}
@@ -1008,7 +1010,7 @@ static struct ast_category *category_get_sep(const struct ast_config *config,
struct ast_category *ast_category_get(const struct ast_config *config,
const char *category_name, const char *filter)
{
return category_get_sep(config, category_name, filter, ',');
return category_get_sep(config, category_name, filter, ',', 1);
}
const char *ast_category_get_name(const struct ast_category *category)
@@ -1792,7 +1794,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
if (cur[1] != ',') {
filter = &cur[1];
}
*cat = category_get_sep(cfg, catname, filter, '&');
*cat = category_get_sep(cfg, catname, filter, '&', 0);
if (!(*cat)) {
if (newcat) {
ast_category_destroy(newcat);
@@ -1810,7 +1812,7 @@ static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
} else {
struct ast_category *base;
base = ast_category_get(cfg, cur, "TEMPLATES=include");
base = category_get_sep(cfg, cur, "TEMPLATES=include", ',', 0);
if (!base) {
if (newcat) {
ast_category_destroy(newcat);