[asterisk-dev] bridge_unreal: An alternative approach to Local/Unreal channel optimization

Matthew Jordan mjordan at digium.com
Tue Mar 11 10:22:49 CDT 2014


On Mon, Mar 10, 2014 at 7:27 AM, Matthew Jordan <mjordan at digium.com> wrote:
>
> On Mon, Mar 10, 2014 at 6:59 AM, Joshua Colp <jcolp at digium.com> wrote:
>>
>> Matthew Jordan wrote:

<snip>

>> The NLB compatibility code actually checks whether something like a
>> MixMonitor is on either Local channel and won't allow it to be used.
>>
>> Now that I've given a diagram to show where things optimize and how it
>> isn't inside of chan_local... what do you think NOW? ;)
>
>
> I think this proposal is tantamount to killing Local channel optimization.
>
> I'm not sure that's a bad thing, but I'd certainly like to get more
> opinions.
>

Updating this thread with some more thoughts. These are a bit random, but
hopefully they'll spark some conversation about possibilities here:

 * We probably can't get rid of Local channel optimization. While it is
ugly - and prone to causing strange thing to happen both in the core and
from the perspective of an external user - there's at least one use case
that needs this feature: collapsing two RTP capable channels into a native
bridge. For example, assume we have the following:

     -->   <------> <-------->   <--
SIP/foo \ / Local;1  Local;2 \ /  SIP/bar
         -                    -
        B0                    B1

Here, B0 and B1 would currently be simple two party bridges with the media
flowing through the core. If feature requirements meant that SIP/foo and
SIP/bar could not be natively bridged - even if they were directly in a
bridge together - then optimizing this scenario doesn't buy much
performance. If, however, optimizing away the Local channel would result in
the bridge between SIP/foo and SIP/bar being a native bridge, then the
performance gain is significant.

* There's lots of strange edge cases with Local channels. Consider, for
example, some of the following scenarios (all of which are possible in 12):

** Local channel between Real channel and multi-party bridge with Real
channels. In this case, optimization should result in the Real/A channel
being pushed into bridge B1.

           B0                           / <-------- Real
Real/A -->/  \<------>  <------> - B1 --  <-------- Real
               Local;1   Local;2        \ <-------- Real

** Local channel between Local channel and a multi-party bridge with Real
channels. Here, there's a possible race condition between the Local
channels: we don't know for sure what is on the other end of the Local/A;2
channel. Finding out is also a bad idea - a whole lot of things would have
to be locked in order to get that information. What's more, there may be
another Local channel beyond Local/A! This is where Josh's proposal comes
into play, as the information is passed down the chain - making it so that
optimizations don't have to occur in Local channel chains. At the same
time, we may want to try and optimize away the Local channel between the
multi-party bridge of Real channels and the other Local channel. Assuming
Local/A doesn't win in an optimization race, we'd want Local/A to take the
place of the existing Local channel - but we have to prevent it from
optimizing away at the same time.

              B0                           / <-------- Real
Local/A;2 -->/  \<------>  <------> - B1 --  <-------- Real
                  Local;1   Local;2        \ <-------- Real

** Local channel between two multi-party bridges. Here, there's really two
ways to handle this: either don't optimize away, or merge both bridges
together into one massive multi-party bridge.

Real  --> \                                  / <-------- Real
Real  -->  -- B0 - <-------> <------> - B1 --  <-------- Real
Real  --> /          Local;1 Local;2         \ <-------- Real

** Two Local channels optimizing into a multi-party bridge. Both our Local
channel - as well as Local/B - may attempt to optimize the channels on the
other ends into B1 at the same time. The bridge has to carefully manage
this process.

           B0                           / <-------- Real
Real/A -->/  \<------>  <------> - B1 --  <-------- Local/B
               Local;1   Local;2        \ <-------- Real

All of these scenarios are currently handled by core_unreal and core_local
in some fashion. It is, however, very complex code that - particularly with
Local channel chains - is prone to error. The implementation today faces
two problems:
(1) Knowledge of what is on the other side of the bridge is known by the
bridge, but not by either Local channel half. In order to get that
knowledge, both Local channel halves must take control of the bridge (and
all of its participants), then synchronize with each other.
(2) When multiple Local channels can optimize in a chain, they have to
communicate with each other (or at least compete with each other) to see
who optimizes out first. This can change the information that a Local
channel has about how it can optimize: for example, a Local channel may
view that it is in a two party bridge with another Local channel, attempt
to optimize, only to find out later that it is now in a multi-party bridge
with multiple Real channels.
(3) When optimization occurs, there can be *no* information in flight on
the Local channel. This is particularly difficult as the write queue exists
on the ast_channel struct - which means that the bridging layer has to be
informed to not write to the channel when the optimization occurs. Again,
more points of synchronization and locking.

There's a few possible approaches that may simplify the implementation:

 * Use approaches such as Josh's native Local bridge to move logic out of
core_unreal and core_local into bridge implementations. The bridges
actually have state now, and *know* who is in the bridge with them. A
bridge implementation could be written that handles a Local channel + one
other channel, and it could tell the Local channel when it can optimize.

* Add a write queue on the bridge_channel struct. There already exists a
read queue on this same struct; having two queues would make it so that the
bridge never has to stop writing frames destined for a channel, even during
optimization. There is a possible performance cost to this approach, but it
would reduce friction during optimization as the Local channel can opt to
stop reading from its write queue.

Lots of things to think about!

Matt

-- 
Matthew Jordan
Digium, Inc. | Engineering Manager
445 Jan Davis Drive NW - Huntsville, AL 35806 - USA
Check us out at: http://digium.com & http://asterisk.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.digium.com/pipermail/asterisk-dev/attachments/20140311/c8aa3bcb/attachment-0001.html>


More information about the asterisk-dev mailing list