<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Oct 3, 2013 at 1:57 PM, Sanne Grinovero <span dir="ltr">&lt;<a href="mailto:sanne@infinispan.org" target="_blank">sanne@infinispan.org</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>On 3 October 2013 10:29, Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com" target="_blank">dan.berindei@gmail.com</a>&gt; wrote:<br>



&gt;<br>
&gt; On Wed, Oct 2, 2013 at 12:48 PM, Pedro Ruivo &lt;<a href="mailto:pedro@infinispan.org" target="_blank">pedro@infinispan.org</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; On 10/02/2013 12:03 AM, Sanne Grinovero wrote:<br>
&gt;&gt; &gt; I&#39;d love to brainstorm about the clear() operation and what it means<br>
&gt;&gt; &gt; on Infinispan.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I&#39;m not sure to what extent, but it seems that clear() is designed to<br>
&gt;&gt; &gt; work in a TX, or even create an implicit transaction if needed, but<br>
&gt;&gt; &gt; I&#39;m not understanding how that can work.<br>
&gt;<br>
&gt;<br>
&gt; I think it&#39;s pretty straight-forward to define the semantics of operations<br>
&gt; after clear(): they should assume that every key in the cache was removed.<br>
&gt;<br>
&gt; True, like Pedro mentioned, the current implementation allows subsequent<br>
&gt; operations in the same tx to see keys inserted by other txs. But I don&#39;t<br>
&gt; think fixing that would be harder than ensuring that if a tx inserts key k<br>
&gt; owned by nodes A and B, clear() from outside the tx either deletes k on A<br>
&gt; and B or doesn&#39;t delete k on either node.<br>
&gt;<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Obviously a clear() operation isn&#39;t listing all keys explicitly.<br>
&gt;&gt;<br>
&gt;&gt; (offtopic) like entrySet(), keySet(), values() and iterator() when<br>
&gt;&gt; executed in a transactional context. however, I think that this<br>
&gt;&gt; operations are more difficult to handle, because they have to return<br>
&gt;&gt; consistent data...<br>
&gt;<br>
&gt;<br>
&gt; I agree, defining how entrySet() and the others should work in a tx seems<br>
&gt; harder than defining clear().<br>
<br>
</div>I agree, those other nasty beasts are next on my list: see below..<br>
But we&#39;re not arguing about which method deserves the gold medal for<br>
complex design ;-)<br>
<div><br>
<br>
&gt; Will, I&#39;m guessing your fix for ISPN-3560 still allows entrySet() after<br>
&gt; clear() to see entries inserted by another tx in the meantime?<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt; Which<br>
&gt;&gt; &gt; implies that it&#39;s undefined on which keys it&#39;s going to operate when<br>
&gt;&gt; &gt; it&#39;s fired.. that seems like terribly wrong in a distributed key/value<br>
&gt;&gt; &gt; store as we can&#39;t possibly freeze the global state and somehow define<br>
&gt;&gt; &gt; a set of keys which are going to be affected, while an explicit<br>
&gt;&gt; &gt; enumeration is needed to acquire the needed locks.<br>
&gt;&gt;<br>
&gt;&gt; you may not need to explicit acquire the lock for the affected key. you<br>
&gt;&gt; can use a global lock that is share acquired for write transactions<br>
&gt;&gt; without clear operation and exclusively acquire for transactions with<br>
&gt;&gt; clear operation (exactly what I use for Total Order). also, the clear<br>
&gt;&gt; transactions (i.e. the transactions with clear operation) can also only<br>
&gt;&gt; acquired the global lock.<br>
&gt;<br>
&gt;<br>
&gt; +1 for the global lock. It may slow things down a bit in the general case,<br>
&gt; because every tx will have to acquire it in shared mode, but it will<br>
&gt; guarantee consistency for clear().<br>
<br>
</div>I had thought of that too, but it will slow down all operations, at<br>
which benefit?<br>
To have a nice transactional clear() operation which guarantees consistency?<br></blockquote><div><br></div><div>For me, the most important reason is to support the JCache API.<br></div><div></div><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">


<br>
The goal of this thread is to challenge if that makes sense for real use cases,<br>
it seems in fact we would highly prefer a non transactional version,<br>
and considering that we can&#39;t run a single Cache in both modes anymore<br>
that&#39;s a problem. <br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
Side note on the implementation complexity:<br>
even the AsyncCacheStore decorator code is made extremely more tricky<br>
just to handle clear() appropriately, to keep it in the correct order<br>
of execution<br>
compared to the other operations, while still allowing<br>
&quot;coaleshing&quot; of other operations, which essentially implies we allow<br>
reordering of operations as long as they affect independent keys.. where clear()<br>
is of course a jolly which requires it&#39;s own execution path, its own global lock<br>
and generally makes it far more complex.<br></blockquote><div><br></div>Off-topic: I&#39;m not very familiar with the async cache store code, but I really don&#39;t think coalescing writes is good for consistency. In case of a crash, you&#39;d have lots of incomplete transactions on disk.<br>

