[asterisk-commits] murf: branch murf/fast-ast2 r87039 - /team/murf/fast-ast2/main/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Oct 25 12:19:05 CDT 2007
Author: murf
Date: Thu Oct 25 12:19:04 2007
New Revision: 87039
URL: http://svn.digium.com/view/asterisk?view=rev&rev=87039
Log:
Just the hashtab stuff folded back in; pulled the latest hashtab out of datastructs. It compiles.
Modified:
team/murf/fast-ast2/main/Makefile
team/murf/fast-ast2/main/pbx.c
Modified: team/murf/fast-ast2/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast2/main/Makefile?view=diff&rev=87039&r1=87038&r2=87039
==============================================================================
--- team/murf/fast-ast2/main/Makefile (original)
+++ team/murf/fast-ast2/main/Makefile Thu Oct 25 12:19:04 2007
@@ -27,7 +27,7 @@
netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
- astobj2.o
+ astobj2.o hashtab.o
# we need to link in the objects statically, not as a library, because
# otherwise modules will not have them available if none of the static
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=87039&r1=87038&r2=87039
==============================================================================
--- team/murf/fast-ast2/main/pbx.c (original)
+++ team/murf/fast-ast2/main/pbx.c Thu Oct 25 12:19:04 2007
@@ -67,6 +67,7 @@
#include "asterisk/devicestate.h"
#include "asterisk/stringfields.h"
#include "asterisk/event.h"
+#include "asterisk/hashtab.h"
#include "asterisk/module.h"
/*!
@@ -76,6 +77,17 @@
* aspects of this PBX. The switching scheme as it exists right now isn't
* terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
* of priorities, but a constant search time here would be great ;-)
+ *
+ * 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
+ * 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,
+ * I'm using hash tables, which do searches (ideally) in O(1) time.
*
*/
@@ -132,6 +144,8 @@
void *data; /*!< Data to use (arguments) */
void (*datad)(void *); /*!< Data destructor */
struct ast_exten *peer; /*!< Next higher priority with our extension */
+ struct ast_hashtab *peer_tree; /*!< Priorities list in tree form -- only on the head of the peer list */
+ struct ast_hashtab *peer_label_tree; /*!< labeled priorities in the peer list -- only on the head of the peer list */
const char *registrar; /*!< Registrar */
struct ast_exten *next; /*!< Extension with a greater ID */
char stuff[0];
@@ -166,10 +180,33 @@
const char pattern[0];
};
+/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
+struct match_char
+{
+ int is_pattern; /* the pattern started with '_' */
+ char *x;
+ int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
+ struct match_char *alt_char;
+ struct match_char *next_char;
+ struct ast_exten *exten; /* attached to last char of a pattern for exten */
+};
+
+struct scoreboard /* make sure all fields are 0 before calling new_find_extension */
+{
+ int total_specificity;
+ int total_length;
+ char last_char; /* set to ! or . if they are the end of the pattern */
+ int canmatch; /* if the string to match was just too short */
+ struct ast_exten *canmatch_exten;
+ struct ast_exten *exten;
+};
+
/*! \brief ast_context: An extension context */
struct ast_context {
ast_rwlock_t lock; /*!< A lock to prevent multiple threads from clobbering the context */
struct ast_exten *root; /*!< The root of the list of extensions */
+ struct ast_hashtab *root_tree; /*!< The root of the list of extensions in threaded red-black tree form */
+ struct match_char *pattern_tree; /*!< A tree to speed up extension pattern matching */
struct ast_context *next; /*!< Link them together */
struct ast_include *includes; /*!< Include other contexts */
struct ast_ignorepat *ignorepats; /*!< Patterns for which to continue playing dialtone */
@@ -283,6 +320,75 @@
static int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
static int pbx_builtin_importvar(struct ast_channel *, void *);
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
+void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid);
+struct match_char *already_in_tree(struct match_char *current, char *pat);
+struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity);
+struct match_char *create_match_char_tree(struct ast_context *con);
+struct ast_exten *get_canmatch_exten(struct match_char *node);
+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);
+static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
+static int hashtab_hash_contexts(const void *obj);
+static int hashtab_hash_extens(const void *obj);
+static int hashtab_hash_priority(const void *obj);
+static int hashtab_hash_labels(const void *obj);
+
+/* labels, contexts are case sensitive priority numbers are ints */
+static int hashtab_compare_contexts(const void *ah_a, const void *ah_b)
+{
+ const struct ast_context *ac = ah_a;
+ const struct ast_context *bc = ah_b;
+ /* assume context names are registered in a string table! */
+ return ac->name != bc->name;
+}
+
+static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
+{
+ const struct ast_exten *ac = ah_a;
+ const struct ast_exten *bc = ah_b;
+ return strcmp(ac->exten, bc->exten);
+}
+
+static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
+{
+ const struct ast_exten *ac = ah_a;
+ const struct ast_exten *bc = ah_b;
+ return ac->priority != bc->priority;
+}
+
+static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
+{
+ const struct ast_exten *ac = ah_a;
+ const struct ast_exten *bc = ah_b;
+ return ac->label != bc->label;
+}
+
+static int hashtab_hash_contexts(const void *obj)
+{
+ const struct ast_context *ac = obj;
+ return ast_hashtab_hash_string(ac->name);
+}
+
+static int hashtab_hash_extens(const void *obj)
+{
+ const struct ast_exten *ac = obj;
+ return ast_hashtab_hash_string(ac->exten);
+}
+
+static int hashtab_hash_priority(const void *obj)
+{
+ const struct ast_exten *ac = obj;
+ return ast_hashtab_hash_int(ac->priority);
+}
+
+static int hashtab_hash_labels(const void *obj)
+{
+ const struct ast_exten *ac = obj;
+ return ast_hashtab_hash_string(ac->label);
+}
+
AST_RWLOCK_DEFINE_STATIC(globalslock);
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
@@ -554,6 +660,8 @@
};
static struct ast_context *contexts;
+static struct ast_hashtab *contexts_tree = NULL;
+
AST_RWLOCK_DEFINE_STATIC(conlock); /*!< Lock for the ast_context list */
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
@@ -647,6 +755,296 @@
static void pbx_destroy(struct ast_pbx *p)
{
ast_free(p);
+}
+
+/* form a tree that fully describes all the patterns in a context's extensions
+ * in this tree, a "node" consists of a series of match_char structs linked in a chain
+ * via the alt_char pointers. More than one pattern can share the same parts of the
+ * tree as other extensions with the same pattern to that point. The algorithm to
+ * find which pattern best matches a string, would follow **all** matching paths. As
+ * complete matches are found, a "max" match record would be updated if the match first involves
+ * a longer string, then, on a tie, a smaller total of specificity. This can be accomplished
+ * by recursive calls affecting a shared scoreboard.
+ * As and example, consider these 4 extensions:
+ * (a) NXXNXXXXXX
+ * (b) 307754XXXX
+ * (c) fax
+ * (d) NXXXXXXXXX
+ *
+ * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
+ * most numbers. For all numbers beginning with 307754, (b) should always win.
+ *
+ * These pattern should form a tree that looks like this:
+ * { "N" } --next--> { "X" } --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
+ * | |
+ * | |alt
+ * |alt |
+ * | { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
+ * |
+ * { "3" } --next--> { "0" } --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
+ * |
+ * |alt
+ * |
+ * { "f" } --next--> { "a" } --next--> { "x" exten_match: (c) }
+ *
+ * In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
+ * fewer CPU cycles than a call to index("23456789",*z), where *z is the char to match...
+ *
+ * traversal is pretty simple: one routine merely traverses the alt list, and for each match in the pattern, it calls itself
+ * on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
+ * We pass a pointer to a scoreboard down through, also.
+ * When an exten_match pointer is set, or a '.' or a '!' is encountered, we update the scoreboard only if the length is greater, or in case
+ * of equal length, if the specificity is lower, and return. Hope the limit on stack depth won't be a problem... this routine should
+ * be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
+ *
+ * In the above example, with the number "3077549999" as the pattern, the traversor should match extensions a, b and d. All are
+ * 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.
+ *
+ * */
+
+/* you only really update the scoreboard, if the new score is BETTER than the
+ * one stored there. ignore it otherwise.
+ */
+
+
+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 */
+
+ if (length > board->total_length) {
+ board->total_specificity = spec;
+ board->total_length = length;
+ board->exten = exten;
+ board->last_char = last;
+ } else if (length == board->total_length && spec < board->total_specificity) {
+ board->total_specificity = spec;
+ board->total_length = length;
+ board->exten = exten;
+ board->last_char = last;
+ }
+}
+
+struct ast_exten *get_canmatch_exten(struct match_char *node)
+{
+ /* find the exten at the end of the rope */
+ struct match_char *node2 = node;
+ for (node2 = node; node2; node2 = node2->next_char)
+ if (node2->exten)
+ return node2->exten;
+ return 0;
+}
+
+void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid)
+{
+ 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) {
+ update_scoreboard(score, length+1, spec+8, p->exten,0,callerid);
+ return;
+ } else if (p->next_char && !*(str+1)) {
+ score->canmatch = 1;
+ score->canmatch_exten = get_canmatch_exten(p);
+ } else {
+ 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;
+ } else if (p->next_char && !*(str+1)) {
+ score->canmatch = 1;
+ score->canmatch_exten = get_canmatch_exten(p);
+ } else {
+ 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;
+ } 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 ) {
+ update_scoreboard(score, length+1, spec+11, p->exten, '.', callerid);
+ return;
+ } else if (p->x[0] == '!' && p->x[1] == 0 ) {
+ update_scoreboard(score, length+1, spec+11, p->exten, '!', callerid);
+ return;
+ } 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;
+ } else if (p->next_char && !*(str+1)) {
+ score->canmatch = 1;
+ score->canmatch_exten = get_canmatch_exten(p);
+ } else {
+ return;
+ }
+
+ }
+ }
+}
+
+/* the algorithm for forming the extension pattern tree is also a bit simple; you
+ * traverse all the extensions in a context, and for each char of the extension,
+ * you see if it exists in the tree; if it doesn't, you add it at the appropriate
+ * spot. What more can I say? At the end of the list, you cap it off by adding the
+ * address of the extension involved. Duplicate patterns will be complained about.
+ *
+ * Ideally, this would be done for each context after it is created and fully
+ * filled. It could be done as a finishing step after extensions.conf or .ael is
+ * loaded, or it could be done when the first search is encountered. It should only
+ * have to be done once, until the next unload or reload.
+ *
+ * I guess forming this pattern tree would be analogous to compiling a regex.
+ */
+
+
+struct match_char *already_in_tree(struct match_char *current, char *pat)
+{
+ struct match_char *t;
+ if (!current)
+ return 0;
+ for (t=current; t; t=t->alt_char) {
+ if (strcmp(pat,t->x) == 0) /* uh, we may want to sort exploded [] contents to make matching easy */
+ return t;
+ }
+ return 0;
+}
+
+struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity)
+{
+ struct match_char *m = ast_calloc(1,sizeof(struct match_char));
+ m->x = strdup(pattern);
+ m->is_pattern = is_pattern;
+ if (specificity == 1 && is_pattern && pattern[0] == 'N')
+ m->specificity = 8;
+ else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
+ m->specificity = 9;
+ else if (specificity == 1 && is_pattern && pattern[0] == 'X')
+ m->specificity = 10;
+ else if (specificity == 1 && is_pattern && pattern[0] == '.')
+ m->specificity = 11;
+ else if (specificity == 1 && is_pattern && pattern[0] == '!')
+ m->specificity = 11;
+ else
+ m->specificity = specificity;
+
+ if (!con->pattern_tree) {
+ con->pattern_tree = m;
+ } else {
+ if (already) { /* switch to the new regime (traversing vs appending)*/
+ m->alt_char = current->alt_char;
+ current->alt_char = m;
+ } else {
+ if (current->next_char) {
+ m->alt_char = current->next_char->alt_char;
+ current->next_char = m;
+ } else {
+ current->next_char = m;
+ }
+ }
+ }
+ return m;
+}
+
+struct match_char *create_match_char_tree(struct ast_context *con)
+{
+ struct ast_hashtab_iter *t1;
+ struct ast_exten *e1;
+ struct match_char *m1,*m2;
+ char buf[256];
+ int already;
+ int specif;
+
+ t1 = ast_hashtab_start_traversal(con->root_tree);
+ while( (e1 = ast_hashtab_next(t1)) ) {
+ int pattern = 0;
+ char *s1 = e1->exten;
+ m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
+ already = 1;
+
+ if ( *s1 == '_') {
+ pattern = 1;
+ s1++;
+ }
+ while( *s1 )
+ {
+ if (pattern && *s1 == '[' && *(s1-1) != '\\') {
+ char *s2 = buf;
+ while (*s1 != ']' && *(s1-1) != '\\' ) {
+ if (*s1 == '\\') {
+ if (*(s1+1) == ']') {
+ *s2++ = ']';
+ s1++;s1++;
+ } else if (*(s1+1) == '\\') {
+ *s2++ = '\\';
+ s1++;s1++;
+ } else if (*(s1+1) == '-') {
+ *s2++ = '-';
+ s1++; s1++;
+ } else if (*(s1+1) == '[') {
+ *s2++ = '[';
+ s1++; s1++;
+ }
+ } else if (*s1 == '-') { /* remember to add some error checking to all this! */
+ char s3 = *(s1-1);
+ char s4 = *(s1+1);
+ for (s3++; s3 <= s4; s3++) {
+ *s2++ = s3;
+ }
+ s1++; s1++;
+ } else {
+ *s2++ = *s1++;
+ }
+ }
+ specif = strlen(buf);
+ } else {
+ if (*s1 == '\\') {
+ s1++;
+ buf[0] = *s1;
+ } else {
+ buf[0] = *s1;
+ }
+ buf[1] = 0;
+ specif = 1;
+ }
+
+ if (already && (m2=already_in_tree(m1,buf))) {
+ 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 */
+ already = 0;
+ }
+ s1++; /* advance to next char */
+ }
+ m1->exten = e1; /* that last node should have an exten pointer */
+ }
+ return m1; /* just in case you want to see how the pattern ended */
}
/*
@@ -938,14 +1336,35 @@
return extension_match_core(pattern, data, needmore);
}
+struct fake_context /* this struct is purely for matching in the hashtab */
+{
+ ast_mutex_t lock;
+ struct ast_exten *root;
+ struct trb_table *root_tree;
+ struct match_char *pattern_tree;
+ struct ast_context *next;
+ struct ast_include *includes;
+ struct ast_ignorepat *ignorepats;
+ const char *registrar;
+ AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
+ ast_mutex_t macrolock;
+ char name[256];
+};
+
struct ast_context *ast_context_find(const char *name)
{
struct ast_context *tmp = NULL;
+ struct fake_context item;
+ strncpy(item.name,name,256);
ast_rdlock_contexts();
+ if( contexts_tree )
+ tmp = ast_hashtab_lookup(contexts_tree,&item);
+#ifdef NOTNOW
while ( (tmp = ast_walk_contexts(tmp)) ) {
if (!name || !strcasecmp(name, tmp->name))
break;
}
+#endif
ast_unlock_contexts();
return tmp;
}
@@ -977,6 +1396,12 @@
struct ast_exten *e, *eroot;
struct ast_include *i;
struct ast_sw *sw;
+ struct ast_exten pattern;
+ struct scoreboard score;
+
+ pattern.label = label;
+ pattern.priority = priority;
+
/* Initialize status if appropriate */
if (q->stacklen == 0) {
@@ -998,18 +1423,65 @@
if (bypass) /* bypass means we only look there */
tmp = bypass;
else { /* look in contexts */
+ struct fake_context item;
+ strncpy(item.name,context,256);
+ tmp = ast_hashtab_lookup(contexts_tree,&item);
+#ifdef NOTNOW
tmp = NULL;
while ((tmp = ast_walk_contexts(tmp)) ) {
if (!strcmp(tmp->name, context))
break;
}
+#endif
if (!tmp)
return NULL;
}
if (q->status < STATUS_NO_EXTENSION)
q->status = STATUS_NO_EXTENSION;
-
+
+ /* Do a search for matching extension */
+ eroot = NULL;
+ score.total_specificity = 0;
+ score.exten = 0;
+ score.total_length = 0;
+ if (!tmp->pattern_tree)
+ create_match_char_tree(tmp);
+ new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid);
+ eroot = score.exten;
+
+ if (score.last_char == '!' && action == E_MATCHMORE) {
+ /* We match an extension ending in '!'.
+ * The decision in this case is final and is NULL (no match).
+ */
+ return NULL;
+ }
+
+ if (!eroot && action == E_CANMATCH && score.canmatch_exten) {
+ q->status = STATUS_SUCCESS;
+ return score.canmatch_exten;
+ }
+
+ if (eroot) {
+ /* found entry, now look for the right priority */
+ if (q->status < STATUS_NO_PRIORITY)
+ q->status = STATUS_NO_PRIORITY;
+ e = NULL;
+ if (action == E_FINDLABEL && label ) {
+ if (q->status < STATUS_NO_LABEL)
+ q->status = STATUS_NO_LABEL;
+ e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+ } else {
+ e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+ }
+ if (e) { /* found a valid match */
+ q->status = STATUS_SUCCESS;
+ q->foundcontext = context;
+ return e;
+ }
+ }
+
+#ifdef NOTNOW2
/* scan the list trying to match extension and CID */
eroot = NULL;
while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
@@ -1028,6 +1500,14 @@
if (q->status < STATUS_NO_PRIORITY)
q->status = STATUS_NO_PRIORITY;
e = NULL;
+ if (action == E_FINDLABEL && label ) {
+ if (q->status < STATUS_NO_LABEL)
+ q->status = STATUS_NO_LABEL;
+ e = ast_hashtab_lookup(eroot->peer_label_tree, &pattern);
+ } else {
+ e = ast_hashtab_lookup(eroot->peer_tree, &pattern);
+ }
+#ifdef NOTNOW
while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
/* Match label or priority */
if (action == E_FINDLABEL) {
@@ -1039,12 +1519,14 @@
break; /* found it */
} /* else keep searching */
}
+#endif
if (e) { /* found a valid match */
q->status = STATUS_SUCCESS;
q->foundcontext = context;
return e;
}
}
+#endif
/* Check alternative switches */
AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
struct ast_switch *asw = pbx_findswitch(sw->name);
@@ -2733,6 +3215,10 @@
if (e->priority == PRIORITY_HINT)
ast_remove_hint(e);
+ if (e->peer_tree)
+ ast_hashtab_destroy(e->peer_tree,0);
+ if (e->peer_label_tree)
+ ast_hashtab_destroy(e->peer_label_tree, 0);
if (e->datad)
e->datad(e->data);
ast_free(e);
@@ -2812,15 +3298,20 @@
static struct ast_context *find_context_locked(const char *context)
{
struct ast_context *c = NULL;
-
+ struct fake_context item;
+ strncpy(item.name, context, 256);
ast_rdlock_contexts();
+ c = ast_hashtab_lookup(contexts_tree,&item);
+#ifdef NOTNOW
+
while ( (c = ast_walk_contexts(c)) ) {
if (!strcmp(ast_get_context_name(c), context))
return c;
}
+#endif
ast_unlock_contexts();
- return NULL;
+ return c;
}
/*!
@@ -3038,8 +3529,17 @@
{
struct ast_context *c = NULL;
int ret = -1;
+ struct fake_context item;
ast_rdlock_contexts();
+
+ strncpy(item.name,context,256);
+ c = ast_hashtab_lookup(contexts_tree,&item);
+ if (c)
+ ret = 0;
+
+
+#ifdef NOTNOW
while ((c = ast_walk_contexts(c))) {
if (!strcmp(ast_get_context_name(c), context)) {
@@ -3048,6 +3548,7 @@
}
}
+#endif
ast_unlock_contexts();
/* if we found context, lock macrolock */
@@ -3066,8 +3567,15 @@
{
struct ast_context *c = NULL;
int ret = -1;
+ struct fake_context item;
ast_rdlock_contexts();
+
+ strncpy(item.name, context, 256);
+ c = ast_hashtab_lookup(contexts_tree,&item);
+ if (c)
+ ret = 0;
+#ifdef NOTNOW
while ((c = ast_walk_contexts(c))) {
if (!strcmp(ast_get_context_name(c), context)) {
@@ -3076,6 +3584,7 @@
}
}
+#endif
ast_unlock_contexts();
/* if we found context, unlock macrolock */
@@ -4020,7 +4529,23 @@
static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
{
struct ast_context *tmp, **local_contexts;
+ struct fake_context search;
int length = sizeof(struct ast_context) + strlen(name) + 1;
+
+ if (!contexts_tree)
+ contexts_tree = ast_hashtab_create(17,
+ hashtab_compare_contexts,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_contexts,
+ 1);
+ strncpy(search.name,name,sizeof(search.name));
+ tmp = ast_hashtab_lookup(contexts_tree, &search);
+
+ if (!existsokay && tmp) {
+ ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
+ return tmp;
+ }
if (!extcontexts) {
ast_wrlock_contexts();
@@ -4028,6 +4553,7 @@
} else
local_contexts = extcontexts;
+#ifdef NO_MORE
for (tmp = *local_contexts; tmp; tmp = tmp->next) {
if (!strcasecmp(tmp->name, name)) {
if (!existsokay) {
@@ -4039,16 +4565,19 @@
return tmp;
}
}
+#endif
if ((tmp = ast_calloc(1, length))) {
ast_rwlock_init(&tmp->lock);
ast_mutex_init(&tmp->macrolock);
strcpy(tmp->name, name);
tmp->root = NULL;
+ tmp->root_tree = NULL;
tmp->registrar = registrar;
tmp->next = *local_contexts;
tmp->includes = NULL;
tmp->ignorepats = NULL;
*local_contexts = tmp;
+ ast_hashtab_insert_safe(contexts_tree, tmp); /*put this context into the tree */
ast_debug(1, "Registered context '%s'\n", tmp->name);
ast_verb(3, "Registered extension context '%s'\n", tmp->name);
}
@@ -4829,12 +5358,16 @@
struct ast_exten *el, struct ast_exten *e, int replace)
{
struct ast_exten *ep;
+ struct ast_exten *eh=e;
for (ep = NULL; e ; ep = e, e = e->peer) {
if (e->priority >= tmp->priority)
break;
}
if (!e) { /* go at the end, and ep is surely set because the list is not empty */
+ ast_hashtab_insert_safe(eh->peer_tree, tmp);
+ if (tmp->label)
+ ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
ep->peer = tmp;
return 0; /* success */
}
@@ -4853,12 +5386,41 @@
*/
tmp->next = e->next; /* not meaningful if we are not first in the peer list */
tmp->peer = e->peer; /* always meaningful */
- if (ep) /* We're in the peer list, just insert ourselves */
+ if (ep) { /* We're in the peer list, just insert ourselves */
+ ast_hashtab_remove_object_via_lookup(eh->peer_tree,e);
+ if (e->label)
+ ast_hashtab_remove_object_via_lookup(eh->peer_label_tree,e);
+ ast_hashtab_insert_safe(eh->peer_tree,tmp);
+ if (tmp->label)
+ ast_hashtab_insert_safe(eh->peer_label_tree,tmp);
ep->peer = tmp;
- else if (el) /* We're the first extension. Take over e's functions */
+ } else if (el) { /* We're the first extension. Take over e's functions */
+ tmp->peer_tree = e->peer_tree;
+ tmp->peer_label_tree = e->peer_label_tree;
+ ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
+ ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+ if (e->label)
+ ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+ if (tmp->label)
+ ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+ ast_hashtab_remove_object_via_lookup(con->root_tree, e->exten);
+ ast_hashtab_insert_safe(con->root_tree, tmp->exten);
el->next = tmp;
- else /* We're the very first extension. */
- con->root = tmp;
+ } else { /* We're the very first extension. */
+ ast_hashtab_remove_object_via_lookup(con->root_tree,e);
+ ast_hashtab_insert_safe(con->root_tree,tmp);
+ tmp->peer_tree = e->peer_tree;
+ tmp->peer_label_tree = e->peer_label_tree;
+ ast_hashtab_remove_object_via_lookup(tmp->peer_tree,e);
+ ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+ if (e->label)
+ ast_hashtab_remove_object_via_lookup(tmp->peer_label_tree,e);
+ if (tmp->label)
+ ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+ ast_hashtab_remove_object_via_lookup(con->root_tree, e->exten);
+ ast_hashtab_insert_safe(con->root_tree, tmp->exten);
+ con->root = tmp;
+ }
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e,tmp);
/* Destroy the old one */
@@ -4868,9 +5430,22 @@
} else { /* Slip ourselves in just before e */
tmp->peer = e;
tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
- if (ep) /* Easy enough, we're just in the peer list */
+ if (ep) { /* Easy enough, we're just in the peer list */
+ if (tmp->label)
+ ast_hashtab_insert_safe(eh->peer_label_tree, tmp);
+ ast_hashtab_insert_safe(eh->peer_tree, tmp);
ep->peer = tmp;
- else { /* we are the first in some peer list, so link in the ext list */
+ } else { /* we are the first in some peer list, so link in the ext list */
+ tmp->peer_tree = e->peer_tree;
+ tmp->peer_label_tree = e ->peer_label_tree;
+ e->peer_tree = 0;
+ e->peer_label_tree = 0;
+ ast_hashtab_insert_safe(tmp->peer_tree,tmp);
+ if (tmp->label) {
+ ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+ }
+ ast_hashtab_remove_object_via_lookup(con->root_tree,e);
+ ast_hashtab_insert_safe(con->root_tree,tmp);
if (el)
el->next = tmp; /* in the middle... */
else
@@ -5005,10 +5580,49 @@
* so insert in the main list right before 'e' (if any)
*/
tmp->next = e;
- if (el)
+ if (el) {
el->next = tmp;
- else
+ tmp->peer_tree = ast_hashtab_create(13,
+ hashtab_compare_exten_numbers,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_priority,
+ 1);
+ tmp->peer_label_tree = ast_hashtab_create(7,
+ hashtab_compare_exten_labels,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_labels,
+ 1);
+ if (label)
+ ast_hashtab_insert_safe(tmp->peer_label_tree,tmp);
+ ast_hashtab_insert_safe(tmp->peer_tree, tmp);
+
+ } else {
+ con->root_tree = ast_hashtab_create(27,
+ hashtab_compare_extens,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_extens,
+ 1);
con->root = tmp;
+ con->root->peer_tree = ast_hashtab_create(13,
+ hashtab_compare_exten_numbers,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_priority,
+ 1);
+ con->root->peer_label_tree = ast_hashtab_create(7,
+ hashtab_compare_exten_labels,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_labels,
+ 1);
+ if (label)
+ ast_hashtab_insert_safe(con->root->peer_label_tree,tmp);
+ ast_hashtab_insert_safe(con->root->peer_tree, tmp);
+ }
+ ast_hashtab_insert_safe(con->root_tree, tmp);
ast_unlock_context(con);
if (tmp->priority == PRIORITY_HINT)
ast_add_hint(tmp);
@@ -5443,6 +6057,8 @@
break;
ast_wrlock_context(tmp);
ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+ ast_hashtab_remove_this_object(contexts_tree,tmp);
+
next = tmp->next;
if (tmpl)
tmpl->next = next;
More information about the asterisk-commits
mailing list