<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Oct 14, 2014 at 9:55 AM, Radim Vansa <span dir="ltr">&lt;<a href="mailto:rvansa@redhat.com" target="_blank">rvansa@redhat.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 10/13/2014 05:55 PM, Mircea Markus wrote:<br>
&gt; On Oct 13, 2014, at 14:06, Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com">dan.berindei@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; On Fri, Oct 10, 2014 at 9:01 PM, Mircea Markus &lt;<a href="mailto:mmarkus@redhat.com">mmarkus@redhat.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; On Oct 10, 2014, at 17:30, William Burns &lt;<a href="mailto:mudokonman@gmail.com">mudokonman@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt;&gt;&gt; Also we didn&#39;t really talk about the fact that these methods would<br>
&gt;&gt;&gt;&gt;&gt;&gt;&gt; ignore ongoing transactions and if that is a concern or not.<br>
&gt;&gt;&gt;&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;&gt;&gt; It might be a concern for the Hibernate 2LC impl, it was their TCK that<br>
&gt;&gt;&gt;&gt;&gt;&gt; prompted the last round of discussions about clear().<br>
&gt;&gt;&gt;&gt;&gt; Although I wonder how much these methods are even used since they only<br>
&gt;&gt;&gt;&gt;&gt; work for Local, Replication or Invalidation caches in their current<br>
&gt;&gt;&gt;&gt;&gt; state (and didn&#39;t even use loaders until 6.0).<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; There is some more information about the test in the mailing list discussion<br>
&gt;&gt;&gt;&gt; [1]<br>
&gt;&gt;&gt;&gt; There&#39;s also a JIRA for clear() [2]<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I think 2LC almost never uses distribution, so size() being local-only<br>
&gt;&gt;&gt;&gt; didn&#39;t matter, but making it non-tx could cause problems - at least for that<br>
&gt;&gt;&gt;&gt; particular test.<br>
&gt;&gt;&gt; I had toyed around with the following idea before, but I never thought<br>
&gt;&gt;&gt; of it in the scope of the size method solely, but I have a solution<br>
&gt;&gt;&gt; that would work mostly for transactional caches.  Essentially the size<br>
&gt;&gt;&gt; method would always operate in a READ_COMMITTED like state, using<br>
&gt;&gt;&gt; REPEATABLE_READ doesn&#39;t seem feasible since we can&#39;t keep all the<br>
&gt;&gt;&gt; contents in memory.  Essentially the iterator would be ran and for<br>
&gt;&gt;&gt; each key that is found it checks the context to see if it is there.<br>
&gt;&gt;&gt; If the context entry is marked as removed it doesn&#39;t count the key, if<br>
&gt;&gt;&gt; the key is there it marks the key as found and counts it, and if it is<br>
&gt;&gt;&gt; not found it counts it.  Then after iteration it finds all the keys in<br>
&gt;&gt;&gt; the context that were not found and also adds them to the count.  This<br>
&gt;&gt;&gt; way it doesn&#39;t need to store additional memory (besides iteration<br>
&gt;&gt;&gt; costs) as all the context information is in memory.<br>
&gt;&gt; sounds good to me.<br>
&gt;&gt;<br>
&gt;&gt; Mircea, you have to decide whether you want the precise estimation using the entry iterator or the loose estimation using dataContainer.size() :)<br>
&gt;&gt;<br>
&gt;&gt; I guess we can&#39;t make size() read everything into the invocation context, so READ_COMMITTED is all we can provide if we want to keep size() transactional. Maybe we don&#39;t really need it though... Will, could you investigate the failing test that started the clear() thread [1] to see if it really needs size() to be transactional?<br>
&gt; I&#39;m okay with both approaches TBH, both are much better than what we currently have. The accurate one is more costly but seems to be the solution of choice so let&#39;s go for it.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;&gt; My original thought was to also make the EntryIterator transactional<br>
&gt;&gt;&gt; in the same way which also means the keySet, entrySet and values<br>
&gt;&gt;&gt; methods could do the same things.  The main reason stumbling block I<br>
&gt;&gt;&gt; had was the fact that the iterator and various collections returned<br>
&gt;&gt;&gt; could be used outside of the ongoing transaction which didn&#39;t seem to<br>
&gt;&gt;&gt; make much sense to me.  But maybe these should be changed to be more<br>
&gt;&gt;&gt; like backing maps which HashMap, ConcurrentHashMap etc use for their<br>
&gt;&gt;&gt; methods, where instead it would pick up the transaction if there is<br>
&gt;&gt;&gt; one in the current thread and if there is no transaction just start an<br>
&gt;&gt;&gt; implicit one.<br>
&gt;&gt; or if they are outside of a transaction to deny progress<br>
&gt;&gt;<br>
&gt;&gt; I don&#39;t think it&#39;s fair to require an explicit transaction for every entrySet(). It should be possible to start an iteration without a transaction, and only to invalidate an iteration started from an explicit transaction the moment the transaction is committed/rolled back (although it would complicate rules a bit).<br>
&gt;&gt;<br>
&gt;&gt; And what happens if the user writes to the cache while it&#39;s iterating through the cache-backed collection? Should the user see the new entry in the iteration, or not? I don&#39;t think you can figure out at the end of the iteration which keys were included without keeping all the keys on the originator.<br>
&gt; If the modification is done outside the iterator one might expect an ConcurrentModificationException, as it is the case with some JDK iterators.<br>
<br>
</div></div>-1 We&#39;re aiming at high performance cache with a lot of changes while<br>
the operation is executed. This way, the iteration would never complete,<br>
unless you explicitly switch the cache to read only mode (either through<br>
Infinispan operation or in application).<br></blockquote><div><br></div><div>I was referring only to changes made in the same transaction, not changes made by other transactions. But you make a good point, we can&#39;t throw a ConcurrentModificationException if the user for writes in the same transaction and ignore other transactions.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
I think that adding isCacheModified() or isTopologyChanged() to the<br>
iterator would make sense, if that&#39;s not too complicated to implement.<br>
Though, if we want non-disturbed iteration, snapshot isolation is the<br>
only answer.<span class="HOEnZb"><font color="#888888"><br></font></span></blockquote><div><br></div><div>isCacheModified() is probably too costly to implement. </div><div>isTopologyChanged() could be done, but I&#39;m not sure what&#39;s the use case, as the entry iterator abstracts topology changes from the user.</div><div><br></div><div>I don&#39;t think we want undisturbed iteration, at least not at this point. Personally, I just want to have a good story on why the iteration behaves in a certain way. By my standards, explaining that changes made by other transactions may completely/partially/not at all be visible in the iteration is fine, explaining that changes made by the same transaction may or may not be visible is not.</div><div><br></div><div><br></div><div>Cheers</div><div>Dan</div><div><br></div></div></div></div>