[asterisk-commits] dlee: branch dlee/hashtab-skiplist r399768 - in /team/dlee/hashtab-skiplist: ...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Sep 24 18:39:59 CDT 2013


Author: dlee
Date: Tue Sep 24 18:39:56 2013
New Revision: 399768

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=399768
Log:
Merged revisions 399752-399764 from http://svn.asterisk.org/svn/asterisk/team/group/performance

Modified:
    team/dlee/hashtab-skiplist/   (props changed)
    team/dlee/hashtab-skiplist/apps/app_queue.c
    team/dlee/hashtab-skiplist/channels/chan_iax2.c
    team/dlee/hashtab-skiplist/main/astobj2.c
    team/dlee/hashtab-skiplist/main/cdr.c
    team/dlee/hashtab-skiplist/main/stasis_bridges.c
    team/dlee/hashtab-skiplist/tests/test_cdr.c

Propchange: team/dlee/hashtab-skiplist/
------------------------------------------------------------------------------
Binary property 'branch-11-merged' - no diff available.

Propchange: team/dlee/hashtab-skiplist/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Sep 24 18:39:56 2013
@@ -1,1 +1,1 @@
-/team/group/performance:1-399750
+/team/group/performance:1-399767

Modified: team/dlee/hashtab-skiplist/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/hashtab-skiplist/apps/app_queue.c?view=diff&rev=399768&r1=399767&r2=399768
==============================================================================
--- team/dlee/hashtab-skiplist/apps/app_queue.c (original)
+++ team/dlee/hashtab-skiplist/apps/app_queue.c Tue Sep 24 18:39:56 2013
@@ -5914,6 +5914,8 @@
 	const char *monitor_options;
 	const char *monitor_exec;
 
+	escaped_monitor_exec[0] = '\0';
+
 	if (filename) {
 		escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
 	} else {

Modified: team/dlee/hashtab-skiplist/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/hashtab-skiplist/channels/chan_iax2.c?view=diff&rev=399768&r1=399767&r2=399768
==============================================================================
--- team/dlee/hashtab-skiplist/channels/chan_iax2.c (original)
+++ team/dlee/hashtab-skiplist/channels/chan_iax2.c Tue Sep 24 18:39:56 2013
@@ -5517,34 +5517,44 @@
 			break;
 		}
 		other = (who == c0) ? c1 : c0;  /* the 'other' channel */
-		if ((f->frametype == AST_FRAME_CONTROL)) {
-			if (f->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) {
+		if (f->frametype == AST_FRAME_CONTROL) {
+			switch (f->subclass.integer) {
+			case AST_CONTROL_VIDUPDATE:
+			case AST_CONTROL_SRCUPDATE:
+			case AST_CONTROL_SRCCHANGE:
+			case AST_CONTROL_T38_PARAMETERS:
+				ast_write(other, f);
+				break;
+			case AST_CONTROL_PVT_CAUSE_CODE:
 				ast_channel_hangupcause_hash_set(other, f->data.ptr, f->datalen);
-			} else if (f->subclass.integer != AST_CONTROL_SRCUPDATE) {
+				break;
+			default:
 				*fo = f;
 				*rc = who;
-				res =  AST_BRIDGE_COMPLETE;
+				res = AST_BRIDGE_COMPLETE;
 				break;
 			}
-		}
-		if ((f->frametype == AST_FRAME_VOICE) ||
-			(f->frametype == AST_FRAME_TEXT) ||
-			(f->frametype == AST_FRAME_VIDEO) ||
-			(f->frametype == AST_FRAME_IMAGE) ||
-			(f->frametype == AST_FRAME_DTMF) ||
-			(f->frametype == AST_FRAME_CONTROL && f->subclass.integer != AST_CONTROL_PVT_CAUSE_CODE)) {
+			if (res == AST_BRIDGE_COMPLETE) {
+				break;
+			}
+		} else if (f->frametype == AST_FRAME_VOICE
+			|| f->frametype == AST_FRAME_TEXT
+			|| f->frametype == AST_FRAME_VIDEO
+			|| f->frametype == AST_FRAME_IMAGE) {
+			ast_write(other, f);
+		} else if (f->frametype == AST_FRAME_DTMF) {
 			/* monitored dtmf take out of the bridge.
 			 * check if we monitor the specific source.
 			 */
 			int monitored_source = (who == c0) ? AST_BRIDGE_DTMF_CHANNEL_0 : AST_BRIDGE_DTMF_CHANNEL_1;
-			if (f->frametype == AST_FRAME_DTMF && (flags & monitored_source)) {
+
+			if (flags & monitored_source) {
 				*rc = who;
 				*fo = f;
 				res = AST_BRIDGE_COMPLETE;
 				/* Remove from native mode */
 				break;
 			}
-			/* everything else goes to the other side */
 			ast_write(other, f);
 		}
 		ast_frfree(f);

Modified: team/dlee/hashtab-skiplist/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/hashtab-skiplist/main/astobj2.c?view=diff&rev=399768&r1=399767&r2=399768
==============================================================================
--- team/dlee/hashtab-skiplist/main/astobj2.c (original)
+++ team/dlee/hashtab-skiplist/main/astobj2.c Tue Sep 24 18:39:56 2013
@@ -1175,7 +1175,8 @@
 		return NULL;
 	}
 
-	flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+	flags &= ~OBJ_SEARCH_MASK;
+	flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
 	__ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
 
 	return NULL;
@@ -1189,7 +1190,8 @@
 		return NULL;
 	}
 
-	flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
+	flags &= ~OBJ_SEARCH_MASK;
+	flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
 	__ao2_callback(c, flags, ao2_match_by_addr, user_data);
 
 	return NULL;
@@ -2132,7 +2134,7 @@
 		return NULL;
 	}
 
