<br><div class="gmail_quote">On Fri, Jun 28, 2013 at 12:17 AM, William Burns <span dir="ltr">&lt;<a href="mailto:mudokonman@gmail.com" target="_blank">mudokonman@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

Trying to leave my points that would most likely have responses to<br>
second email so we can try to get back to a single thread :)<br>
<div class="im"><br></div></blockquote><div><br>No such luck :)<br><br>Sorry for sending 2 replies in the first place, but it seemed more natural - I meant to comment on your proposal in one email and to describe my alternative proposal in the second email.<br>

 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
On Thu, Jun 27, 2013 at 4:12 PM, Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com">dan.berindei@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt; On Thu, Jun 27, 2013 at 4:18 PM, William Burns &lt;<a href="mailto:mudokonman@gmail.com">mudokonman@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; First off I apologize for the length.<br>
&gt;&gt;<br>
&gt;&gt; There have been a few Jiras recently that have identified L1 consistency<br>
&gt;&gt; issues with both TX and non TX sync caches.  Async caches with L1 have their<br>
&gt;&gt; own issues as well, but I only wanted to talk about sync caches.<br>
&gt;&gt;<br>
&gt;&gt; <a href="https://issues.jboss.org/browse/ISPN-3197" target="_blank">https://issues.jboss.org/browse/ISPN-3197</a><br>
&gt;&gt; <a href="https://issues.jboss.org/browse/ISPN-2965" target="_blank">https://issues.jboss.org/browse/ISPN-2965</a><br>
&gt;&gt; <a href="https://issues.jboss.org/browse/ISPN-2990" target="_blank">https://issues.jboss.org/browse/ISPN-2990</a><br>
&gt;&gt;<br>
&gt;&gt; I have proposed a solution in<br>
&gt;&gt; <a href="https://github.com/infinispan/infinispan/pull/1922" target="_blank">https://github.com/infinispan/infinispan/pull/1922</a> which should start L1<br>
&gt;&gt; consistency down the right track.  There are quite a few comments on it if<br>
&gt;&gt; you want to look into it more, but because of that I am moving this to the<br>
&gt;&gt; dev mailing list.<br>
&gt;&gt;<br>
&gt;&gt; The key changes in the PR are the following (non-tx):<br>
&gt;&gt;<br>
&gt;&gt; 1. Concurrent reads for a key that can retrieve a remote value are<br>
&gt;&gt; &quot;corralled&quot; into a single thread of execution for that given key.  This<br>
&gt;&gt; would reduce network traffic with concurrent gets for the same key.  Note<br>
&gt;&gt; the &quot;corralling&quot; only happens on a per key basis.<br>
&gt;<br>
&gt;<br>
&gt; Get commands on owners should not be serialized. Get commands on non-owners<br>
&gt; should not be serialized either, if the key already exists in L1. So I&#39;d say<br>
&gt; L1ReadSynchronizer should be L1WriteSynchronizer instead :)<br>
<br>
</div>You are suggesting to check the context to see if the key is present<br>
before attempting the synchronizer right?  Reading your second email<br>
that seems the case :)<br>
<div class="im"><br></div></blockquote><div><br>Nope, I meant we should check the data container (aka the L1 cache). But obviously we have to check the invocation context first in a tx cache, if the tx read the key before it should see the same value.<br>

 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
&gt;<br>
&gt;&gt;<br>
&gt;&gt; 2. The single thread that is doing the remote get would update the L1 if<br>
&gt;&gt; able (without locking) and make available the value to all the requests<br>
&gt;&gt; waiting on the get.<br>
&gt;<br>
&gt;<br>
&gt; Well, L1ReadSynchronizer does prevent other threads from modifying the same<br>
&gt; key, so we are locking the key - just not using LockManager.<br>
&gt; It would also require StateTransferLock.acquireSharedTopologyLock() to make<br>
&gt; sure it doesn&#39;t write an L1 entry after the node became a proper owner.<br>
<br>
</div>Agree, when I was saying locking I was meaning through the use of the<br>
lock manager.<br>
<div class="im"><br></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
&gt;<br>
&gt;&gt;<br>
&gt;&gt; 3. Invalidations that are received would first check to see if there is a<br>
&gt;&gt; current remote get occurring for it&#39;s keys.  If there is it will attempt to<br>
&gt;&gt; cancel the L1 write(s) before it occurs.  If it cannot cancel the L1 write,<br>
&gt;&gt; then it must also wait on the current remote get completion and subsequently<br>
&gt;&gt; run the invalidation.  Note the cancellation would fail when the remote get<br>
&gt;&gt; was done and it is in the middle of updating the L1, so this would be very<br>
&gt;&gt; small window.<br>
&gt;<br>
&gt;<br>
&gt; I think it would be clearer to describe this as the L1 invalidation<br>
&gt; cancelling the remote get, not the L1 update, because the actual L1 update<br>
&gt; can&#39;t be cancelled.<br>
<br>
</div>When I say L1 update I meant the write to the data container after the<br>
remote get.  The invalidation can&#39;t stop the remote get, all it does<br>
is tell the caller that &quot;Hey don&#39;t write the remote value you<br>
retrieved into the L1.&quot;<br>
<div class="im"><br></div></blockquote><div><br>Oh right, the get command will still use the value it got from the remote node, it just won&#39;t write it.<br>That makes me wonder, though, if something like this can happen:<br>