</div><div class="gmail_quote"><br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><div><br>
&gt;<br>
&gt; It still won&#39;t help entrySet() and its brethren...<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; It might give a nice safe feeling that, when invoking a clear()<br>
&gt;&gt; &gt; operation in a transaction, I can still abort the transaction to make<br>
&gt;&gt; &gt; it cancel the operation; that&#39;s the only good part I can think of: we<br>
&gt;&gt; &gt; can cancel it.<br>
&gt;&gt;<br>
&gt;&gt; yep<br>
&gt;<br>
&gt;<br>
&gt; Wouldn&#39;t it be harder to integrate it with Total Order if it didn&#39;t have a<br>
&gt; tx?<br>
&gt;<br>
&gt; But most of all, I think we have to keep it because it&#39;s a part of the Map<br>
&gt; interface and a part of JCache&#39;s Cache interface.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I don&#39;t think it has anything to do with consistency though? To make<br>
&gt;&gt; &gt; sure you&#39;re effectively involving all replicas of all entries in a<br>
&gt;&gt; &gt; consistent way, a lock would need to be acquired on each affected key,<br>
&gt;&gt; &gt; which again implies a need to enumerate all keys, including the<br>
&gt;&gt; &gt; unknown keys which might be hiding in a CacheStore: it&#39;s not enough to<br>
&gt;&gt; &gt; broadcast the clear() operation to all nodes and have them simply wipe<br>
&gt;&gt; &gt; their local state as that&#39;s never going to deal correctly<br>
&gt;&gt; &gt; (consistently) with in-flight transactions working on different nodes<br>
&gt;&gt; &gt; at different times (I guess enabling Total Order could help but you&#39;d<br>
&gt;&gt; &gt; need to make it mandatory).<br>
&gt;&gt; &gt;<br>
&gt;&gt;<br>
&gt;&gt; see the comment above about the locks... may not be the most efficient,<br>
&gt;&gt; but handles the problem.<br>
&gt;<br>
&gt;<br>
&gt; Note that we need to iterate the keys anyway, in order to fire the<br>
&gt; CacheEntryRemoved listeners. Even if we optimized it skip the iteration when<br>
&gt; there are no registered listeners, it would still have to handle the general<br>
&gt; case.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt; So let&#39;s step back a second and consider what is the use case for<br>
&gt;&gt; &gt; clear() ? I suspect it&#39;s primarily a method needed during testing, or<br>
&gt;&gt; &gt; maybe cleanup before a backup is restored (operations), maybe a<br>
&gt;&gt; &gt; manually activated JMX operation to clear the cache in exceptional<br>
&gt;&gt; &gt; cases.<br>
&gt;&gt;<br>
&gt;&gt; I&#39;m not aware of the uses cases of a clear() operation, but use it as<br>
&gt;&gt; JMX operation can be a problem in transactional caches (depending the<br>
&gt;&gt; semantic you have in mind).<br>
&gt;&gt;<br>
&gt;&gt; If it is going to clear all the caches (i.e. from all replicas/nodes),<br>
&gt;&gt; then we have to find a way to set an order with the current transactions<br>
&gt;&gt; or we will have something some nodes delivering a transaction (say tx1)<br>
&gt;&gt; before the clear() and other nodes delivering tx1 after the clear(),<br>
&gt;&gt; leading to an inconsistent state.<br>
&gt;&gt;<br>
&gt;&gt; (offtopic) I&#39;m wondering if we have that problem in the current<br>
&gt;&gt; implementation if tx1 is only insert new keys... in that case, we have<br>
&gt;&gt; no lock to serialize an order between the clear() and tx1...<br>
&gt;<br>
&gt;<br>
&gt; I&#39;m pretty sure we do have this problem. We definitely need to add some<br>
&gt; tests for clear concurrent with other write operations.<br>
&gt;<br>
&gt; In my view, as long as we&#39;re going to expose a clear() operation in some<br>
&gt; way, it&#39;s going to be easiest to include it in a tx in transactional caches.<br>
&gt; Exposing it in some other way is not going to make it any more consistent,<br>
&gt; although prohibiting other operations in the same tx may make the code a bit<br>
&gt; simpler.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I don&#39;t think there would ever be a need for a clear() operation to<br>
&gt;&gt; &gt; interact with other transactions, so I&#39;d rather make it illegal to<br>
&gt;&gt; &gt; invoke a clear() inside a transaction, or simply ignore the<br>
&gt;&gt; &gt; transactional scope and have an immediate and distributed effect.<br>
&gt;<br>
&gt;<br>
&gt; We can&#39;t control whether other transactions are invoked concurrently with<br>
&gt; clear(), so we can&#39;t make that illegal... If you mean interaction with other<br>
&gt; operations in the same transaction, I agree that it&#39;s not absolutely<br>
&gt; necessary to allow them, but I think most of that work has already been<br>
&gt; done.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; I think the second solution can make inconsistency data (&quot;or simply<br>
&gt;&gt; ignore the transactional scope and have an immediate and distributed<br>
&gt;&gt; effect&quot;)<br>
&gt;<br>
&gt;<br>
&gt; Maybe that&#39;s the idea? Sanne, do you mean that if clear() were exposed via a<br>
&gt; different API, it wouldn&#39;t have to provide the same consistency guarantees<br>
&gt; as regular operations?<br>
<br>
</div></div>Yes that&#39;s the main point that we need to clarify.<br>
Note that this discussion started because of a problem we&#39;re having in<br>
the integration<br>
of Infinispan as Hibernate 2nd level cache, which is a quite mature<br>
contract with<br>
some very clear ideas of how a cache needs to behave.<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
After more discussions yesterday, I think I&#39;m understanding (Galder<br>
will likely know more<br>
but is currently away) that ideally a cache should be able to provide<br>
both a transactional<br>
clear() operation and an immediately-affecting one.<br>
The only need for the transactional one is to be able to undo the<br>
operation in case the<br>
user&#39;s transaction is rolled back: we don&#39;t even support this case<br>
today since it&#39;s suspending<br>
the transaction to run the clear() operation in an independent transaction.<br></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
But the transactional clear() operation is far less important than<br>
having a clear &quot;evict all now&quot;<br>
operation. That&#39;s one of the basic operations a good mannered Cache<br>
should provide:<br>
remember that as a cache it&#39;s always a valid answer to return &quot;null&quot;,<br>
it&#39;s just suboptimal.<br>
Returning the wrong answer instead, can have critical consequences, so<br>
it&#39;s expected to<br>
provide a way for the admin (JMX) or driving application to<br>
immediately wipe the state;<br>
I would argue that even a glocal lock&#39;s timing implications are<br>
undesirable in such a case.<br></blockquote><div><br></div><div>TBH I&#39;m not sure how would such an &quot;evict all now&quot; operation would work in a distributed cache. Could you post a link to the Hibernate docs?<br>

