<div dir="ltr"><br>On Mon, Mar 10, 2014 at 7:27 AM, Matthew Jordan <<a href="mailto:mjordan@digium.com">mjordan@digium.com</a>> wrote:<br>><br>> On Mon, Mar 10, 2014 at 6:59 AM, Joshua Colp <<a href="mailto:jcolp@digium.com">jcolp@digium.com</a>> wrote:<br>
>><br>>> Matthew Jordan wrote:<br><br><snip><br><br>>> The NLB compatibility code actually checks whether something like a<br>>> MixMonitor is on either Local channel and won't allow it to be used.<br>
>><br>>> Now that I've given a diagram to show where things optimize and how it<br>>> isn't inside of chan_local... what do you think NOW? ;)<br>><br>><br>> I think this proposal is tantamount to killing Local channel optimization.<br>
><br>> I'm not sure that's a bad thing, but I'd certainly like to get more<br>> opinions.<br>><br><br>Updating this thread with some more thoughts. These are a bit random, but hopefully they'll spark some conversation about possibilities here:<div>
<br></div><div> * 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:</div>
<div><br></div><div><font face="courier new, monospace">     -->   <------> <-------->   <--</font></div><div><font face="courier new, monospace">SIP/foo \ / Local;1  Local;2 \ /  SIP/bar</font></div><div>
<font face="courier new, monospace">         -                    -</font></div><div style><font face="courier new, monospace">        B0                    B1</font></div><div style><font face="courier new, monospace"><br>
</font></div><div style><font face="arial, helvetica, sans-serif">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.</font></div>
<div style><font face="arial, helvetica, sans-serif"><br></font></div><div style><font face="arial, helvetica, sans-serif">* 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):</font></div>
<div style><br></div><div style>** 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.</div><div style>
<br></div><div style><font face="courier new, monospace">           B0                           / <-------- Real</font></div><div style><font face="courier new, monospace">Real/A -->/  \<------>  <------> - B1 --  <-------- Real</font></div>
<div style><font face="courier new, monospace">               Local;1   Local;2        \ <-------- Real</font></div><div style><font face="arial, helvetica, sans-serif"><br></font></div><div style><font face="arial, helvetica, sans-serif">** 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.</font></div>
<div style><font face="arial, helvetica, sans-serif"><br></font></div><div style><div><font face="courier new, monospace">              B0                           / <-------- Real</font></div><div><font face="courier new, monospace">Local/A;2 -->/  \<------>  <------> - B1 --  <-------- Real</font></div>
<div><font face="courier new, monospace">                  Local;1   Local;2        \ <-------- Real</font></div></div><div style><font face="arial, helvetica, sans-serif"><br></font></div><div style><font face="arial, helvetica, sans-serif">** 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.</font></div>
<div style><font face="arial, helvetica, sans-serif"><br></font></div><div style><font face="courier new, monospace">Real  --> \                                  / <-------- Real</font></div><div style><font face="courier new, monospace">Real  -->  -- B0 - <-------> <------> - B1 --  <-------- Real</font></div>
<div style><font face="courier new, monospace">Real  --> /          Local;1 Local;2         \ <-------- Real</font></div><div><br></div><div style>** 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.</div>
<div><br></div><div><div><div><div><font face="courier new, monospace">           B0                           / <-------- Real</font></div><div><font face="courier new, monospace">Real/A -->/  \<------>  <------> - B1 --  <-------- Local/B</font></div>
<div><font face="courier new, monospace">               Local;1   Local;2        \ <-------- Real</font></div></div></div><div><br></div><div style>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:</div>
<div style>(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.</div>
<div style>(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.</div>
<div style>(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.</div>
<div style><br></div><div style>There's a few possible approaches that may simplify the implementation:</div><div style><br></div><div style> * 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.</div>
<div style><br></div><div style>* 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.</div>
<div style><br></div><div style>Lots of things to think about!</div><div style><br></div><div style>Matt</div><br>-- <br>Matthew Jordan<br>Digium, Inc. | Engineering Manager<br>445 Jan Davis Drive NW - Huntsville, AL 35806 - USA<br>
Check us out at: <a href="http://digium.com">http://digium.com</a> & <a href="http://asterisk.org">http://asterisk.org</a><br></div></div>