<br>1. A invokes get(k), starts a L1ReadSynchronizer and a remote get to B<br>2. B invokes put(k, v) and sends an invalidation command to A<br>3. The invalidation command cancels the L1 put on A<br>4. A invokes get(k) again, finds the L1ReadSynchronizer from step 1) and queues on it<br>

5. Both get(k) commands return the same value, even though the value has changed on the owner(s).<br><br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">


&gt;<br>
&gt; We also have to remove the logic in AbstractLockingInterceptor that skips L1<br>
&gt; invalidation for a key if it can&#39;t acquire a lock with a 0 timeout.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; 4. Local writes will also do the same thing as the invalidation with<br>
&gt;&gt; cancelling or waiting.  Note that non tx local writes only do L1<br>
&gt;&gt; invalidations and don&#39;t write the value to the data container.  Reasons why<br>
&gt;&gt; I found at <a href="https://issues.jboss.org/browse/ISPN-3214" target="_blank">https://issues.jboss.org/browse/ISPN-3214</a><br>
&gt;<br>
&gt;<br>
&gt; I didn&#39;t know about ISPN-3214 or that non-tx writes don&#39;t write to L1, but<br>
&gt; it sounds fair.<br>
<br>
</div>Yeah I really wanted that to work, but without some additional checks<br>
such as versioned data, I don&#39;t see a way to do this without locking<br>
at the primary node like tx caches.<br>
<div class="im"><br></div></blockquote><div><br>In theory, the primary owner could send a synchronous RPC back to the originator while it is holding the lock, saying &quot;ok, you can now write the value to L1&quot;. But I don&#39;t think the slowdown from an additional RPC would be acceptable.<br>

 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
&gt;<br>
&gt;&gt;<br>
&gt;&gt; 5. Writes that require the previous value and don&#39;t have it in the L1<br>
&gt;&gt; would also do it&#39;s get operations using the same &quot;corralling&quot; method.<br>
&gt;<br>
&gt;<br>
&gt; The remoteGetBeforeWrites are a bit different - they don&#39;t happen on<br>
&gt; non-owners, they only happen on writeCH-owners that didn&#39;t receive that<br>
&gt; entry via state transfer yet. They put the value in the InvocationContext,<br>
&gt; but they don&#39;t write it to the data container - nor do they invalidate the<br>
&gt; L1 entry, if it exists.<br>
<br>
</div>Ah yes that is true, but only for non tx caches it seems.<br>
<div class="im"><br></div></blockquote><div><br>Right, I wasn&#39;t considering the fact that a conditional command may fail... I think if that happens, even in non-tx caches EntryWrappingInterceptor may write the entry to the data container as an L1 entry. If we move the L1 writes to the L1 interceptor, we must ensure that EntryWrappingInterceptor doesn&#39;t write anything to L1 any more.<br>

