<html>
 <body>
  <div style="font-family: Verdana, Arial, Helvetica, Sans-Serif;">
   <table bgcolor="#f9f3c9" width="100%" cellpadding="8" style="border: 1px #c9c399 solid;">
    <tr>
     <td>
      This is an automatically generated e-mail. To reply, visit:
      <a href="https://reviewboard.asterisk.org/r/2164/">https://reviewboard.asterisk.org/r/2164/</a>
     </td>
    </tr>
   </table>
   <br />









<div>




<table width="100%" border="0" bgcolor="white" style="border: 1px solid #C0C0C0; border-collapse: collapse; margin: 2px padding: 2px;">
 <thead>
  <tr>
   <th colspan="4" bgcolor="#F0F0F0" style="border-bottom: 1px solid #C0C0C0; font-size: 9pt; padding: 4px 8px; text-align: left;">
    <a href="https://reviewboard.asterisk.org/r/2164/diff/1/?file=31870#file31870line1305" style="color: black; font-weight: bold; text-decoration: underline;">/branches/1.8/apps/app_queue.c</a>
    <span style="font-weight: normal;">

     (Diff revision 1)

    </span>
   </th>
  </tr>
 </thead>

 <tbody style="background-color: #e4d9cb; padding: 4px 8px; text-align: center;">
  <tr>

   <td colspan="2"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
   <td colspan="2"><pre style="font-size: 8pt; line-height: 140%; margin: 0; ">static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)</pre></td>

  </tr>
 </tbody>




 
 



 <tbody>

  <tr>
    <th bgcolor="#b1ebb0" style="border-right: 1px solid #C0C0C0;" align="right"><font size="2"></font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
    <th bgcolor="#b1ebb0" style="border-left: 1px solid #C0C0C0; border-right: 1px solid #C0C0C0;" align="right"><font size="2">1305</font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "><span class="k">static</span> <span class="kt">void</span> <span class="nf">queue_member_follower_removal</span><span class="p">(</span><span class="k">struct</span> <span class="n">call_queue</span> <span class="o">*</span><span class="n">queue</span><span class="p">,</span> <span class="k">struct</span> <span class="n">member</span> <span class="o">*</span><span class="n">mem</span><span class="p">)</span></pre></td>
  </tr>

  <tr>
    <th bgcolor="#b1ebb0" style="border-right: 1px solid #C0C0C0;" align="right"><font size="2"></font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
    <th bgcolor="#b1ebb0" style="border-left: 1px solid #C0C0C0; border-right: 1px solid #C0C0C0;" align="right"><font size="2">1306</font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "><span class="p">{</span></pre></td>
  </tr>

  <tr>
    <th bgcolor="#b1ebb0" style="border-right: 1px solid #C0C0C0;" align="right"><font size="2"></font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
    <th bgcolor="#b1ebb0" style="border-left: 1px solid #C0C0C0; border-right: 1px solid #C0C0C0;" align="right"><font size="2">1307</font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; ">        <span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">mem</span><span class="o">-&gt;</span><span class="n">rr_queuepos</span><span class="p">;</span></pre></td>
  </tr>

  <tr>
    <th bgcolor="#b1ebb0" style="border-right: 1px solid #C0C0C0;" align="right"><font size="2"></font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
    <th bgcolor="#b1ebb0" style="border-left: 1px solid #C0C0C0; border-right: 1px solid #C0C0C0;" align="right"><font size="2">1308</font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; ">        <span class="n">ao2_callback</span><span class="p">(</span><span class="n">queue</span><span class="o">-&gt;</span><span class="n">members</span><span class="p">,</span> <span class="n">OBJ_NODATA</span> <span class="o">|</span> <span class="n">OBJ_MULTIPLE</span><span class="p">,</span> <span class="n">queue_member_decrement_followers</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pos</span><span class="p">);</span></pre></td>
  </tr>

  <tr>
    <th bgcolor="#b1ebb0" style="border-right: 1px solid #C0C0C0;" align="right"><font size="2"></font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "></pre></td>
    <th bgcolor="#b1ebb0" style="border-left: 1px solid #C0C0C0; border-right: 1px solid #C0C0C0;" align="right"><font size="2">1309</font></th>
    <td bgcolor="#c5ffc4" width="50%"><pre style="font-size: 8pt; line-height: 140%; margin: 0; "><span class="p">}</span></pre></td>
  </tr>

 </tbody>