<div>The JCache javadoc for clear() doesn&#39;t say anything about its interaction with transactions.<br>
</div><div> </div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
<br>
Focusing on the identify of Infinispan as a Key/Value store, I&#39;d<br>
consider it almost mandatory<br>
for the client to know - to explicitly list - the keys it&#39;s interested<br>
into, and be completely oblivious<br>
to the entries which you&#39;re unable to list. For example, think of a<br>
cache shared by multiple tenants<br>
or multiple apps, which use keys which for some reason can&#39;t return<br>
true to an equality check<br>
(for example because they&#39;re coming from different classloaders).<br>
In such a perspective, any operation which affects (or enumerates)<br>
keys is a bad practice and<br>
should imho be banned from the user API, unless for administration or<br>
monitoring purposes.<br></blockquote><div><br></div><div>Our Map/Reduce API explicitly supports the user not listing the keys he&#39;s interested in.<br>And we don&#39;t support multi-tenancy in a single cache, every cache must have a single ClassLoader.<br>

</div><div></div> <br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">

<br>
I think this is quite clearly expressed already by all the warning in<br>
javadoc on methods like<br>
  org.infinispan.Cache.keySet()<br>
  org.infinispan.Cache.size()<br>
  ...<br>
They all list a warning about needing to be used only for debug<br>
purposes: I don&#39;t think we need<br>
to waste time into making these transitionally consistent, as people<br>
shouldn&#39;t be using them.<br></blockquote><div><br></div>The JCache API still has a clear() method and an iterator() method, even though their Cache interface doesn&#39;t extend Map. That makes me think that there may be legitimate uses for them, after all. And some users may never see our javadocs, if they use the JCache API.<br>

<div> <br>
</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<br>
<br>
If a transactional clear() operation is possible without overhead,<br>
then the 2nd level cache code<br>
would benefit from it, but it&#39;s a borderline decision and its code<br>
could be refactored to not need this,<br>
at least that&#39;s my understanding so far and I guess we need Galder for<br>
that to be clarified.<br>
<span><font color="#888888"><br>
Sanne<br>
</font></span><div><div><br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; I&#39;m likely missing something. What terrible consequences would this<br>
&gt;&gt; &gt; have?<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Cheers,<br>
&gt;&gt; &gt; Sanne<br>
&gt;&gt; &gt; _______________________________________________<br>
&gt;&gt; &gt; infinispan-dev mailing list<br>
&gt;&gt; &gt; <a href="mailto:infinispan-dev@lists.jboss.org" target="_blank">infinispan-dev@lists.jboss.org</a><br>
&gt;&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;&gt; &gt;<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; infinispan-dev mailing list<br>
&gt;&gt; <a href="mailto:infinispan-dev@lists.jboss.org" target="_blank">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" target="_blank">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" target="_blank">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></div></div>