<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; 4/5 are not currently implemented in PR.<br>
&gt;&gt;<br>
&gt;&gt; This approach would use no locking for non tx caches for all L1<br>
&gt;&gt; operations.  The synchronization point would be done through the<br>
&gt;&gt; &quot;corralling&quot; method and invalidations/writes communicating to it.<br>
&gt;&gt;<br>
&gt;&gt; Transactional caches would do almost the same thing as non-tx.  Note these<br>
&gt;&gt; changes are not done in any way yet.<br>
&gt;&gt;<br>
&gt;&gt; 1. Gets would now update the L1 immediately after retrieving the value<br>
&gt;&gt; without locking, but still using the &quot;corralling&quot; technique that non-tx<br>
&gt;&gt; does.  Previously the L1 update from a get was transactional.  This actually<br>
&gt;&gt; would remedy issue [1]<br>
&gt;&gt;<br>
&gt;&gt; 2. Writes currently acquire the remote lock when committing, which is why<br>
&gt;&gt; tx caches are able to update the L1 with the value.  Writes would do the<br>
&gt;&gt; same cancellation/wait method as non-tx.<br>
&gt;&gt;<br></div></blockquote><div><br>Hmm, I don&#39;t think your current approach for L1 invalidations would work for L1 writes, because the actual write to the data container is not synchronized (well, technically you still have the 0-timeout locking for invalidation commands, but I think you&#39;re planning to remove that). So it&#39;s possible for an L1 write and an L1 invalidation to wait for the same remote get and then to get executed in the wrong order.<br>

<br>  <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
&gt;&gt; 3. Writes that require the previous value and don&#39;t have it in the L1<br>
&gt;&gt; would also do it&#39;s get operations using the same method.<br>
&gt;<br>
&gt;<br>
&gt; Just like for non-tx caches, I don&#39;t think these remote gets have to be<br>
&gt; stored in L1.<br>
<br>
</div>Tx caches do the remote get and could cache the L1 value immediately.<br>
This would help if the transaction is rolled back or a conditional<br>
operation failed etc.  There are some locking concerns, here but I<br>
will leave that the other post.<br>
<div class="im"><br></div></blockquote><div><br>Right, the L1 entry could be immediately written to the data container, but not if it complicates things too much: most writes should be successful anyway.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<div class="im">
&gt;<br>
&gt;&gt;<br>
&gt;&gt; 4. For tx cache [2] would also have to be done.<br>
&gt;&gt;<br>
&gt;&gt; [1] -<br>
&gt;&gt; <a href="https://issues.jboss.org/browse/ISPN-2965?focusedCommentId=12779780&amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12779780" target="_blank">https://issues.jboss.org/browse/ISPN-2965?focusedCommentId=12779780&amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-12779780</a><br>


&gt;&gt; [2] - <a href="https://issues.jboss.org/browse/ISPN-1540" target="_blank">https://issues.jboss.org/browse/ISPN-1540</a><br>
&gt;&gt;<br>
&gt;&gt; Also rehashing is another issue, but we should be able to acquire the<br>
&gt;&gt; state transfer lock before updating the L1 on a get, just like when an entry<br>
&gt;&gt; is committed to the data container.<br>
&gt;&gt;<br>
&gt;<br>
&gt; The same for L1 invalidations - we don&#39;t want to remove real entries from<br>
&gt; the data container after the local node became an owner.<br>
<br>
</div>Yeah actually as you mentioned this, it sounds like a hole currently<br>
even.  I don&#39;t know if this case can happen, but what if you received<br>
a L1 invalidation and then got a rehash event right before it was<br>
committing it to the container?  It seems the L1 commit to the<br>
container would block until it could get the shared topology lock and<br>
after it could then removes the value.  I probably need to dig into<br>
the state transfer stuff deeper to know myself.<br>
<div class="HOEnZb"><div class="h5"><br></div></div></blockquote><div><br>I think that&#39;s ok, because the value is stale, and any future get/conditional write command will request the new value from the previous owners. <br>

<br>I don&#39;t think the new value can arrive via a StateResponseCommand and be applied to the data container before the invalidation command manages to commit, because the put command sends the invalidations first (synchronously) and only then commits on the owner.<br>

 </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">
&gt;<br>
&gt;&gt;<br>
&gt;&gt; Any comments/concerns would be appreciated.<br>
&gt;&gt;<br>
&gt;&gt; Thanks,<br>
&gt;&gt;<br>
&gt;&gt;  - Will<br>
&gt;&gt;<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; infinispan-dev mailing list<br>
&gt;&gt; <a href="mailto:infinispan-dev@lists.jboss.org">infinispan-dev@lists.jboss.org</a><br>
&gt;&gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br>
&gt;<br>
&gt;<br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; infinispan-dev mailing list<br>
&gt; <a href="mailto:infinispan-dev@lists.jboss.org">infinispan-dev@lists.jboss.org</a><br>
&gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br>
_______________________________________________<br>
infinispan-dev mailing list<br>
<a href="mailto:infinispan-dev@lists.jboss.org">infinispan-dev@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br>
</div></div></blockquote></div><br>