<div dir="ltr"><div>The test fails every time NodeB (cache2) happens to <b>not be</b> the primary owner of &#39;newGoat&#39;, and needs to forward the command to NodeA. Sequence of events:<br><br>1) [NodeB] Compute is called, key is &#39;newGoat&#39;<br>2) [NodeB] Command gets visited by the QueryInterceptor, that suspends the execution<br>3) [NodeB] Owner for &#39;newGoat&#39; is nodeA, so nodeB forwards the command to nodeA<br><br>4) [NodeA] Command gets visited by the QueryInterceptor, that suspends the execution<br>5) [NodeA] perform() is called in the Compute command<br>6) [NodeA] Command is then sent to NodeB, which is a backup owner<br><br>7) [NodeB] Command gets visited by the QueryInterceptor, that suspends the execution<br>8) [NodeB] perform() is called in the compute command<br>9) [NodeB] QueryInterceptor resumes execution. Since command was originated remotely, no indexing is done (due to Index.LOCAL)<br><br>9) [NodeA] Receive response from the call done on 6)<br>10)[NodeA] resumes execution from the QueryInterceptor from 4)<br>11)[NodeA] Since command was originated remotely, no indexing is done (due to Index.LOCAL)<br><br>12)[NodeB] receives response from 3). At this point <b>the computed value is available</b> as the return type of the remote invocation<br>13)[NodeB] resumes the QueryInterceptor invocation from 2)<br>14)[NodeB] processComputes is then executed, but since the computedValue is not available in the command itself nor in the context, indexing is skipped since there is no value to index or remove<br><br><br></div><div>Looking at the method visitComputCommand, the variable &quot;rv&quot; stores the return value from the command, but it&#39;s not being used, instead the stateBeforeCompute is used which is always null in this scenario,<br></div><div>because it is evaluated on 2) which is before the the key exists in the data container:<br></div><div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:&quot;dejavu sans mono&quot;;font-size:9pt"><span style="color:rgb(0,0,128);font-weight:bold">return </span>invokeNextThenAccept(ctx, command, (rCtx, rCommand, rv) -&gt; processComputeCommand(((ComputeCommand) rCommand), rCtx, <span style="background-color:rgb(228,228,255)">stateBeforeCompute</span>, <span style="color:rgb(0,0,128);font-weight:bold">null</span>));<br></pre></div><div><div><div><div><pre style="background-color:rgb(255,255,255);color:rgb(0,0,0);font-family:&quot;dejavu sans mono&quot;;font-size:9pt"><br>Gustavo</pre><div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, May 9, 2017 at 2:21 PM, Katia Aresti <span dir="ltr">&lt;<a href="mailto:karesti@redhat.com" target="_blank">karesti@redhat.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div>Hi all,</div><div><br></div><div>I&#39;m really struggling with something in order to finish the compute methods.</div><div><br></div><div>I added a test in <b>ClusteredCacheWithElasticsearc<wbr>hIndexManagerIT</b></div><div><br></div><div><pre style="color:rgb(0,0,0);font-family:menlo;font-size:9pt"><pre style="font-family:menlo;font-size:9pt"><span style="color:rgb(0,0,128);font-weight:bold">public void </span>testToto() <span style="color:rgb(0,0,128);font-weight:bold">throws </span>Exception {<br>    SearchManager searchManager = Search.<span style="font-style:italic">getSearchManager</span>(<span style="color:rgb(102,14,122);font-weight:bold">cache2</span><wbr>);<br>    QueryBuilder queryBuilder = searchManager<br>          .buildQueryBuilderForClass(Per<wbr>son.<span style="color:rgb(0,0,128);font-weight:bold">class</span>)<br>          .get();<br>    Query allQuery = queryBuilder.all().createQuery<wbr>();<br><br>    String key = <span style="color:rgb(0,128,0);font-weight:bold">&quot;newGoat&quot;</span>;<br>    Person person4 = <span style="color:rgb(0,0,128);font-weight:bold">new </span>Person(key, <span style="color:rgb(0,128,0);font-weight:bold">&quot;eats something&quot;</span>, <span style="color:rgb(0,0,255)">42</span>);<br><br>    <span style="color:rgb(102,14,122);font-weight:bold">cache2</span>.putIfAbsent(key, person4);<br>    StaticTestingErrorHandler.<span style="font-style:italic">asse<wbr>rtAllGood</span>(<span style="color:rgb(102,14,122);font-weight:bold">cache1</span>, <span style="color:rgb(102,14,122);font-weight:bold">cache2</span>);<br><br>    List&lt;Person&gt; found = searchManager.&lt;Person&gt;getQuery<wbr>(allQuery, Person.<span style="color:rgb(0,0,128);font-weight:bold">class</span>).list();<br>    <span style="font-style:italic">assertEquals</span>(<span style="color:rgb(0,0,255)">1</span>, found.size());<br>    <span style="font-style:italic">assertTrue</span>(found.contains(pers<wbr>on4));<br>}</pre></pre></div><div><div>I put some logs in the <span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-family:menlo;font-size:9pt">processPutKeyValueCommand </span><wbr>method in the <b>QueryInterceptor</b> to explain what is happening.<br></div><div><br></div><div><b>2 threads</b></div><div>Sometimes two threads get involved. </div><div><br></div><div>= Thread 72 First (or second) call </div><div>It happens from a non local Node. The so the <span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-family:menlo;font-size:9pt">shouldModifyIndexes </span>says &quot;no, you should not modify any index&quot; because the <span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-family:menlo;font-size:9pt">IndexModificationStrategy</span> <wbr>is set to &quot;LOCAL ONLY&quot;. [1]<br></div><div><br></div><div><div><font face="monospace, monospace">72 ctx.getOrigin() = ClusteredCacheWithElasticsearc<wbr>hIndexManagerIT-NodeB-19565</font></div><div><font face="monospace, monospace">72 should modify false</font></div><div><font face="monospace, monospace">72 previousValue null</font></div><div><font face="monospace, monospace">72 putValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null} // value in the command</font></div><div><font face="monospace, monospace">72 contextValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null} //value in the invocation context</font></div></div><div><br></div><div>= Thread 48 Second (or first) call</div><div>the origin is null, and this is considered as a LOCAL in the <span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-family:menlo;font-size:9pt">SingleKeyNonTxInvocationCo<wbr>ntext. [2]</span> In this case, the index is modified correctly, the value in the context has already been set up by the PutKeyValueCommand and the index get&#39;s correctly updated.</div><div><br></div><div><div><font face="monospace, monospace">48 ctx.getOrigin() = null</font></div><div><font face="monospace, monospace">48 should modify true</font></div><div><font face="monospace, monospace">48 previousValue null</font></div><div><font face="monospace, monospace">48 putValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace">48 contextValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div></div><div><br></div><div>And everything is ok. Everything is fine too in the case of a compute method instead of the put method.</div><div><br></div><div>But sometimes, this is not executed like that.</div></div><div><br></div><div><div><b>3 threads</b></div></div><div><b><br></b></div><div><div>What is a bit more weird to me is this second scenario where the commands are executed both from non local nodes (A and B). And so the index is not updated.</div><div>But  just later, another thread get&#39;s involved and calls the QueryInterceptor with a invocation context where the command has not been executed (the value is not inside the context and the debugger does not enter in the perform method, this has happened just twice before). This call is coming like from a callback? in the <span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-family:menlo;font-size:9pt">QueueAsyncInvocationStage.</span></div></div><div><span style="background-color:rgb(228,228,255);color:rgb(0,0,0);font-size:9pt"><font face="monospace, monospace"><br></font></span></div><div><div><font face="monospace, monospace">80 ctx.getOrigin() = ClusteredCacheWithElasticsearc<wbr>hIndexManagerIT-NodeA-65110</font></div><div><font face="monospace, monospace">80 should modify false</font></div><div><font face="monospace, monospace">80 prev null</font></div><div><font face="monospace, monospace">80 putValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace">80 contextValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">38 ctx.getOrigin() = ClusteredCacheWithElasticsearc<wbr>hIndexManagerIT-NodeB-35919</font></div><div><font face="monospace, monospace">38 should modify false</font></div><div><font face="monospace, monospace">38 prev null</font></div><div><font face="monospace, monospace">38 putValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace">38 contextValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">48 ctx.getOrigin() = null</font></div><div><font face="monospace, monospace">48 should modify true</font></div><div><font face="monospace, monospace">48 prev null</font></div><div><font face="monospace, monospace">48 putValue Person{name=&#39;newGoat&#39;, blurb=&#39;eats something&#39;, age=42, dateOfGraduation=null}</font></div><div><font face="monospace, monospace" color="#ff0000">48 contextValue null</font></div></div><div><br></div><div><br></div><div>This execution works perfectly with PutKeyValueCommand. But don&#39;t work wth compute.</div><div><br></div><div>The &quot;computed value&quot; is not inside the Command like put, replace or others. It is computed in the perform method (if needed). So, the first time the command is executed in A, the computed value is in the context, but the index is not updated. Second call, executed in B, value in context, but the index is not updated. The magic callback is executed, but the computed value is nowhere because the command is not executed a third time, so the context is null.<br></div><div><br></div><div>Can somebody please give me some light on this and explain to me what am I missing ? Other tests are failing for the same problem, like org.infinispan.query.blac<wbr>kbox.ClusteredCacheWithInfinis<wbr>panDirectoryTest</div><div><br></div><div>Thank you very much for your help !</div><div><br></div><div>Katia</div><div><br></div><div>[1] <a href="https://github.com/infinispan/infinispan/blob/master/query/src/main/java/org/infinispan/query/backend/IndexModificationStrategy.java#L50" target="_blank">https://github.com/infinis<wbr>pan/infinispan/blob/master/<wbr>query/src/main/java/org/<wbr>infinispan/query/backend/Index<wbr>ModificationStrategy.java#L50</a></div><div>[2] <a href="https://github.com/infinispan/infinispan/blob/master/core/src/main/java/org/infinispan/context/SingleKeyNonTxInvocationContext.java#L39" target="_blank">https://github.com/infinis<wbr>pan/infinispan/blob/master/<wbr>core/src/main/java/org/infinis<wbr>pan/context/SingleKeyNonTxInvo<wbr>cationContext.java#L39</a></div><div><br></div></div>
<br>______________________________<wbr>_________________<br>
infinispan-dev mailing list<br>
<a href="mailto:infinispan-dev@lists.jboss.org" target="_blank">infinispan-dev@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" target="_blank">https://lists.jboss.org/mailma<wbr>n/listinfo/infinispan-dev</a><br></blockquote></div><br></div></div></div></div></div></div></div>