[asterisk-commits] murf: branch murf/fast-ast2 r89128 - /team/murf/fast-ast2/main/pbx.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Nov 9 09:17:05 CST 2007


Author: murf
Date: Fri Nov  9 09:17:05 2007
New Revision: 89128

URL: http://svn.digium.com/view/asterisk?view=rev&rev=89128
Log:
Some Changes to bring the pattern matching more in line with the algorithm: 1. matches should be able to occur in multiple places as you proceed thru the tree. Of course, the longer pattern will win, but what if the match fails before the longer pattern is finished? 2. Doing the matchcid stuff outside the tree is entirely wrong. I enter a slash and the matchcid pattern into the tree. So, if a match is found in the tree on the extension, and a slash is next after the match, then it continue traversing the tree, using the CID info instead of the extension info to match against. Works nicely, and gives the same benefits to CID matching (ex-girlfriend pattern matching) as it does to extension matching. Will also do this for the ! and . wildcards. 3. I added a printing capability to the dialplan-show cli, to show the match-char tree; it will do this if you do the core-set-debug thing."

Modified:
    team/murf/fast-ast2/main/pbx.c

Modified: team/murf/fast-ast2/main/pbx.c
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast2/main/pbx.c?view=diff&rev=89128&r1=89127&r2=89128
==============================================================================
--- team/murf/fast-ast2/main/pbx.c (original)
+++ team/murf/fast-ast2/main/pbx.c Fri Nov  9 09:17:05 2007
@@ -81,13 +81,13 @@
  *
  * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
  * here, and shows a fairly flat (constant) search time, even for over
- * 1000 patterns. Still needs some work-- there are some fine points of the matching
+ * 1000 patterns. Might Still needs some work-- there are some fine points of the matching
  * spec about tie-breaking based on the characters in character sets, but this
  * should be do-able via the weight system currently being used.
  *
  * Also, using a hash table for context/priority name lookup can help prevent
  * the find_extension routines from absorbing exponential cpu cycles. I've tested
- * find_extension with red-black trees, which have O(log2(n)) speed.Right now,
+ * find_extension with red-black trees, which have O(log2(n)) speed. Right now,
  * I'm using hash tables, which do searches (ideally) in O(1) time.
  *
  */
@@ -331,7 +331,6 @@
 void create_match_char_tree(struct ast_context *con);
 struct ast_exten *get_canmatch_exten(struct match_char *node);
 void destroy_pattern_tree(struct match_char *pattern_tree);
-static int matchcid(const char *cidpattern, const char *callerid);
 static int hashtab_compare_contexts(const void *ah_a, const void *ah_b);
 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
@@ -354,7 +353,15 @@
 {
 	const struct ast_exten *ac = ah_a;
 	const struct ast_exten *bc = ah_b;
-	return strcmp(ac->exten, bc->exten);
+	int x = strcmp(ac->exten, bc->exten);
+	if (x) /* if exten names are diff, then return */
+		return x;
+	/* but if they are the same, do the cidmatch values match? */
+	if (ac->matchcid && bc->matchcid) {
+		return strcmp(ac->cidmatch,bc->cidmatch);
+	} else {
+		return 1; /* if there's matchcid on one but not the other, they are different */
+	}
 }
 
 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
@@ -380,7 +387,11 @@
 static unsigned int hashtab_hash_extens(const void *obj)
 {
 	const struct ast_exten *ac = obj;
-	return ast_hashtab_hash_string(ac->exten);
+	unsigned int x = ast_hashtab_hash_string(ac->exten);
+	unsigned int y = 0;
+	if (ac->matchcid)
+		y = ast_hashtab_hash_string(ac->cidmatch);
+	return x+y;
 }
 
 static unsigned int hashtab_hash_priority(const void *obj)
@@ -808,9 +819,7 @@
  *   of length 10; but they have total specificities of  96, 46, and 98, respectively. (b) wins with its lower specificity number!
  *
  *   Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown. But, it should
- *   be pretty close to optimal for this sort of overall algorithm. The only other improvement in speed I can imagine would involve locality
- *   of reference. For instance, if all that is wanted is the next priority in an extension, then, it would be wasteful to try matching
- *   extensions at that point in time! This is an easy optimization.
+ *   be pretty close to optimal for this sort of overall algorithm.
  *
  * */
 
