<html>
<head>
    <base href="https://wiki.asterisk.org/wiki">
            <link rel="stylesheet" href="/wiki/s/2033/1/7/_/styles/combined.css?spaceKey=TOP&amp;forWysiwyg=true" type="text/css">
    </head>
<body style="background: white;" bgcolor="white" class="email-body">
<div id="pageContent">
<div id="notificationFormat">
<div class="wiki-content">
<div class="email">
    <h2><a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Threading+Design+for+Asynchronous+Operations">Component Threading Design for Asynchronous Operations</a></h2>
    <h4>Page <b>edited</b> by             <a href="https://wiki.asterisk.org/wiki/display/~khunt">Ken Hunt</a>
    </h4>
        <br/>
                         <h4>Changes (2)</h4>
                                 
    
<div id="page-diffs">
                    <table class="diff" cellpadding="0" cellspacing="0">
    
            <tr><td class="diff-snipped" >...<br></td></tr>
            <tr><td class="diff-unchanged" >This process can be repeated as many times as required. For each AMI call required, an additional state is defined in the state machine. Exceptions to this would be when a collector for multiple similar AMI calls is used to aggregate the results of multiple outbound calls into a single response.  <br> <br></td></tr>
            <tr><td class="diff-deleted-lines" style="color:#999;background-color:#fdd;text-decoration:line-through;">&lt;TBD...&gt; <br></td></tr>
            <tr><td class="diff-added-lines" style="background-color: #dfd;">&lt;TBD... rest is placeholder...&gt; <br></td></tr>
            <tr><td class="diff-unchanged" > <br>h3. Implementation Details <br></td></tr>
            <tr><td class="diff-snipped" >...<br></td></tr>
    
            </table>
    </div>                            <h4>Full Content</h4>
                    <div class="notificationGreySide">
        <p>&lt;Draft!!!&gt;</p>

<h3><a name="ComponentThreadingDesignforAsynchronousOperations-Overview"></a>Overview</h3>
<p>This page describes an approach to supporting asynchronous operations in a component, as implemented in the Basic Routing Service. </p>

<h3><a name="ComponentThreadingDesignforAsynchronousOperations-Background"></a>Background</h3>
<p>Asterisk SCF components can make use of Ice's <a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Cpps.9.8.html" class="external-link" rel="nofollow">Asynchronous Message Dispatch (AMD)</a>, a server-side technique for increasing scalability. Using AMD a server can receive a request but then suspend its processing in order to release the dispatch thread. Components may also use the client-side equivalent, <a href="http://www.zeroc.com/doc/Ice-3.4.1-IceTouch/manual/Cpp.7.15.html" class="external-link" rel="nofollow">Asynchronous Method Invocation (AMI)</a>, a way to invoke an operation on a server which never blocks the calling thread even for two-way calls. However, many (if not most) Asterisk SCF components will act as both client and server, where an incoming request will involve invoking one or more operations on other components in order to achieve a result. Even operations which return void and have no "out" parameters may throw exceptions, which need to be communicated to the initiator of the request. </p>

<p>The Basic Routing Service falls into the category of components which will act as both server and client within a given servant. An approach for managing the lifecycle of a server operation was implemented in the routing service, and is described on the remainder of this page. The impact of the design on the component's state replication is also discussed. </p>

<h3><a name="ComponentThreadingDesignforAsynchronousOperations-Design"></a>Design</h3>
<p>The approach implemented in the Basic Routing Service employs what the Ice documentation refers to as <em>asynchronous request chaining</em>, where an incoming AMD request is processed, and in that processing executes an AMI request on some other component. This simple concept is shown in Figure 1. A client invoke some operation ("op") on the Server Component. The Server dispatches dependent operations to external Component X, but is free to process other work in the intervening time from when a reply is sent from Component X. </p>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<td class='confluenceTd'><span class="image-wrap" style=""><img src="/wiki/download/attachments/10649930/async_request_chaining.png?version=1&amp;modificationDate=1293125396126" style="border: 1px solid black" /></span></td>
</tr>
<tr>
<td class='confluenceTd'><b>Figure 1. Asynchronous Request Chaining</b></td>
</tr>
</tbody></table>
</div>