-	i = abs(self->hash_fn(obj_new, OBJ_POINTER));
+	i = abs(self->hash_fn(obj_new, OBJ_SEARCH_OBJECT));
 	i %= self->n_buckets;
 
 	if (tag) {
@@ -2177,7 +2179,7 @@
 	if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
 		if (sort_fn) {
 			AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
-				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp > 0) {
 					continue;
 				}
@@ -2209,7 +2211,7 @@
 	} else {
 		if (sort_fn) {
 			AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
-				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp < 0) {
 					continue;
 				}
@@ -2309,15 +2311,24 @@
 	 * If lookup by pointer or search key, run the hash and optional
 	 * sort functions.  Otherwise, traverse the whole container.
 	 */
-	if (flags & (OBJ_POINTER | OBJ_KEY)) {
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+	case OBJ_SEARCH_KEY:
 		/* we know hash can handle this case */
-		bucket_cur = abs(self->hash_fn(arg, flags & (OBJ_POINTER | OBJ_KEY)));
+		bucket_cur = abs(self->hash_fn(arg, flags & OBJ_SEARCH_MASK));
 		bucket_cur %= self->n_buckets;
 		state->sort_fn = self->common.sort_fn;
-	} else {
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		/* scan all buckets for partial key matches */
+		bucket_cur = -1;
+		state->sort_fn = self->common.sort_fn;
+		break;
+	default:
 		/* don't know, let's scan all buckets */
 		bucket_cur = -1;
-		state->sort_fn = (flags & OBJ_PARTIAL_KEY) ? self->common.sort_fn : NULL;
+		state->sort_fn = NULL;
+		break;
 	}
 
 	if (state->descending) {
@@ -2353,8 +2364,7 @@
 
 				if (state->sort_fn) {
 					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg,
-						flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
 					if (cmp > 0) {
 						continue;
 					}
@@ -2379,7 +2389,7 @@
 			/* Was this the starting bucket? */
 			if (bucket_cur == state->bucket_start
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* In case the bucket was empty or none of the nodes matched. */
 				state->sort_fn = NULL;
 			}
@@ -2387,7 +2397,7 @@
 			/* Was this the first container bucket? */
 			if (bucket_cur == 0
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* Move to the end to ensure we check every bucket */
 				bucket_cur = self->n_buckets;
 				state->bucket_last = state->bucket_start + 1;
@@ -2434,8 +2444,7 @@
 
 				if (state->sort_fn) {
 					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg,
-						flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
 					if (cmp < 0) {
 						continue;
 					}
@@ -2460,7 +2469,7 @@
 			/* Was this the starting bucket? */
 			if (bucket_cur == state->bucket_start
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* In case the bucket was empty or none of the nodes matched. */
 				state->sort_fn = NULL;
 			}
@@ -2468,7 +2477,7 @@
 			/* Was this the last container bucket? */
 			if (bucket_cur == self->n_buckets - 1
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* Move to the beginning to ensure we check every bucket */
 				bucket_cur = -1;
 				state->bucket_last = state->bucket_start;
@@ -2541,8 +2550,7 @@
 
 				if (state->sort_fn) {
 					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg,
-						flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
 					if (cmp > 0) {
 						continue;
 					}
@@ -2573,7 +2581,7 @@
 			/* Was this the first container bucket? */
 			if (bucket_cur == 0
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* Move to the end to ensure we check every bucket */
 				bucket_cur = self->n_buckets;
 				state->bucket_last = state->bucket_start + 1;
@@ -2608,8 +2616,7 @@
 
 				if (state->sort_fn) {
 					/* Filter node through the sort_fn */
-					cmp = state->sort_fn(node->common.obj, arg,
-						flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+					cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
 					if (cmp < 0) {
 						continue;
 					}
@@ -2640,7 +2647,7 @@
 			/* Was this the last container bucket? */
 			if (bucket_cur == self->n_buckets - 1
 				&& (flags & OBJ_CONTINUE)
-				&& (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
+				&& (flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_NONE) {
 				/* Move to the beginning to ensure we check every bucket */
 				bucket_cur = -1;
 				state->bucket_last = state->bucket_start;
@@ -3042,7 +3049,7 @@
 			++count_obj;
 
 			/* Check container hash key for expected bucket. */
-			bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_POINTER));
+			bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_SEARCH_OBJECT));
 			bucket_exp %= self->n_buckets;
 			if (bucket != bucket_exp) {
 				ast_log(LOG_ERROR, "Bucket %d node hashes to bucket %d!\n",
@@ -3053,7 +3060,7 @@
 			/* Check sort if configured. */
 			if (self->common.sort_fn) {
 				if (obj_last
-					&& self->common.sort_fn(obj_last, node->common.obj, OBJ_POINTER) > 0) {
+					&& self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
 					ast_log(LOG_ERROR, "Bucket %d nodes out of sorted order!\n",
 						bucket);
 					return -1;
@@ -3509,9 +3516,9 @@
  * \param sort_fn Sort comparison function for non-empty nodes.
  * \param obj_right pointer to the (user-defined part) of an object.
  * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
+ *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
+ *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
  * \param bias How to bias search direction for duplicates
  *
  * \return enum empty_node_direction to proceed.
@@ -4259,7 +4266,7 @@
 	for (;;) {
 		if (!cur->common.obj) {
 			/* Which direction do we go to insert this node? */
-			if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_POINTER, bias)
+			if (rb_find_empty_direction(cur, sort_fn, node->common.obj, OBJ_SEARCH_OBJECT, bias)
 				== GO_LEFT) {
 				if (cur->left) {
 					cur = cur->left;
@@ -4283,7 +4290,7 @@
 			rb_insert_fixup(self, node);
 			return AO2_CONTAINER_INSERT_NODE_INSERTED;
 		}
-		cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
+		cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 		if (cmp > 0) {
 			if (cur->left) {
 				cur = cur->left;
@@ -4365,7 +4372,7 @@
 					/* Reject inserting the same object */
 					return AO2_CONTAINER_INSERT_NODE_REJECTED;
 				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp) {
 					break;
 				}
@@ -4381,7 +4388,7 @@
 					/* Reject inserting the same object */
 					return AO2_CONTAINER_INSERT_NODE_REJECTED;
 				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp) {
 					break;
 				}
@@ -4406,7 +4413,7 @@
 					/* Reject inserting the same object */
 					return AO2_CONTAINER_INSERT_NODE_REJECTED;
 				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp) {
 					break;
 				}
@@ -4422,7 +4429,7 @@
 					/* Reject inserting the same object */
 					return AO2_CONTAINER_INSERT_NODE_REJECTED;
 				}
-				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_POINTER);
+				cmp = sort_fn(next->common.obj, node->common.obj, OBJ_SEARCH_OBJECT);
 				if (cmp) {
 					break;
 				}
@@ -4543,8 +4550,7 @@
 
 		if (state->sort_fn) {
 			/* Filter node through the sort_fn */
-			cmp = state->sort_fn(node->common.obj, arg,
-				flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
+			cmp = state->sort_fn(node->common.obj, arg, flags & OBJ_SEARCH_MASK);
 			if (cmp) {
 				/* No more nodes in this container are possible to match. */
 				break;
@@ -4580,9 +4586,9 @@
  * \param self Container to operate upon.
  * \param obj_right pointer to the (user-defined part) of an object.
  * \param flags flags from ao2_callback()
- *   OBJ_POINTER - if set, 'obj_right', is an object.
- *   OBJ_KEY - if set, 'obj_right', is a search key item that is not an object.
- *   OBJ_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
+ *   OBJ_SEARCH_OBJECT - if set, 'obj_right', is an object.
+ *   OBJ_SEARCH_KEY - if set, 'obj_right', is a search key item that is not an object.
+ *   OBJ_SEARCH_PARTIAL_KEY - if set, 'obj_right', is a partial search key item that is not an object.
  *   OBJ_CONTINUE - if set, return node right before or right after search key if not a match.
  * \param bias How to bias search direction for duplicates
  *
@@ -4597,7 +4603,7 @@
 	struct rbtree_node *next = NULL;
 	ao2_sort_fn *sort_fn;
 
-	sort_flags = flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY);
+	sort_flags = flags & OBJ_SEARCH_MASK;
 	sort_fn = self->common.sort_fn;
 
 	/* Find node where normal search would find it. */
@@ -4730,12 +4736,17 @@
 	state->arg = arg;
 	state->flags = flags;
 
-	if (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+	case OBJ_SEARCH_KEY:
+	case OBJ_SEARCH_PARTIAL_KEY:
 		/* We are asked to do a directed search. */
 		state->sort_fn = self->common.sort_fn;
-	} else {
+		break;
+	default:
 		/* Don't know, let's visit all nodes */
 		state->sort_fn = NULL;
+		break;
 	}
 
 	if (!self->root) {
@@ -4763,7 +4774,7 @@
 		switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
 		case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
 		case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-			if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+			if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
 				/* There are no duplicates allowed. */
 				bias = BIAS_EQUAL;
 				break;
@@ -4798,7 +4809,7 @@
 		switch (self->common.options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
 		case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
 		case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
-			if ((flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) != OBJ_PARTIAL_KEY) {
+			if ((flags & OBJ_SEARCH_MASK) != OBJ_SEARCH_PARTIAL_KEY) {
 				/* There are no duplicates allowed. */
 				bias = BIAS_EQUAL;
 				break;
@@ -5228,7 +5239,7 @@
 			}
 
 			if (obj_last) {
-				if (self->common.sort_fn(obj_last, node->common.obj, OBJ_POINTER) > 0) {
+				if (self->common.sort_fn(obj_last, node->common.obj, OBJ_SEARCH_OBJECT) > 0) {
 					ast_log(LOG_ERROR, "Tree nodes are out of sorted order!\n");
 					return -1;
 				}
@@ -5517,18 +5528,33 @@
 	const struct ao2_reg_container *reg_left = obj_left;
 	int cmp;
 
-	if (flags & OBJ_KEY) {
-		const char *name = obj_right;
-
-		cmp = strcasecmp(reg_left->name, name);
-	} else if (flags & OBJ_PARTIAL_KEY) {
-		const struct ao2_reg_partial_key *partial_key = obj_right;
-
-		cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
-	} else {
-		const struct ao2_reg_container *reg_right = obj_right;
-
-		cmp = strcasecmp(reg_left->name, reg_right->name);
+	switch (flags & OBJ_SEARCH_MASK) {
+	case OBJ_SEARCH_OBJECT:
+		{
+			const struct ao2_reg_container *reg_right = obj_right;
+
+			cmp = strcasecmp(reg_left->name, reg_right->name);
+		}
+		break;
+	case OBJ_SEARCH_KEY:
+		{
+			const char *name = obj_right;
+
+			cmp = strcasecmp(reg_left->name, name);
+		}
+		break;
+	case OBJ_SEARCH_PARTIAL_KEY:
+		{
+			const struct ao2_reg_partial_key *partial_key = obj_right;
+
+			cmp = strncasecmp(reg_left->name, partial_key->name, partial_key->len);
+		}
+		break;
+	default:
+		/* Sort can only work on something with a full or partial key. */
+		ast_assert(0);
+		cmp = 0;
+		break;
 	}
 	return cmp;
 }
@@ -5575,7 +5601,7 @@
 void ao2_container_unregister(const char *name)
 {
 #if defined(AST_DEVMODE)
-	ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_KEY,
+	ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY,
 		"Unregister container");
 #endif	/* defined(AST_DEVMODE) */
 }
@@ -5606,7 +5632,7 @@
 	partial_key.name = a->word;
 	which.find_nth = a->n;
 	which.count = 0;
-	reg = ao2_t_callback_data(reg_containers, partial_key.len ? OBJ_PARTIAL_KEY : 0,
+	reg = ao2_t_callback_data(reg_containers, partial_key.len ? OBJ_SEARCH_PARTIAL_KEY : 0,
 		ao2_complete_reg_cb, &partial_key, &which, "Find partial registered container");
 	if (reg) {
 		name = ast_strdup(reg->name);
@@ -5675,7 +5701,7 @@
 	}
 
 	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
 	if (reg) {
 		ao2_container_dump(reg->registered, 0, name, (void *) &a->fd, cli_output,
 			reg->prnt_obj);
@@ -5711,7 +5737,7 @@
 	}
 
 	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
 	if (reg) {
 		ao2_container_stats(reg->registered, 0, name, (void *) &a->fd, cli_output);
 		ao2_t_ref(reg, -1, "Done with registered container object.");
@@ -5746,7 +5772,7 @@
 	}
 
 	name = a->argv[3];
-	reg = ao2_t_find(reg_containers, name, OBJ_KEY, "Find registered container");
+	reg = ao2_t_find(reg_containers, name, OBJ_SEARCH_KEY, "Find registered container");
 	if (reg) {
 		ast_cli(a->fd, "Container check of '%s': %s.\n", name,
 			ao2_container_check(reg->registered, 0) ? "failed" : "OK");

Modified: team/dlee/hashtab-skiplist/main/cdr.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/hashtab-skiplist/main/cdr.c?view=diff&rev=399768&r1=399767&r2=399768
==============================================================================
--- team/dlee/hashtab-skiplist/main/cdr.c (original)
+++ team/dlee/hashtab-skiplist/main/cdr.c Tue Sep 24 18:39:56 2013
@@ -327,7 +327,7 @@
 AST_MUTEX_DEFINE_STATIC(cdr_pending_lock);
 static ast_cond_t cdr_pending_cond;
 
-/*! \brief A container of the active CDRs indexed by Party A channel name */
+/*! \brief A container of the active CDRs indexed by Party A channel id */
 static struct ao2_container *active_cdrs_by_channel;
 
 /*! \brief Message router for stasis messages regarding channel state */
@@ -682,6 +682,7 @@
 	struct ast_flags flags;                 /*!< Flags on the CDR */
 	AST_DECLARE_STRING_FIELDS(
 		AST_STRING_FIELD(linkedid);         /*!< Linked ID. Cached here as it may change out from party A, which must be immutable */
+		AST_STRING_FIELD(uniqueid);			/*!< Unique id of party A. Cached here as it is the primary key of this CDR */
 		AST_STRING_FIELD(name);             /*!< Channel name of party A. Cached here as the party A address may change */
 		AST_STRING_FIELD(bridge);           /*!< The bridge the party A happens to be in. */
 		AST_STRING_FIELD(appl);             /*!< The last accepted application party A was in */
@@ -772,42 +773,58 @@
 	}
 }
 /*! \internal
- * \brief Hash function for containers of CDRs indexing by Party A name */
+ * \brief Hash function for containers of CDRs indexing by Party A uniqueid */
 static int cdr_object_channel_hash_fn(const void *obj, const int flags)
 {
-	const struct cdr_object *cdr = obj;
-	const char *name = (flags & OBJ_KEY) ? obj : cdr->name;
-	return ast_str_case_hash(name);
+	const struct cdr_object *cdr;
+	const char *key;
+
+	switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+	case OBJ_KEY:
+		key = obj;
+		break;
+	case OBJ_POINTER:
+		cdr = obj;
+		key = cdr->uniqueid;
+		break;
+	default:
+		ast_assert(0);
+		return 0;
+	}
+	return ast_str_case_hash(key);
 }
 
 /*! \internal
- * \brief Comparison function for containers of CDRs indexing by Party A name
+ * \brief Comparison function for containers of CDRs indexing by Party A uniqueid
  */
 static int cdr_object_channel_cmp_fn(void *obj, void *arg, int flags)
 {
-	struct cdr_object *left = obj;
-	struct cdr_object *right = arg;
-	const char *match = (flags & OBJ_KEY) ? arg : right->name;
-	return strcasecmp(left->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-/*! \internal
- * \brief Comparison function for containers of CDRs indexing by bridge. Note
- * that we expect there to be collisions, as a single bridge may have multiple
- * CDRs active at one point in time
- */
-static int cdr_object_bridge_cmp_fn(void *obj, void *arg, int flags)
-{
-	struct cdr_object *left = obj;
-	struct cdr_object *it_cdr;
-	const char *match = arg;
-
-	for (it_cdr = left; it_cdr; it_cdr = it_cdr->next) {
-		if (!strcasecmp(it_cdr->bridge, match)) {
-			return CMP_MATCH;
-		}
-	}
-	return 0;
+    struct cdr_object *left = obj;
+    struct cdr_object *right = arg;
+    const char *right_key = arg;
+    int cmp;
+
+    switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
+    case OBJ_POINTER:
+        right_key = right->uniqueid;
+        /* Fall through */
+    case OBJ_KEY:
+        cmp = strcmp(left->uniqueid, right_key);
+        break;
+    case OBJ_PARTIAL_KEY:
+        /*
+         * We could also use a partial key struct containing a length
+         * so strlen() does not get called for every comparison instead.
+         */
+        cmp = strncmp(left->uniqueid, right_key, strlen(right_key));
+        break;
+    default:
+        /* Sort can only work on something with a full or partial key. */
+        ast_assert(0);
+        cmp = 0;
+        break;
+    }
+    return cmp ? 0 : CMP_MATCH;
 }
 
 /*!
@@ -854,6 +871,7 @@
 		ao2_cleanup(cdr);
 		return NULL;
 	}
+	ast_string_field_set(cdr, uniqueid, chan->uniqueid);
 	ast_string_field_set(cdr, name, chan->name);
 	ast_string_field_set(cdr, linkedid, chan->linkedid);
 	cdr->disposition = AST_CDR_NULL;
@@ -985,7 +1003,7 @@
 	} else if (left->snapshot->creationtime.tv_sec > right->snapshot->creationtime.tv_sec) {
 		return right;
 	} else if (left->snapshot->creationtime.tv_usec > right->snapshot->creationtime.tv_usec) {
-			return right;
+		return right;
 	} else {
 		/* Okay, fine, take the left one */
 		return left;
@@ -1062,12 +1080,15 @@
 	struct ast_var_t *it_var, *it_copy_var;
 	struct ast_channel_snapshot *party_a;
 	struct ast_channel_snapshot *party_b;
+	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
 
 	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
 		struct ast_cdr *cdr_copy;
 
 		/* Don't create records for CDRs where the party A was a dialed channel */
-		if (snapshot_is_dialed(it_cdr->party_a.snapshot)) {
+		if (snapshot_is_dialed(it_cdr->party_a.snapshot) && !it_cdr->party_b.snapshot) {
+			CDR_DEBUG(mod_cfg, "%p - %s is dialed and has no Party B; discarding\n", it_cdr,
+				it_cdr->party_a.snapshot->name);
 			continue;
 		}
 
@@ -1437,6 +1458,7 @@
 static int single_state_bridge_enter_comparison(struct cdr_object *cdr,
 		struct cdr_object *cand_cdr)
 {
+	RAII_VAR(struct module_config *, mod_cfg, ao2_global_obj_ref(module_configs), ao2_cleanup);
 	struct cdr_object_snapshot *party_a;
 
 	/* Don't match on ourselves */
@@ -1447,6 +1469,8 @@
 	/* Try the candidate CDR's Party A first */
 	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_a);
 	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+		CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
+			cdr, cdr->party_a.snapshot->name, cand_cdr->party_a.snapshot->name);
 		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_a);
 		if (!cand_cdr->party_b.snapshot) {
 			/* We just stole them - finalize their CDR. Note that this won't
@@ -1465,6 +1489,8 @@
 	}
 	party_a = cdr_object_pick_party_a(&cdr->party_a, &cand_cdr->party_b);
 	if (!strcasecmp(party_a->snapshot->name, cdr->party_a.snapshot->name)) {
+		CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
+			cdr, cdr->party_a.snapshot->name, cand_cdr->party_b.snapshot->name);
 		cdr_object_snapshot_copy(&cdr->party_b, &cand_cdr->party_b);
 		return 0;
 	}
@@ -1474,27 +1500,31 @@
 
 static enum process_bridge_enter_results single_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 {
-	struct ao2_iterator *it_cdrs;
-	struct cdr_object *cand_cdr_master;
-	char *bridge_id = ast_strdupa(bridge->uniqueid);
+	struct ao2_iterator it_cdrs;
+	char *channel_id;
 	int success = 0;
 
 	ast_string_field_set(cdr, bridge, bridge->uniqueid);
 
-	/* Get parties in the bridge */
-	it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE,
-			cdr_object_bridge_cmp_fn, bridge_id);
-	if (!it_cdrs) {
-		/* No one in the bridge yet! */
+	if (ao2_container_count(bridge->channels) == 1) {
+		/* No one in the bridge yet but us! */
 		cdr_object_transition_state(cdr, &bridge_state_fn_table);
 		return BRIDGE_ENTER_ONLY_PARTY;
 	}
 
-	while ((cand_cdr_master = ao2_iterator_next(it_cdrs))) {
+	for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
+		!success && (channel_id = ao2_iterator_next(&it_cdrs));
+		ao2_ref(channel_id, -1)) {
+		RAII_VAR(struct cdr_object *, cand_cdr_master,
+			ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
+			ao2_cleanup);
 		struct cdr_object *cand_cdr;
-		RAII_VAR(struct cdr_object *, cdr_cleanup, cand_cdr_master, ao2_cleanup);
-		SCOPED_AO2LOCK(lock, cand_cdr_master);
-
+
+		if (!cand_cdr_master) {
+			continue;
+		}
+
+		ao2_lock(cand_cdr_master);
 		for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
 			/* Skip any records that are not in a bridge or in this bridge.
 			 * I'm not sure how that would happen, but it pays to be careful. */
@@ -1510,8 +1540,9 @@
 			success = 1;
 			break;
 		}
-	}
-	ao2_iterator_destroy(it_cdrs);
+		ao2_unlock(cand_cdr_master);
+	}
+	ao2_iterator_destroy(&it_cdrs);
 
 	/* We always transition state, even if we didn't get a peer */
 	cdr_object_transition_state(cdr, &bridge_state_fn_table);
@@ -1620,27 +1651,32 @@
 
 static enum process_bridge_enter_results dial_state_process_bridge_enter(struct cdr_object *cdr, struct ast_bridge_snapshot *bridge, struct ast_channel_snapshot *channel)
 {
-	struct ao2_iterator *it_cdrs;
-	char *bridge_id = ast_strdupa(bridge->uniqueid);
-	struct cdr_object *cand_cdr_master;
+	struct ao2_iterator it_cdrs;
+	char *channel_id;
 	int success = 0;
 
 	ast_string_field_set(cdr, bridge, bridge->uniqueid);
 
 	/* Get parties in the bridge */
-	it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE,
-			cdr_object_bridge_cmp_fn, bridge_id);
-	if (!it_cdrs) {
-		/* No one in the bridge yet! */
+	if (ao2_container_count(bridge->channels) == 1) {
+		/* No one in the bridge yet but us! */
 		cdr_object_transition_state(cdr, &bridge_state_fn_table);
 		return BRIDGE_ENTER_ONLY_PARTY;
 	}
 
-	while ((cand_cdr_master = ao2_iterator_next(it_cdrs))) {
+	for (it_cdrs = ao2_iterator_init(bridge->channels, 0);
+		!success && (channel_id = ao2_iterator_next(&it_cdrs));
+		ao2_ref(channel_id, -1)) {
+		RAII_VAR(struct cdr_object *, cand_cdr_master,
+			ao2_find(active_cdrs_by_channel, channel_id, OBJ_KEY),
+			ao2_cleanup);
 		struct cdr_object *cand_cdr;
-		RAII_VAR(struct cdr_object *, cdr_cleanup, cand_cdr_master, ao2_cleanup);
-		SCOPED_AO2LOCK(lock, cand_cdr_master);
-
+
+		if (!cand_cdr_master) {
+			continue;
+		}
+
+		ao2_lock(cand_cdr_master);
 		for (cand_cdr = cand_cdr_master; cand_cdr; cand_cdr = cand_cdr->next) {
 			/* Skip any records that are not in a bridge or in this bridge.
 			 * I'm not sure how that would happen, but it pays to be careful. */
@@ -1669,8 +1705,9 @@
 			success = 1;
 			break;
 		}
-	}
-	ao2_iterator_destroy(it_cdrs);
+		ao2_unlock(cand_cdr_master);
+	}
+	ao2_iterator_destroy(&it_cdrs);
 
 	/* We always transition state, even if we didn't get a peer */
 	cdr_object_transition_state(cdr, &bridge_state_fn_table);
@@ -1829,9 +1866,9 @@
 
 	/* Figure out who is running this show */
 	if (caller) {
-		cdr = ao2_find(active_cdrs_by_channel, caller->name, OBJ_KEY);
+		cdr = ao2_find(active_cdrs_by_channel, caller->uniqueid, OBJ_KEY);
 	} else {
-		cdr = ao2_find(active_cdrs_by_channel, peer->name, OBJ_KEY);
+		cdr = ao2_find(active_cdrs_by_channel, peer->uniqueid, OBJ_KEY);
 	}
 
 	if (!cdr) {
@@ -1986,6 +2023,7 @@
 	struct stasis_cache_update *update = stasis_message_data(message);
 	struct ast_channel_snapshot *old_snapshot;
 	struct ast_channel_snapshot *new_snapshot;
+	const char *uniqueid;
 	const char *name;
 	struct cdr_object *it_cdr;
 
@@ -1994,16 +2032,12 @@
 
 	old_snapshot = stasis_message_data(update->old_snapshot);
 	new_snapshot = stasis_message_data(update->new_snapshot);
+	uniqueid = new_snapshot ? new_snapshot->uniqueid : old_snapshot->uniqueid;
 	name = new_snapshot ? new_snapshot->name : old_snapshot->name;
 
 	if (filter_channel_cache_message(old_snapshot, new_snapshot)) {
 		return;
 	}
-
-	CDR_DEBUG(mod_cfg, "Channel Update message for %s: %u.%08u\n",
-			name,
-			(unsigned int)stasis_message_timestamp(message)->tv_sec,
-			(unsigned int)stasis_message_timestamp(message)->tv_usec);
 
 	if (new_snapshot && !old_snapshot) {
 		cdr = cdr_object_alloc(new_snapshot);
@@ -2015,7 +2049,7 @@
 
 	/* Handle Party A */
 	if (!cdr) {
-		cdr = ao2_find(active_cdrs_by_channel, name, OBJ_KEY);
+		cdr = ao2_find(active_cdrs_by_channel, uniqueid, OBJ_KEY);
 	}
 	if (!cdr) {
 		ast_log(AST_LOG_WARNING, "No CDR for channel %s\n", name);
@@ -2027,7 +2061,6 @@
 				if (!it_cdr->fn_table->process_party_a) {
 					continue;
 				}
-				CDR_DEBUG(mod_cfg, "%p - Processing new channel snapshot %s\n", it_cdr, new_snapshot->name);
 				all_reject &= it_cdr->fn_table->process_party_a(it_cdr, new_snapshot);
 			}
 			if (all_reject && check_new_cdr_needed(old_snapshot, new_snapshot)) {
@@ -2121,7 +2154,7 @@
 	RAII_VAR(struct module_config *, mod_cfg,
 			ao2_global_obj_ref(module_configs), ao2_cleanup);
 	RAII_VAR(struct cdr_object *, cdr,
-			ao2_find(active_cdrs_by_channel, channel->name, OBJ_KEY),
+			ao2_find(active_cdrs_by_channel, channel->uniqueid, OBJ_KEY),
 			ao2_cleanup);
 	struct cdr_object *it_cdr;
 	struct bridge_leave_data leave_data = {
@@ -2171,163 +2204,6 @@
 	}
 }
 
-struct bridge_candidate {
-	struct cdr_object *cdr;					/*!< The actual CDR this candidate belongs to, either as A or B */
-	struct cdr_object_snapshot candidate;	/*!< The candidate for a new pairing */
-};
-
-/*! \internal
- * \brief Comparison function for \ref bridge_candidate objects
- */
-static int bridge_candidate_cmp_fn(void *obj, void *arg, int flags)
-{
-	struct bridge_candidate *left = obj;
-	struct bridge_candidate *right = arg;
-	const char *match = (flags & OBJ_KEY) ? arg : right->candidate.snapshot->name;
-	return strcasecmp(left->candidate.snapshot->name, match) ? 0 : (CMP_MATCH | CMP_STOP);
-}
-
-/*! \internal
- * \brief Hash function for \ref bridge_candidate objects
- */
-static int bridge_candidate_hash_fn(const void *obj, const int flags)
-{
-	const struct bridge_candidate *bc = obj;
-	const char *id = (flags & OBJ_KEY) ? obj : bc->candidate.snapshot->name;
-	return ast_str_case_hash(id);
-}
-
-/*! \brief \ref bridge_candidate Destructor */
-static void bridge_candidate_dtor(void *obj)
-{
-	struct bridge_candidate *bcand = obj;
-	ao2_cleanup(bcand->cdr);
-	ao2_cleanup(bcand->candidate.snapshot);
-	free_variables(&bcand->candidate.variables);
-}
-
-/*!
- * \brief \ref bridge_candidate Constructor
- * \param cdr The \ref cdr_object that is a candidate for being compared to in
- *  a bridge operation
- * \param candidate The \ref cdr_object_snapshot candidate snapshot in the CDR
- *  that should be used during the operaton
- */
-static struct bridge_candidate *bridge_candidate_alloc(struct cdr_object *cdr, struct cdr_object_snapshot *candidate)
-{
-	struct bridge_candidate *bcand;
-
-	bcand = ao2_alloc(sizeof(*bcand), bridge_candidate_dtor);
-	if (!bcand) {
-		return NULL;
-	}
-	bcand->cdr = cdr;
-	ao2_ref(bcand->cdr, +1);
-	bcand->candidate.flags = candidate->flags;
-	strcpy(bcand->candidate.userfield, candidate->userfield);
-	bcand->candidate.snapshot = candidate->snapshot;
-	ao2_ref(bcand->candidate.snapshot, +1);
-	copy_variables(&bcand->candidate.variables, &candidate->variables);
-
-	return bcand;
-}
-
-/*!
- * \internal
- * \brief Build and add bridge candidates based on a CDR
- *
- * \param bridge_id The ID of the bridge we need candidates for
- * \param candidates The container of \ref bridge_candidate objects
- * \param cdr The \ref cdr_object that is our candidate
- * \param party_a Non-zero if we should look at the Party A channel; 0 if Party B
- */
-static void add_candidate_for_bridge(const char *bridge_id,
-		struct ao2_container *candidates,
-		struct cdr_object *cdr,
-		int party_a)
-{
-	struct cdr_object *it_cdr;
-
-	for (it_cdr = cdr; it_cdr; it_cdr = it_cdr->next) {
-		struct cdr_object_snapshot *party_snapshot;
-		RAII_VAR(struct bridge_candidate *, bcand, NULL, ao2_cleanup);
-
-		party_snapshot = party_a ? &it_cdr->party_a : &it_cdr->party_b;
-
-		if (it_cdr->fn_table != &bridge_state_fn_table || strcmp(bridge_id, it_cdr->bridge)) {
-			continue;
-		}
-
-		if (!party_snapshot->snapshot) {
-			continue;
-		}
-
-		/* Don't add a party twice */
-		bcand = ao2_find(candidates, party_snapshot->snapshot->name, OBJ_KEY);
-		if (bcand) {
-			continue;
-		}
-
-		bcand = bridge_candidate_alloc(it_cdr, party_snapshot);
-		if (bcand) {
-			ao2_link(candidates, bcand);
-		}
-	}
-}
-
-/*!
- * \brief Create new \ref bridge_candidate objects for each party currently
- * in a bridge
- * \param bridge The \param ast_bridge_snapshot for the bridge we're processing
- *
- * Note that we use two passes here instead of one so that we only create a
- * candidate for a party B if they are never a party A in the bridge. Otherwise,
- * we don't care about them.
- */
-static struct ao2_container *create_candidates_for_bridge(struct ast_bridge_snapshot *bridge)
-{
-	struct ao2_container *candidates = ao2_container_alloc(61, bridge_candidate_hash_fn, bridge_candidate_cmp_fn);
-	char *bridge_id = ast_strdupa(bridge->uniqueid);
-	struct ao2_iterator *it_cdrs;
-	struct cdr_object *cand_cdr_master;
-
-	if (!candidates) {
-		return NULL;
-	}
-
-	/* For each CDR that has a record in the bridge, get their Party A and
-	 * make them a candidate. Note that we do this in two passes as opposed to one so
-	 * that we give preference CDRs where the channel is Party A */
-	it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE,
-			cdr_object_bridge_cmp_fn, bridge_id);
-	if (!it_cdrs) {
-		/* No one in the bridge yet! */
-		ao2_cleanup(candidates);
-		return NULL;
-	}
-	for (; (cand_cdr_master = ao2_iterator_next(it_cdrs)); ao2_cleanup(cand_cdr_master)) {
-		SCOPED_AO2LOCK(lock, cand_cdr_master);
-		add_candidate_for_bridge(bridge->uniqueid, candidates, cand_cdr_master, 1);
-	}
-	ao2_iterator_destroy(it_cdrs);
-	/* For each CDR that has a record in the bridge, get their Party B and
-	 * make them a candidate. */
-	it_cdrs = ao2_callback(active_cdrs_by_channel, OBJ_MULTIPLE,
-			cdr_object_bridge_cmp_fn, bridge_id);
-	if (!it_cdrs) {
-		/* Now it's just an error. */
-		ao2_cleanup(candidates);
-		return NULL;
-	}
-	for (; (cand_cdr_master = ao2_iterator_next(it_cdrs)); ao2_cleanup(cand_cdr_master)) {
-		SCOPED_AO2LOCK(lock, cand_cdr_master);
-		add_candidate_for_bridge(bridge->uniqueid, candidates, cand_cdr_master, 0);
-	}
-	ao2_iterator_destroy(it_cdrs);
-
-	return candidates;
-}
-
 /*!
  * \internal
  * \brief Create a new CDR, append it to an existing CDR, and update its snapshots
@@ -2335,9 +2211,10 @@
  * \note The new CDR will be automatically transitioned to the bridge state
  */
 static void bridge_candidate_add_to_cdr(struct cdr_object *cdr,
-		const char *bridge_id,
 		struct cdr_object_snapshot *party_b)
 {
+	RAII_VAR(struct module_config *,  mod_cfg,
+		ao2_global_obj_ref(module_configs), ao2_cleanup);
 	struct cdr_object *new_cdr;
 
 	new_cdr = cdr_object_create_and_append(cdr);
@@ -2348,76 +2225,70 @@
 	cdr_object_check_party_a_answer(new_cdr);
 	ast_string_field_set(new_cdr, bridge, cdr->bridge);
 	cdr_object_transition_state(new_cdr, &bridge_state_fn_table);
-}
-
-/*!
- * \brief Process a single \ref bridge_candidate. Note that this is called as
- * part of an \ref ao2_callback on an \ref ao2_container of \ref bridge_candidate
- * objects previously created by \ref create_candidates_for_bridge.
+	CDR_DEBUG(mod_cfg, "%p - Party A %s has new Party B %s\n",
+		new_cdr, new_cdr->party_a.snapshot->name,
+		party_b->snapshot->name);
+}
+
+/*!
+ * \brief Process a single \ref bridge_candidate
  *
- * \param obj The \ref bridge_candidate being processed
- * \param arg The \ref cdr_object that is being compared against the candidates
+ * When a CDR enters a bridge, it needs to make pairings with everyone else
+ * that it is not currently paired with. This function determines, for the
+ * CDR for the channel that entered the bridge and the CDR for every other
+ * channel currently in the bridge, who is Party A and makes new CDRs.
  *
- * The purpose of this function is to create the necessary CDR entries as a
- * result of \ref cdr_object having entered the same bridge as the CDR
- * represented by \ref bridge_candidate.
- */
-static int bridge_candidate_process(void *obj, void *arg, int flags)
-{
-	struct bridge_candidate *bcand = obj;
-	struct cdr_object *cdr = arg;
+ * \param cdr The \ref cdr_obj being processed
+ * \param cand_cdr The \ref cdr_object that is a candidate
+ *
+ */
+static int bridge_candidate_process(struct cdr_object *cdr, struct cdr_object *base_cand_cdr)
+{
+	RAII_VAR(struct module_config *, mod_cfg,
+		ao2_global_obj_ref(module_configs), ao2_cleanup);
 	struct cdr_object_snapshot *party_a;
-
-	/* If the candidate is us or someone we've taken on, pass on by */
-	if (!strcasecmp(cdr->party_a.snapshot->name, bcand->candidate.snapshot->name)
-		|| (cdr->party_b.snapshot

[... 402 lines stripped ...]



More information about the asterisk-commits mailing list