@@ -821,12 +830,10 @@
 
 static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid)
 {
-	/* wait a minute, here's where we check that matchcid stuff... if they mismatch,
-	 * then there's no use in continuing the rest of the checks! */
-	if (exten->matchcid && !matchcid(exten->cidmatch, callerid))
-		return;       /* matchcid's didn't-- so this isn't a matching candidate */
-	else if (exten->matchcid)
-		length++;    /* if a cid match is made, then that should count at least as an extra matching digit */
+	/* doing a matchcid() check here would be easy and cheap, but...
+	   unfortunately, it only works if an extension can have only one 
+	   cid to match. That's not real life. CID patterns need to exist 
+	   in the tree for this sort of thing to work properly. */
 
 	if (length > board->total_length) {
 		board->total_specificity = spec;
@@ -842,7 +849,7 @@
 }
 
 #ifdef NEED_DEBUG
-static void print_match_char_tree(struct match_char *node, char *prefix)
+static void log_match_char_tree(struct match_char *node, char *prefix)
 {
 	char my_prefix[1024];
 	
@@ -856,6 +863,19 @@
 }
 #endif
 
+static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
+{
+	char my_prefix[1024];
+	
+	ast_cli(fd, "%s%s:%c:%d:%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', node->specificity, node->exten? "EXTEN":"");
+	strcpy(my_prefix,prefix);
+	strcat(my_prefix,"+-----------------");
+	if (node->next_char)
+		cli_match_char_tree(node->next_char, my_prefix, fd);
+	if (node->alt_char)
+		cli_match_char_tree(node->alt_char, prefix, fd);
+}
+
 struct ast_exten *get_canmatch_exten(struct match_char *node)
 {
 	/* find the exten at the end of the rope */
@@ -871,11 +891,14 @@
 	struct match_char *p; /* note minimal stack storage requirements */
 	for (p=tree; p; p=p->alt_char) {
 		if (p->x[0] == 'N' && p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
-			if (p->next_char && *(str+1))
-				new_find_extension(str+1, score, p->next_char, length+1, spec+8, callerid);
-			else if (p->exten) {
+			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
 				update_scoreboard(score, length+1, spec+8, p->exten,0,callerid);
-				return;
+
+			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
+				if (*(str+1))
+					new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
+				else
+					new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
 			} else if (p->next_char && !*(str+1)) {
 				score->canmatch = 1;
 				score->canmatch_exten = get_canmatch_exten(p);
@@ -883,11 +906,14 @@
 				return;
 			}
 		} else if (p->x[0] == 'Z' && p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
-			if (p->next_char && *(str+1))
-				new_find_extension(str+1, score, p->next_char, length+1, spec+9, callerid);
-			else if (p->exten) {
-				update_scoreboard(score, length+1, spec+9, p->exten,0, callerid);
-				return;
+			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+				update_scoreboard(score, length+1, spec+8, p->exten,0,callerid);
+
+			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
+				if (*(str+1))
+					new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
+				else
+					new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
 			} else if (p->next_char && !*(str+1)) {
 				score->canmatch = 1;
 				score->canmatch_exten = get_canmatch_exten(p);
@@ -895,29 +921,48 @@
 				return;
 			}
 		} else if (p->x[0] == 'X' && p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
-			if (p->next_char && *(str+1))
-				new_find_extension(str+1, score, p->next_char, length+1, spec+10, callerid);
-			else if (p->exten) {
-				update_scoreboard(score, length+1, spec+10, p->exten,0, callerid);
-				return;
+			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+				update_scoreboard(score, length+1, spec+8, p->exten,0,callerid);
+
+			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
+				if (*(str+1))
+					new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
+				else
+					new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
 			} else if (p->next_char && !*(str+1)) {
 				score->canmatch = 1;
 				score->canmatch_exten = get_canmatch_exten(p);
 			} else {
 				return;
 			}
-		} else if (p->x[0] == '.' && p->x[1] == 0 ) {
+		} else if (p->x[0] == '.' && p->x[1] == 0) {
 			update_scoreboard(score, length+1, spec+11, p->exten, '.', callerid);
+			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
+				new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
+			}
 			return;
-		} else if (p->x[0] == '!' && p->x[1] == 0 ) {
+		} else if (p->x[0] == '!' && p->x[1] == 0) {
 			update_scoreboard(score, length+1, spec+11, p->exten, '!', callerid);
+			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
+				new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
+			}
 			return;
+		} else if (p->x[0] == '/' && p->x[1] == 0) {
+			/* the pattern in the tree includes the cid match! */
+			if (p->next_char && callerid && *callerid) {
+				new_find_extension(callerid, score, p->next_char, length+1, spec, callerid);
+			}
 		} else if (index(p->x, *str)) {
-			if (p->next_char && *(str+1))
-				new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
-			else if (p->exten) {
-				update_scoreboard(score, length+1, spec+p->specificity, p->exten,0, callerid);
-				return;
+			if (p->exten) /* if a shorter pattern matches along the way, might as well report it */
+				update_scoreboard(score, length+1, spec+8, p->exten,0,callerid);
+
+
+			if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0))) {
+				if (*(str+1)) {
+					new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid);
+				} else {
+					new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid);
+				}
 			} else if (p->next_char && !*(str+1)) {
 				score->canmatch = 1;
 				score->canmatch_exten = get_canmatch_exten(p);
@@ -998,9 +1043,21 @@
 	int already;
 	int pattern = 0;
 	char buf[256];
-	char *s1 = e1->exten;
+	char extenbuf[512];
+	char *s1 = extenbuf;
+	int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
+	
+
+	strncpy(extenbuf,e1->exten,sizeof(extenbuf));
+	if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
+		strcat(extenbuf,"/");
+		strcat(extenbuf,e1->cidmatch);
+	} else if (l1 > sizeof(extenbuf)) {
+		ast_log(LOG_ERROR,"The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
+		return 0;
+	}
 #ifdef NEED_DEBUG
-	ast_log(LOG_DEBUG,"Adding exten %s to tree\n", s1);
+	ast_log(LOG_DEBUG,"Adding exten %s%c%s to tree\n", s1, e1->matchcid? '/':' ', e1->matchcid? e1->cidmatch : "");
 #endif
 	m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
 	already = 1;
@@ -1051,14 +1108,18 @@
 		}
 		
 		if (already && (m2=already_in_tree(m1,buf))) {
+			if (!(*(s1+1)))  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
+								a shorter pattern might win if the longer one doesn't match */
+				m1->exten = e1;
 			m1 = m2->next_char; /* m1 points to the node to compare against */
 		} else {
 			m1 = add_pattern_node(con, m1, buf, pattern, already,specif); /* m1 is the node just added */
+			if (!(*(s1+1)))
+				m1->exten = e1;
 			already = 0;
 		}
 		s1++; /* advance to next char */
 	}