<p>To support this concept, the Server Component is required to do quite a bit of bookkeeping. When an AMD dispatch is received, the servant must store enough information about the request to forward the processing of the operation to a separate worker thread. When it is invoked on the worker the thread, the operation will eventually create an AMI callback object to make AMI calls to Component X. When Component X provides its results, the AMI callback object is invoked. That callback object must then cause the remainder of the processing required in the operation to be executed with the appropriate state maintained across all of these thread hops. </p>

<p>The solution used in the Basic Routing Service was to implement an operation-specific state machine. Figure 2 shows the creation of this state machine at operation 1.3. As can be inferred from the diagram, the object that implements the state machine is also capable of being enqueued to a Work Queue. </p>

<p>The Operation State Machine is designed to have a state handler for each state. This handler is maintained internally in a boost::function&lt;void ()&gt; reference. Whenever the operation processing requires an AMI call to another component, a callback operation is created to receive the results. This is considered a state transition point. The operation transitions its state internally, and invokes the remote call on Component X. Until the results of the AMI call are received, there is no thread blocked within the Server Component. The AMI callback will reschedule the operation to be processed on the work queue, which enters the state machine in the state transitioned to prior to the AMI call. </p>

<div class='table-wrap'>
<table class='confluenceTable'><tbody>
<tr>
<td class='confluenceTd'><span class="image-wrap" style=""><img src="/wiki/download/attachments/10649930/async_op_state_machine.png?version=1&amp;modificationDate=1293125402006" style="border: 1px solid black" /></span></td>
</tr>
<tr>
<td class='confluenceTd'><b>Figure 2. Server Component Details</b></td>
</tr>
</tbody></table>
</div>


<p>This process can be repeated as many times as required. For each AMI call required, an additional state is defined in the state machine. Exceptions to this would be when a collector for multiple similar AMI calls is used to aggregate the results of multiple outbound calls into a single response. </p>

<p>&lt;TBD... rest is placeholder...&gt;</p>

<h3><a name="ComponentThreadingDesignforAsynchronousOperations-ImplementationDetails"></a>Implementation Details</h3>

<ul class="alternate" type="square">
        <li>shared pointer usage<br/>
  &gt; Servant's map of ongoing operations<br/>
  &gt; Work queue<br/>
  &gt; Callback objects</li>
</ul>


<ul class="alternate" type="square">
        <li>Work Queue<br/>
  &gt; General interface</li>
        <li>Supportive of thread pools</li>
</ul>



<h3><a name="ComponentThreadingDesignforAsynchronousOperations-ImpactonStateReplication"></a>Impact on State Replication</h3>

<ul class="alternate" type="square">
        <li>additional states to specifically capture AMI-waiting states will be needed</li>
</ul>


<h3><a name="ComponentThreadingDesignforAsynchronousOperations-SpecificElementsoftheBasicRoutingServiceImplementation"></a>Specific Elements of the Basic Routing Service Implementation</h3>

<ul class="alternate" type="square">
        <li>lookup() (a separate interface from SessionRouter) is implemented as AMD, but called locally.</li>
        <li>Calls made using two-ways until performance benchmarks show where further AMI useful, since we've offloaded the work from I/O threads onto Work Queue.</li>
</ul>


    </div>
        <div id="commentsSection" class="wiki-content pageSection">
        <div style="float: right;">
            <a href="https://wiki.asterisk.org/wiki/users/viewnotifications.action" class="grey">Change Notification Preferences</a>
        </div>
        <a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Threading+Design+for+Asynchronous+Operations">View Online</a>
        |
        <a href="https://wiki.asterisk.org/wiki/pages/diffpagesbyversion.action?pageId=10649930&revisedVersion=4&originalVersion=3">View Changes</a>
                |
        <a href="https://wiki.asterisk.org/wiki/display/TOP/Component+Threading+Design+for+Asynchronous+Operations?showComments=true&amp;showCommentArea=true#addcomment">Add Comment</a>
            </div>
</div>
</div>
</div>
</div>
</body>
</html>