<div dir="ltr"><br><br><div class="gmail_quote"><div dir="ltr">On Wed, Mar 29, 2017 at 4:05 AM Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com">dan.berindei@gmail.com</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Tue, Mar 28, 2017 at 8:54 PM, 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 Tue, Mar 28, 2017 at 12:52 PM Dan Berindei &lt;<a href="mailto:dan.berindei@gmail.com" class="gmail_msg" target="_blank">dan.berindei@gmail.com</a>&gt;<br class="gmail_msg">
&gt; wrote:<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; On Tue, Mar 28, 2017 at 6:44 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; wrote:<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; On Tue, Mar 28, 2017 at 11:24 AM Sanne Grinovero &lt;<a href="mailto:sanne@infinispan.org" class="gmail_msg" target="_blank">sanne@infinispan.org</a>&gt;<br class="gmail_msg">
&gt;&gt; &gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Hi Will,<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; I&#39;m confused about the premise; when you state<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &quot; the Consumer is called while holding the lock for the given key and<br class="gmail_msg">
&gt;&gt; &gt;&gt; subsequently released after the Consumer operation completes.&quot;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; What are the transaction boundaries?<br class="gmail_msg">
&gt;&gt; &gt;&gt; I see two options, please correct me so I understand:<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; A)<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; transaction.begin();<br class="gmail_msg">
&gt;&gt; &gt;&gt; cache.lockedStream().filterKeys(keys).filter(predicate).forEach(<br class="gmail_msg">
&gt;&gt; &gt;&gt; someOperation );<br class="gmail_msg">
&gt;&gt; &gt;&gt; transaction.commit(); &lt;-- release all locks<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; B)<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; cache.lockedStream().filterKeys(keys).filter(predicate).forEach(<br class="gmail_msg">
&gt;&gt; &gt;&gt;     transaction.begin();<br class="gmail_msg">
&gt;&gt; &gt;&gt;     //to stuff on entry<br class="gmail_msg">
&gt;&gt; &gt;&gt;     /transaction.commit(); &lt;-- release this single entry&#39;s lock<br class="gmail_msg">
&gt;&gt; &gt;&gt; );<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; The user code doesn&#39;t really affect this, it is done internally by<br class="gmail_msg">
&gt;&gt; &gt; Infinispan. We would acquire the lock on the user&#39;s behalf in the stream<br class="gmail_msg">
&gt;&gt; &gt; operation then call the user&#39;s accept method. Then after they return we<br class="gmail_msg">
&gt;&gt; &gt; would unlock the lock. The way I have it implemented at the moment in my<br class="gmail_msg">
&gt;&gt; &gt; PoC<br class="gmail_msg">
&gt;&gt; &gt; (which could change) is I don&#39;t even start a transaction. It just locks<br class="gmail_msg">
&gt;&gt; &gt; the<br class="gmail_msg">
&gt;&gt; &gt; key and then if the user were to invoke an operation that requires a<br class="gmail_msg">
&gt;&gt; &gt; transaction it adds the lock owner to their tx context at that point so<br class="gmail_msg">
&gt;&gt; &gt; they<br class="gmail_msg">
&gt;&gt; &gt; have ownership of the key.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; Also to note that a commit or rollback in the Consumer currently doesn&#39;t<br class="gmail_msg">
&gt;&gt; &gt; release the lock on the key. Although this could be discussed to be<br class="gmail_msg">
&gt;&gt; &gt; possibly<br class="gmail_msg">
&gt;&gt; &gt; changed.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; With a transactional cache I was assuming you manage the transaction<br class="gmail_msg">
&gt;&gt; yourself... if the user has to call<br class="gmail_msg">
&gt;&gt; transactionManager.begin()/commit()/rollback() anyway, why not use a<br class="gmail_msg">
&gt;&gt; regular stream?<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; The user would be using an implicit transaction or explicit. Like I said<br class="gmail_msg">
&gt; this is up for discussion. The main reason I am staying away from managing<br class="gmail_msg">
&gt; the transaction is that the user can mess with the transaction as well which<br class="gmail_msg">
&gt; would possibly release the lock. It is much simpler if all I am doing is<br class="gmail_msg">
&gt; managing the lock. And if the user doesn&#39;t require a transaction in<br class="gmail_msg">
&gt; Infinispan we didn&#39;t waste time starting one and releasing one.<br class="gmail_msg">
&gt;<br class="gmail_msg">
<br class="gmail_msg">
Every write to a transactional cache will start an implicit<br class="gmail_msg">
transaction, so I don&#39;t think we really have the option of not<br class="gmail_msg">
starting a transaction.<br class="gmail_msg"></blockquote><div><br></div><div>Yes a write to it will, but the stream stuff doesn&#39;t write to it, it just locks. So if the user doesn&#39;t have to actually write to the cache, they may want to just update a 3rd party system for example.</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">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; I think it&#39;s important to clarify this as I suspect that #A is not<br class="gmail_msg">
&gt;&gt; &gt;&gt; implementable within reasonable guarantees, while in the case of B# I<br class="gmail_msg">
&gt;&gt; &gt;&gt; see no use for optimistic locking *from a user&#39;s perspective*.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; Exactly my thoughts regarding optimistic. I don&#39;t think #A is even<br class="gmail_msg">
&gt;&gt; &gt; feasible<br class="gmail_msg">
&gt;&gt; &gt; given constraints of having a distributed transaction like this.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; Totally agree that #A can&#39;t work with any kind of transaction<br class="gmail_msg">
&gt;&gt; configuration.<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; As to optimistic locking, I would like having &quot;feature parity&quot; between<br class="gmail_msg">
&gt;&gt; pessimistic and optimistic caches as much as possible, but I agree<br class="gmail_msg">
&gt;&gt; locking eagerly and retrying the consumer on WriteSkewException are a<br class="gmail_msg">
&gt;&gt; bit too different to fit under the same API.<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; Yeah I would definitely like to have it as well, but I just can&#39;t see how it<br class="gmail_msg">
&gt; fits in. This is despite the implementation detail that it is quite<br class="gmail_msg">
&gt; difficult to get it working currently :D<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Also: what kind of guarantees do you expect about having the operation<br class="gmail_msg">
&gt;&gt; &gt;&gt; being applied on some entry which is strictly *still* a subset of the<br class="gmail_msg">
&gt;&gt; &gt;&gt; keys as defined by the filter predicates?<br class="gmail_msg">
&gt;&gt; &gt;&gt; I take it you&#39;d want to acquire the locks during the filtering process?<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; That is a good question. I hadn&#39;t thought about the details but what I<br class="gmail_msg">
&gt;&gt; &gt; had<br class="gmail_msg">
&gt;&gt; &gt; implemented was we have to first read the entry, lock the key, reread<br class="gmail_msg">
&gt;&gt; &gt; the<br class="gmail_msg">
&gt;&gt; &gt; entry (in case of concurrent update) and then finally call their<br class="gmail_msg">
&gt;&gt; &gt; Predicate.<br class="gmail_msg">
&gt;&gt; &gt; Another reason the filterKeys is much more efficient :) Note this read,<br class="gmail_msg">
&gt;&gt; &gt; locking and reread is done even without a Predicate supplied. And<br class="gmail_msg">
&gt;&gt; &gt; actually I<br class="gmail_msg">
&gt;&gt; &gt; can also optimize filterKeys to not do the initial read since we already<br class="gmail_msg">
&gt;&gt; &gt; have the key.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; Would this be more efficient than the consumer reading the key with<br class="gmail_msg">
&gt;&gt; FORCE_WRITE_LOCK and deciding what to do based on the value?<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; The problem with this is you have to go remote to lock the key, return the<br class="gmail_msg">
&gt; value then do something for every key (not to mention pulling those keys<br class="gmail_msg">
&gt; using an iterator). Very costly! The main benefit of the stream with lock is<br class="gmail_msg">
&gt; that you are performing everything on the primary owner of the data with the<br class="gmail_msg">
&gt; lock already acquired. The only piece sent remotely is the consumer and some<br class="gmail_msg">
&gt; internal classes, very light weight and you have all the benefits of data<br class="gmail_msg">
&gt; locality.<br class="gmail_msg">
&gt;<br class="gmail_msg">
<br class="gmail_msg">
I meant using cache.withFlags(FORCE_WRITE_LOCK).get(key) in the<br class="gmail_msg">
Consumer itself, and assuming it runs on the primary owner.<br class="gmail_msg"></blockquote><div><br></div><div>Ah yes you could for pessimistic, but not optimistic or nontx :( In this case it would be very similar.</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">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; That would require the move the transaction boundary to the scenario<br class="gmail_msg">
&gt;&gt; &gt;&gt; A# which seems undesirable.<br class="gmail_msg">
&gt;&gt; &gt;&gt; Technically if I were to need something like this I guess I&#39;d expect<br class="gmail_msg">
&gt;&gt; &gt;&gt; to have a user experience akin to B# but have Infinispan essentially<br class="gmail_msg">
&gt;&gt; &gt;&gt; use optimistic locking (and auto-skip) on entries which are mutated<br class="gmail_msg">
&gt;&gt; &gt;&gt; and fall out of the filter predicate during the lock attempt.<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; Essentially I suspect that we&#39;d not want to implement different<br class="gmail_msg">
&gt;&gt; &gt;&gt; versions of this depending on the transaction mode, but figure out the<br class="gmail_msg">
&gt;&gt; &gt;&gt; use case and implement a one and only transaction mode which suites<br class="gmail_msg">
&gt;&gt; &gt;&gt; such use cases. So for example we&#39;d simply not offer a mode which<br class="gmail_msg">
&gt;&gt; &gt;&gt; requires to copy the whole grid into the current TX context.<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt; This was never the intent and in my follow up emails I came to what<br class="gmail_msg">
&gt;&gt; &gt; seems<br class="gmail_msg">
&gt;&gt; &gt; like the same conclusion that basically this can&#39;t be done with the user<br class="gmail_msg">
&gt;&gt; &gt; controlling the transaction and it doesn&#39;t really make sense in an<br class="gmail_msg">
&gt;&gt; &gt; optimistic transaction (since you are already at that node, you are<br class="gmail_msg">
&gt;&gt; &gt; already<br class="gmail_msg">
&gt;&gt; &gt; doing everything pessimistically).<br class="gmail_msg">
&gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; Even local caches can use optimistic locking :)<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt;<br class="gmail_msg">
&gt; Yes I know :) I was just framing it in the notion of remote. If anyone can<br class="gmail_msg">
&gt; think of a nice way of using this with optimistic transactions I would all<br class="gmail_msg">
&gt; be for it. But optimistic transactions just doesn&#39;t make any sense to me<br class="gmail_msg">
&gt; when you are locking a key eagerly for someone to do something with it<br class="gmail_msg">
&gt; (definition of pessimistic transaction).<br class="gmail_msg">
&gt;<br class="gmail_msg">
<br class="gmail_msg">
Maybe I didn&#39;t explain properly...<br class="gmail_msg">
<br class="gmail_msg">
I meant in optimistic caches we wouldn&#39;t acquire the lock at all. The<br class="gmail_msg">
stream would just start an optimistic transaction, run the consumer,<br class="gmail_msg">
and try to commit. If the prepare fails because of a<br class="gmail_msg">
WriteSkewException, start from the beginning.<br class="gmail_msg"></blockquote><div><br></div><div>This assumes the user will be updating the cache, I am not sure we can always assume that (in regards to starting a transaction).</div><div><br></div><div>But this is a good point (I misunderstood earlier), it should be pretty easy to just catch WriteSkewException and retry the given Consumer with the new entry (if it exists still).</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">
&gt;&gt;<br class="gmail_msg">
&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<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; Sanne<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; 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;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; --<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; Galder Zamarreño<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; Infinispan, Red Hat<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; I&#39;m leaning towards option 1.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; Are you thinking about also allowing the consumer to modify the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; entry,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; like JCache&#39;s EntryProcessors? For a consumer that can only modify<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; current entry, we could even &quot;emulate&quot; locking in an optimistic<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; cache<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; by catching the WriteSkewException and running the consumer again.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; I wouldn&#39;t allow this to be mixed with other operations in a<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; stream,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; because then you may have to run filters/mappers/sorting while<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; holding<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; the lock as well.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; ^ Would forEach w/ lock still run for all entries in originator? If<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; so,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; not being able to filter could be a pain. IOW, you&#39;d be forcing all<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; entries<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; to be shipped to a node and user to do its own filtering. Not ideal<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; :\<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; No the primary owner would run the operation per entry. I was<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; thinking<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; we<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; would have 2 levels of filtering in my proposal above.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; We would have the first one which is using filterKeys on the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; CacheStream<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; method. This requires serializing keys sent to each node (only<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; primary<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; owned<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; keys are sent). While it has the cost of serialization it makes up<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; for<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; by<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; having constant time lookups (no iterating memory/stores) for the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; keys<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; as it<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; creates a stream using Cache.get to populate it.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; The second was to support the filter method on the Stream API which<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; would<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; allow for a Predicate so you don&#39;t have to serialize keys. In this<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; case<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; you<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; wouldn&#39;t want to include keys in this Predicate as all keys would be<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; serialized to all nodes and then you still have to iterate and check<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; entire data container/store.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; You could actually do both as well. So if you only want a subset of<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; known<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; keys where their values match a Predicate this can be done too.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; cache.lockedStream().filterKeys(keys).filter(predicate).forEach();<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; Cheers<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; Dan<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; On Tue, Mar 21, 2017 at 5:37 PM, William Burns<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; &lt;<a href="mailto:mudokonman@gmail.com" class="gmail_msg" target="_blank">mudokonman@gmail.com</a>&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; wrote:<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; Some users have expressed the need to have some sort of forEach<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; operation<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; that is performed where the Consumer is called while holding the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; lock<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; for<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; the given key and subsequently released after the Consumer<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; operation<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; completes.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; Due to the nature of how streams work with retries and performing<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; operation on the primary owner, this works out quite well with<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; forEach<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; to be<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; done in an efficient way.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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; &gt;&gt; &gt;&gt; pessimistic<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; tx. This obviously leaves out optimistic tx, which at first I was<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; a<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; little<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; worried about. But after thinking about it more, this prelocking<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; and<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; optimistic tx don&#39;t really fit that well together anyways. So I<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; am<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; thinking<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; whenever this operation is performed it would throw an exception<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; not<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; letting<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; the user use this feature in optimistic transactions.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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; &gt;&gt; &gt;&gt; debating<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; between 3 options myself:<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; 1. AdvancedCache.forEachWithLock(BiConsumer&lt;Cache, CacheEntry&lt;K,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; V&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; consumer)<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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; &gt;&gt; &gt;&gt; customize<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; certain parameters that CacheStream currently provides (listed<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; below<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; -<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; big<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; one being filterKeys).<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; 2. CacheStream.forEachWithLock(BiConsumer&lt;Cache, CacheEntry&lt;K,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; V&gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; consumer)<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; This method would only be allowed to be invoked on the Stream if<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; no<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; other<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; intermediate operations were invoked, otherwise an exception<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; would<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; be<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; thrown. This still gives us access to all of the CacheStream<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; methods<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; that<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; aren&#39;t on the Stream interface (ie. sequentialDistribution,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; parallelDistribution, parallel, sequential, filterKeys,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; filterKeySegments,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; distributedBatchSize, disableRehashAware, timeout).<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; 3. LockedStream&lt;CacheEntry&lt;K, V&gt;&gt; AdvancedCache.lockedStream()<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; This requires the most changes, however the API would be the most<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; explicit.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; In this case the LockedStream would only have the methods on it<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; that<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; are<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; able to be invoked as noted above and forEach.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; I personally feel that #3 might be the cleanest, but obviously<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; requires<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; adding more classes. Let me know what you guys think and if you<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; think<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; the<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; optimistic exclusion is acceptable.<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; Thanks,<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; - Will<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt;&gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; &gt;&gt; &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; &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;&gt; &gt;&gt; &gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; &gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; &gt;&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; &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;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;&gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&gt; &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; &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;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt;<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; _______________________________________________<br class="gmail_msg">
&gt;&gt; &gt;&gt; &gt; infinispan-dev mailing list<br class="gmail_msg">
&gt;&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; &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;&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;<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; 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>