-	m1->exten =  e1; /* that last node should have an exten pointer */
 	return m1;
 }
 
@@ -1431,17 +1492,6 @@
 #define STATUS_NO_PRIORITY	3
 #define STATUS_NO_LABEL		4
 #define STATUS_SUCCESS		5
-
-static int matchcid(const char *cidpattern, const char *callerid)
-{
-	/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
-	   failing to get a number should count as a match, otherwise not */
-
-	if (ast_strlen_zero(callerid))
-		return ast_strlen_zero(cidpattern) ? 1 : 0;
-
-	return ast_extension_match(cidpattern, callerid);
-}
 
 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
 	struct ast_context *bypass, struct pbx_find_info *q,
@@ -4208,6 +4258,13 @@
 					buf, ast_get_switch_registrar(sw));
 			}
 		}
+		
+		if (option_debug && c->pattern_tree)
+		{
+			ast_cli(fd," In-mem exten Trie for Fast Extension Pattern Matching:\r\b\n");
+			cli_match_char_tree(c->pattern_tree, " ", fd);
+		}
+		
 
 		ast_unlock_context(c);
 
@@ -5734,7 +5791,7 @@
 	}
 
 	if (tmp->matchcid) {
-		ast_verb(3, "Added extension '%s' priority %d (CID matcvih '%s')to %s\n",
+		ast_verb(3, "Added extension '%s' priority %d (CID match '%s')to %s\n",
 			tmp->exten, tmp->priority, tmp->cidmatch, con->name);
 	} else {
 		ast_verb(3, "Added extension '%s' priority %d to %s\n",




More information about the asterisk-commits mailing list