</table>

<pre style="margin-left: 2em; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">Small addendum here in response to something I uncovered while testing:

        /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don&#39;t skip the member
         * who would have been next otherwise. */
        if (pos &lt; queue-&gt;rrpos) {
                queue-&gt;rrpos--;
        }

goes between the pos declaration and the ao2_callback.</pre>
</div>
<br />



<p>- jrose</p>


<br />
<p>On October 16th, 2012, 3:26 p.m., jrose wrote:</p>






<table bgcolor="#fefadf" width="100%" cellspacing="0" cellpadding="8" style="background-image: url('https://reviewboard.asterisk.org/media/rb/images/review_request_box_top_bg.png'); background-position: left top; background-repeat: repeat-x; border: 1px black solid;">
 <tr>
  <td>

<div>Review request for Asterisk Developers, Mark Michelson, rmudgett, Matt Jordan, and kmoore.</div>
<div>By jrose.</div>


<p style="color: grey;"><i>Updated Oct. 16, 2012, 3:26 p.m.</i></p>




<h1 style="color: #575012; font-size: 10pt; margin-top: 1.5em;">Description </h1>
<table width="100%" bgcolor="#ffffff" cellspacing="0" cellpadding="10" style="border: 1px solid #b8b5a0">
 <tr>
  <td>
   <pre style="margin: 0; padding: 0; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">This patch is a complicated way to solve what appears on the surface to be a simple problem.

When using the round robin memory strategy for a queue, Asterisk dumps all members into an ao2_container (read: hash table) without any reliable ordering. In order to get a member out of that hash, for the purpose of calling a member in the queue, it tracks a round robin position variable and simply iterates along the queue members until it reaches that member position.

Round Robin Ordered causes the order to be forced to the order the members are added by making the hash table have a single bucket, effectively making the container into a linked list. Ordering becomes much more predictable this way.

The problem reported in this case was that when adding and removing members to/from a queue in various ways, the order isn&#39;t preserved. In the case of rrmemory, this is because the items themselves are capable of moving from position to position, so the new member can be placed in front of the old one cause it to &#39;slide back&#39; in the order. In this manner, it&#39;s possible for a single member to be called twice in a row if a member is added between calls into the queue.

Another problem which can occur when removing a member is that a member will be skipped when a member is removed. This occurs for similar reasons. This also affects round robin ordered unlike with the addition of a member since members can be removed regardless members being in front of or behind them (with rrordered, additions always occur at the end of the linked list)

Addressing this required the addition of a field to members (rr_queuepos) which tracks where in the queue a member is supposed to be. Each time a member is added, their queuepos is set to be the next available position in the list. If a member is removed from the queue, then that member&#39;s order is checked and all members of the queue with a larger order value will see their order decremented by one. If this occurs with many members at once (such as in the case of a reload) then this process may be repeated multiple times so that no value will be skipped.

This effectively makes the behavior of both round robin queues the same as far as picking which member is next is concerned. I&#39;m not sure if that could be considered a breaking change since the order of rrmemory before isn&#39;t guaranteed to follow any particular metric.</pre>
  </td>
 </tr>
</table>


<h1 style="color: #575012; font-size: 10pt; margin-top: 1.5em;">Testing </h1>
<table width="100%" bgcolor="#ffffff" cellspacing="0" cellpadding="10" style="border: 1px solid #b8b5a0">
 <tr>
  <td>
   <pre style="margin: 0; padding: 0; white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;">Checked that order is followed by calling into queues, tested removal and addition from rrordered and rrmemory queues, tested reloads.</pre>
  </td>
 </tr>
</table>



<div style="margin-top: 1.5em;">
 <b style="color: #575012; font-size: 10pt; margin-top: 1.5em;">Bugs: </b>


 <a href="https://issues.asterisk.org/jira/browse/AST-989">AST-989</a>


</div>


<h1 style="color: #575012; font-size: 10pt; margin-top: 1.5em;">Diffs</b> </h1>
<ul style="margin-left: 3em; padding-left: 0;">

 <li>/branches/1.8/apps/app_queue.c <span style="color: grey">(375024)</span></li>

</ul>

<p><a href="https://reviewboard.asterisk.org/r/2164/diff/" style="margin-left: 3em;">View Diff</a></p>




  </td>
 </tr>
</table>








  </div>
 </body>
</html>