<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Tue, Mar 28, 2017 at 11:24 AM Sanne Grinovero &lt;<a href="mailto:sanne@infinispan.org">sanne@infinispan.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Will,<br class="gmail_msg">
<br class="gmail_msg">
I&#39;m confused about the premise; when you state<br class="gmail_msg">
<br class="gmail_msg">
&quot; the Consumer is called while holding the lock for the given key and<br class="gmail_msg">
subsequently released after the Consumer operation completes.&quot;<br class="gmail_msg">
<br class="gmail_msg">
What are the transaction boundaries?<br class="gmail_msg">
I see two options, please correct me so I understand:<br class="gmail_msg">
<br class="gmail_msg">
A)<br class="gmail_msg">
<br class="gmail_msg">
transaction.begin();<br class="gmail_msg">
cache.lockedStream().filterKeys(keys).filter(predicate).forEach(<br class="gmail_msg">
someOperation );<br class="gmail_msg">
transaction.commit(); &lt;-- release all locks<br class="gmail_msg">
<br class="gmail_msg">
B)<br class="gmail_msg">
<br class="gmail_msg">
cache.lockedStream().filterKeys(keys).filter(predicate).forEach(<br class="gmail_msg">
    transaction.begin();<br class="gmail_msg">
    //to stuff on entry<br class="gmail_msg">
    /transaction.commit(); &lt;-- release this single entry&#39;s lock<br class="gmail_msg">
);<br class="gmail_msg"></blockquote><div><br></div><div>The user code doesn&#39;t really affect this, it is done internally by Infinispan. We would acquire the lock on the user&#39;s behalf in the stream operation then call the user&#39;s accept method. Then after they return we would unlock the lock. The way I have it implemented at the moment in my PoC (which could change) is I don&#39;t even start a transaction. It just locks the key and then if the user were to invoke an operation that requires a transaction it adds the lock owner to their tx context at that point so they have ownership of the key.</div><div><br></div><div>Also to note that a commit or rollback in the Consumer currently doesn&#39;t release the lock on the key. Although this could be discussed to be possibly changed.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="gmail_msg">
<br class="gmail_msg">
I think it&#39;s important to clarify this as I suspect that #A is not<br class="gmail_msg">
implementable within reasonable guarantees, while in the case of B# I<br class="gmail_msg">
see no use for optimistic locking *from a user&#39;s perspective*.<br class="gmail_msg"></blockquote><div><br></div><div>Exactly my thoughts regarding optimistic. I don&#39;t think #A is even feasible given constraints of having a distributed transaction like this.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="gmail_msg">
Also: what kind of guarantees do you expect about having the operation<br class="gmail_msg">
being applied on some entry which is strictly *still* a subset of the<br class="gmail_msg">
keys as defined by the filter predicates?<br class="gmail_msg">
I take it you&#39;d want to acquire the locks during the filtering process?<br class="gmail_msg"></blockquote><div><br></div><div>That is a good question. I hadn&#39;t thought about the details but what I had implemented was we have to first read the entry, lock the key, reread the entry (in case of concurrent update) and then finally call their Predicate. Another reason the filterKeys is much more efficient :) Note this read, locking and reread is done even without a Predicate supplied. And actually I can also optimize filterKeys to not do the initial read since we already have the key.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="gmail_msg">
That would require the move the transaction boundary to the scenario<br class="gmail_msg">
A# which seems undesirable.<br class="gmail_msg">
Technically if I were to need something like this I guess I&#39;d expect<br class="gmail_msg">
to have a user experience akin to B# but have Infinispan essentially<br class="gmail_msg">
use optimistic locking (and auto-skip) on entries which are mutated<br class="gmail_msg">
and fall out of the filter predicate during the lock attempt.<br class="gmail_msg">
<br class="gmail_msg">
Essentially I suspect that we&#39;d not want to implement different<br class="gmail_msg">
versions of this depending on the transaction mode, but figure out the<br class="gmail_msg">
use case and implement a one and only transaction mode which suites<br class="gmail_msg">
such use cases. So for example we&#39;d simply not offer a mode which<br class="gmail_msg">
requires to copy the whole grid into the current TX context.<br class="gmail_msg"></blockquote><div><br></div><div>This was never the intent and in my follow up emails I came to what seems like the same conclusion that basically this can&#39;t be done with the user controlling the transaction and it doesn&#39;t really make sense in an optimistic transaction (since you are already at that node, you are already doing everything pessimistically).</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br class="gmail_msg">
Thanks,<br class="gmail_msg">
Sanne<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
<br class="gmail_msg">
On 28 March 2017 at 14:49, William Burns &lt;<a href="mailto:mudokonman@gmail.com" class="gmail_msg" target="_blank">mudokonman@gmail.com</a>&gt; wrote:<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; On Mon, Mar 27, 2017 at 9:02 PM Galder Zamarreño &lt;<a href="mailto:galder@redhat.com" class="gmail_msg" target="_blank">galder@redhat.com</a>&gt; wrote:<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; --<br class="gmail_msg">
&gt;&gt; Galder Zamarreño<br class="gmail_msg">
&gt;&gt; Infinispan, Red Hat<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt; On 21 Mar 2017, at 17:16, Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com" class="gmail_msg" target="_blank">dan.berindei@gmail.com</a>&gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; I&#39;m leaning towards option 1.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; Are you thinking about also allowing the consumer to modify the entry,<br class="gmail_msg">
&gt;&gt; &gt; like JCache&#39;s EntryProcessors? For a consumer that can only modify the<br class="gmail_msg">
&gt;&gt; &gt; current entry, we could even &quot;emulate&quot; locking in an optimistic cache<br class="gmail_msg">
&gt;&gt; &gt; by catching the WriteSkewException and running the consumer again.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; I wouldn&#39;t allow this to be mixed with other operations in a stream,<br class="gmail_msg">
&gt;&gt; &gt; because then you may have to run filters/mappers/sorting while holding<br class="gmail_msg">
&gt;&gt; &gt; the lock as well.<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; ^ Would forEach w/ lock still run for all entries in originator? If so,<br class="gmail_msg">
&gt;&gt; not being able to filter could be a pain. IOW, you&#39;d be forcing all entries<br class="gmail_msg">
&gt;&gt; to be shipped to a node and user to do its own filtering. Not ideal :\<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; No the primary owner would run the operation per entry. I was thinking we<br class="gmail_msg">
&gt; would have 2 levels of filtering in my proposal above.<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; We would have the first one which is using filterKeys on the CacheStream<br class="gmail_msg">
&gt; method. This requires serializing keys sent to each node (only primary owned<br class="gmail_msg">
&gt; keys are sent). While it has the cost of serialization it makes up for by<br class="gmail_msg">
&gt; having constant time lookups (no iterating memory/stores) for the keys as it<br class="gmail_msg">
&gt; creates a stream using Cache.get to populate it.<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; The second was to support the filter method on the Stream API which would<br class="gmail_msg">
&gt; allow for a Predicate so you don&#39;t have to serialize keys. In this case you<br class="gmail_msg">
&gt; wouldn&#39;t want to include keys in this Predicate as all keys would be<br class="gmail_msg">
&gt; serialized to all nodes and then you still have to iterate and check the<br class="gmail_msg">
&gt; entire data container/store.<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; You could actually do both as well. So if you only want a subset of known<br class="gmail_msg">
&gt; keys where their values match a Predicate this can be done too.<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; cache.lockedStream().filterKeys(keys).filter(predicate).forEach();<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; Cheers<br class="gmail_msg">
&gt;&gt; &gt; Dan<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; On Tue, Mar 21, 2017 at 5:37 PM, William Burns &lt;<a href="mailto:mudokonman@gmail.com" class="gmail_msg" target="_blank">mudokonman@gmail.com</a>&gt;<br class="gmail_msg">
&gt;&gt; &gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;&gt; Some users have expressed the need to have some sort of forEach<br class="gmail_msg">
&gt;&gt; &gt;&gt; operation<br class="gmail_msg">
&gt;&gt; &gt;&gt; that is performed where the Consumer is called while holding the lock<br class="gmail_msg">
&gt;&gt; &gt;&gt; for<br class="gmail_msg">
&gt;&gt; &gt;&gt; the given key and subsequently released after the Consumer operation<br class="gmail_msg">
&gt;&gt; &gt;&gt; completes.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Due to the nature of how streams work with retries and performing the<br class="gmail_msg">
&gt;&gt; &gt;&gt; operation on the primary owner, this works out quite well with forEach<br class="gmail_msg">
&gt;&gt; &gt;&gt; to be<br class="gmail_msg">
&gt;&gt; &gt;&gt; done in an efficient way.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; The problem is that this only really works well with non tx and<br class="gmail_msg">
&gt;&gt; &gt;&gt; pessimistic<br class="gmail_msg">
&gt;&gt; &gt;&gt; tx. This obviously leaves out optimistic tx, which at first I was a<br class="gmail_msg">
&gt;&gt; &gt;&gt; little<br class="gmail_msg">
&gt;&gt; &gt;&gt; worried about. But after thinking about it more, this prelocking and<br class="gmail_msg">
&gt;&gt; &gt;&gt; optimistic tx don&#39;t really fit that well together anyways. So I am<br class="gmail_msg">
&gt;&gt; &gt;&gt; thinking<br class="gmail_msg">
&gt;&gt; &gt;&gt; whenever this operation is performed it would throw an exception not<br class="gmail_msg">
&gt;&gt; &gt;&gt; letting<br class="gmail_msg">
&gt;&gt; &gt;&gt; the user use this feature in optimistic transactions.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Another question is what does the API for this look like. I was<br class="gmail_msg">
&gt;&gt; &gt;&gt; debating<br class="gmail_msg">
&gt;&gt; &gt;&gt; between 3 options myself:<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; 1. AdvancedCache.forEachWithLock(BiConsumer&lt;Cache, CacheEntry&lt;K, V&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; consumer)<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; This require the least amount of changes, however the user can&#39;t<br class="gmail_msg">
&gt;&gt; &gt;&gt; customize<br class="gmail_msg">
&gt;&gt; &gt;&gt; certain parameters that CacheStream currently provides (listed below -<br class="gmail_msg">
&gt;&gt; &gt;&gt; big<br class="gmail_msg">
&gt;&gt; &gt;&gt; one being filterKeys).<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; 2. CacheStream.forEachWithLock(BiConsumer&lt;Cache, CacheEntry&lt;K, V&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; consumer)<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; This method would only be allowed to be invoked on the Stream if no<br class="gmail_msg">
&gt;&gt; &gt;&gt; other<br class="gmail_msg">
&gt;&gt; &gt;&gt; intermediate operations were invoked, otherwise an exception would be<br class="gmail_msg">
&gt;&gt; &gt;&gt; thrown. This still gives us access to all of the CacheStream methods<br class="gmail_msg">
&gt;&gt; &gt;&gt; that<br class="gmail_msg">
&gt;&gt; &gt;&gt; aren&#39;t on the Stream interface (ie. sequentialDistribution,<br class="gmail_msg">
&gt;&gt; &gt;&gt; parallelDistribution, parallel, sequential, filterKeys,<br class="gmail_msg">
&gt;&gt; &gt;&gt; filterKeySegments,<br class="gmail_msg">
&gt;&gt; &gt;&gt; distributedBatchSize, disableRehashAware, timeout).<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; 3. LockedStream&lt;CacheEntry&lt;K, V&gt;&gt; AdvancedCache.lockedStream()<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; This requires the most changes, however the API would be the most<br class="gmail_msg">
&gt;&gt; &gt;&gt; explicit.<br class="gmail_msg">
&gt;&gt; &gt;&gt; In this case the LockedStream would only have the methods on it that<br class="gmail_msg">
&gt;&gt; &gt;&gt; are<br class="gmail_msg">
&gt;&gt; &gt;&gt; able to be invoked as noted above and forEach.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; I personally feel that #3 might be the cleanest, but obviously requires<br class="gmail_msg">
&gt;&gt; &gt;&gt; adding more classes. Let me know what you guys think and if you think<br class="gmail_msg">
&gt;&gt; &gt;&gt; the<br class="gmail_msg">
&gt;&gt; &gt;&gt; optimistic exclusion is acceptable.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Thanks,<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; - Will<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt;&gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; &gt;&gt; <a href="mailto:infinispan-dev@lists.jboss.org" class="gmail_msg" target="_blank">infinispan-dev@lists.jboss.org</a><br class="gmail_msg">
&gt;&gt; &gt;&gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br class="gmail_msg">
&gt;&gt; &gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; &gt; <a href="mailto:infinispan-dev@lists.jboss.org" class="gmail_msg" target="_blank">infinispan-dev@lists.jboss.org</a><br class="gmail_msg">
&gt;&gt; &gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; <a href="mailto:infinispan-dev@lists.jboss.org" class="gmail_msg" target="_blank">infinispan-dev@lists.jboss.org</a><br class="gmail_msg">
&gt;&gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; _______________________________________________<br class="gmail_msg">
&gt; infinispan-dev mailing list<br class="gmail_msg">
&gt; <a href="mailto:infinispan-dev@lists.jboss.org" class="gmail_msg" target="_blank">infinispan-dev@lists.jboss.org</a><br class="gmail_msg">
&gt; <a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a><br class="gmail_msg">
<br class="gmail_msg">
_______________________________________________<br class="gmail_msg">
infinispan-dev mailing list<br class="gmail_msg">
<a href="mailto:infinispan-dev@lists.jboss.org" class="gmail_msg" target="_blank">infinispan-dev@lists.jboss.org</a><br class="gmail_msg">
<a href="https://lists.jboss.org/mailman/listinfo/infinispan-dev" rel="noreferrer" class="gmail_msg" target="_blank">https://lists.jboss.org/mailman/listinfo/infinispan-dev</a></blockquote></div></div>