[Asterisk-code-review] aco: Create ways to minimize use of regex. (asterisk[master])

Corey Farrell asteriskteam at digium.com
Tue Dec 12 13:04:01 CST 2017


Corey Farrell has uploaded this change for review. ( https://gerrit.asterisk.org/7529


Change subject: aco: Create ways to minimize use of regex.
......................................................................

aco: Create ways to minimize use of regex.

ACO uses regex in many situations where it is completely unneeded.  In
some cases this doubles the total processing performed by
aco_process_config.

* Create ACO_IGNORE category type for use in place of skip_category
  regex source string.
* Create additional aco_category_op values to allow specifying category
  filter using either a single plain string or a NULL terminated array
  of plain strings.
* Create ACO_PREFIX to allow matching option names to case insensitive
  prefixes.

Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821
---
M include/asterisk/config_options.h
M main/config_options.c
2 files changed, 74 insertions(+), 5 deletions(-)



  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/29/7529/1

diff --git a/include/asterisk/config_options.h b/include/asterisk/config_options.h
index f4c3db1..3227f94 100644
--- a/include/asterisk/config_options.h
+++ b/include/asterisk/config_options.h
@@ -40,18 +40,30 @@
 enum aco_type_t {
 	ACO_GLOBAL,
 	ACO_ITEM,
+	ACO_IGNORE,
 };
 
-/*! \brief Whether a category regex is a blackist or a whitelist */
+/*! Type of category matching to perform */
 enum aco_category_op {
+	/*! Regex based blacklist. */
 	ACO_BLACKLIST = 0,
+	/*! Regex based whitelist. */
 	ACO_WHITELIST,
+	/*! Blacklist with a single string matched with strcasecmp. */
+	ACO_BLACKLIST_EXACT,
+	/*! Whitelist with a single string matched with strcasecmp. */
+	ACO_WHITELIST_EXACT,
+	/*! Blacklist with a NULL terminated array of strings matched with strcasecmp. */
+	ACO_BLACKLIST_ARRAY,
+	/*! Whitelist with a NULL terminated array of strings matched with strcasecmp. */
+	ACO_WHITELIST_ARRAY,
 };
 
 /*! \brief What kind of matching should be done on an option name */
 enum aco_matchtype {
 	ACO_EXACT = 1,
 	ACO_REGEX,
+	ACO_PREFIX,
 };
 
 /*! Callback functions for option parsing via aco_process_config() */
diff --git a/main/config_options.c b/main/config_options.c
index a9a145b..73ed907 100644
--- a/main/config_options.c
+++ b/main/config_options.c
@@ -373,6 +373,8 @@
 	switch (match->match_type) {
 	case ACO_EXACT:
 		return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
+	case ACO_PREFIX:
+		return strncasecmp(name, match->name, strlen(match->name)) ? 0 : CMP_MATCH | CMP_STOP;
 	case ACO_REGEX:
 		return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
 	}
@@ -402,6 +404,43 @@
 	return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
 }
 
+static int internal_aco_type_category_check(struct aco_type *match, const char *category)
+{
+	const char **categories = (const char **)match->category;
+
+	switch (match->category_match) {
+	case ACO_WHITELIST:
+	case ACO_BLACKLIST:
+		return !regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match;
+
+	case ACO_WHITELIST_EXACT:
+		return strcasecmp(match->category, category);
+
+	case ACO_BLACKLIST_EXACT:
+		return !strcasecmp(match->category, category);
+
+	case ACO_WHITELIST_ARRAY:
+		while (*categories) {
+			if (!strcasecmp(*categories, category)) {
+				return 0;
+			}
+			categories++;
+		}
+		return -1;
+
+	case ACO_BLACKLIST_ARRAY:
+		while (*categories) {
+			if (!strcasecmp(*categories, category)) {
+				return -1;
+			}
+			categories++;
+		}
+		return 0;
+	}
+
+	return -1;
+}
+
 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
 {
 	size_t x;
@@ -410,7 +449,7 @@
 
 	for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
 		/* First make sure we are an object that can service this category */
-		if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
+		if (internal_aco_type_category_check(match, category)) {
 			continue;
 		}
 
@@ -481,6 +520,10 @@
 	if (!(type = internal_aco_type_find(file, cfg, cat))) {
 		ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
 		return -1;
+	}
+
+	if (type->type == ACO_IGNORE) {
+		return 0;
 	}
 
 	field = info->internal->pending + type->item_offset;
@@ -630,6 +673,10 @@
 		/* set defaults for global objects */
 		for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
 			void **field = info->internal->pending + match->item_offset;
+
+			if (match->type == ACO_IGNORE) {
+				continue;
+			}
 
 			if (match->type != ACO_GLOBAL || !*field) {
 				continue;
@@ -797,9 +844,19 @@
 		return -1;
 	}
 
-	if (!(type->internal->regex = build_regex(type->category))) {
-		internal_type_destroy(type);
-		return -1;
+	switch (type->category_match) {
+	case ACO_BLACKLIST:
+	case ACO_WHITELIST:
+		if (!(type->internal->regex = build_regex(type->category))) {
+			internal_type_destroy(type);
+			return -1;
+		}
+		break;
+	case ACO_BLACKLIST_EXACT:
+	case ACO_WHITELIST_EXACT:
+	case ACO_BLACKLIST_ARRAY:
+	case ACO_WHITELIST_ARRAY:
+		break;
 	}
 
 	if (!(type->internal->opts = aco_option_container_alloc())) {

-- 
To view, visit https://gerrit.asterisk.org/7529
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-MessageType: newchange
Gerrit-Change-Id: I66a920dcd8e2b0301f73f968016440a985e72821
Gerrit-Change-Number: 7529
Gerrit-PatchSet: 1
Gerrit-Owner: Corey Farrell <git at cfware.com>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-code-review/attachments/20171212/112f35e9/attachment-0001.html>


More information about the asterisk-code-review mailing list