Non-blocking API --- ok... I am trying to get caught up again

113 views
Skip to first unread message

Rick Hightower

unread,
Feb 1, 2013, 10:49:05 PM2/1/13
to jsr...@googlegroups.com
It seems JSR 107 is not going to make it as part of Java EE 7. Any change on this?
Too bad.

A while back, and I have not found the email, we talked about having callback interfaces in addition to the Future versions of APIs (to for example prevent blocking in large batch loops where you want to track the return but your behavior is not going to change other than logging that a key population failed).

I have been checking

https://github.com/jsr107/jsr107spec/blob/master/src/main/java/javax/cache/Cache.java

from time to time, and see that this did not make it in there.

        Future<V> load(K key);
        Future<Map<K, ? extends V>> loadAll(Set<? extends K> keys);

The websockets JSR made up their own callback for a similar area where one might not want blocking.

We could use this from NIO:

http://docs.oracle.com/javase/7/docs/api/java/nio/channels/CompletionHandler.html

The CompletionHandler is similar to a future, but it calls your code when the task is complete instead of you calling it.

        void load(K key, CompletionHandler <V,A> callMeWhenDone);
        void loadAll(Set<? extends K> keys, CompletionHandler <V,A> callMeWhenDoneEachTime);

Callback methods:
void completed(V result, A attachment)
void failed(Throwable exc, A attachment)


Also I can see more use of Futures and CompletionHandler where you would like to do something with the cache (put an item), but do not want to block, but still need to know if something bad happen (e.g. log it), but you can do this on a foreign thread, i.e., you don't have to block.

 Future<V>  putWhenYouCan(K key, V value);

 void put(K key, V value, CompletionHandler <V,A> callMeWhenDone);

The CompletionHandler allows you to have some sort of remediation of failure, but still not block.

We could even remove the Future from the API and create a utility class that converts a Future wrapper into a CompletionHandler. 

Rick Hightower
(415) 968-9037
Profile

Brian Oliver

unread,
Feb 3, 2013, 10:02:00 AM2/3/13
to jsr...@googlegroups.com
Hi Rick,


On Friday, February 1, 2013 10:49:05 PM UTC-5, RickHightower wrote:

It seems JSR 107 is not going to make it as part of Java EE 7. Any change on this?
Too bad.

Not really.  Several important deadlines have passed for the Java EE 7 project.   While we're making great progress, we're not close to being finished.  Furthermore, we can't delay Java EE 7.
 
A while back, and I have not found the email, we talked about having callback interfaces in addition to the Future versions of APIs (to for example prevent blocking in large batch loops where you want to track the return but your behavior is not going to change other than logging that a key population failed).

I have been checking

https://github.com/jsr107/jsr107spec/blob/master/src/main/java/javax/cache/Cache.java

from time to time, and see that this did not make it in there.

Have you checked the Issue Tracker?   I proposed this:

 
As yet I've had no feedback - and haven't had time to implement it (it's a bit lower on the priorities as I want to get other core functionality working - like CacheWriters).

        Future<V> load(K key);
        Future<Map<K, ? extends V>> loadAll(Set<? extends K> keys);

The websockets JSR made up their own callback for a similar area where one might not want blocking.

Yes.  I'm aware of this work (I routinely attend the Java EE 7 architecture reviews).   Similar work has been occurring with JMS 2.0.   I want to make sure we're using the same approach.
 
We could use this from NIO:

http://docs.oracle.com/javase/7/docs/api/java/nio/channels/CompletionHandler.html

The CompletionHandler is similar to a future, but it calls your code when the task is complete instead of you calling it.

        void load(K key, CompletionHandler <V,A> callMeWhenDone);
        void loadAll(Set<? extends K> keys, CompletionHandler <V,A> callMeWhenDoneEachTime);

Callback methods:
void completed(V result, A attachment)
void failed(Throwable exc, A attachment)


Right.  This is what I've basically proposed.   However it's important to note that while it looks good, it isn't Java 8 (lambda) friendly - because there are two methods!   I'm not sure of the solution as yet - but I haven't thought too much about it either.
 
Also I can see more use of Futures and CompletionHandler where you would like to do something with the cache (put an item), but do not want to block, but still need to know if something bad happen (e.g. log it), but you can do this on a foreign thread, i.e., you don't have to block.

 Future<V>  putWhenYouCan(K key, V value);

Ultimately I believe we should do everything possible to avoid the use of Futures.   They are pretty horrible in terms of encouraging developers to write "blocking" or "polling" code.  Instead a "callback" is way better.   Besides, we can always efficiently make a "callback" into a Future.  The opposite is not always the case.
 
 void put(K key, V value, CompletionHandler <V,A> callMeWhenDone);

The CompletionHandler allows you to have some sort of remediation of failure, but still not block

Right ;)
 
We could even remove the Future from the API and create a utility class that converts a Future wrapper into a CompletionHandler. 

Absolutely.   My plan is to remove all Futures from the API.

galderz

unread,
Feb 6, 2013, 9:14:11 AM2/6/13
to jsr...@googlegroups.com

Hi all,

My name is Galder Zamarreño and I work on the Infinispan project (alongside Manik Surtani).

On Saturday, 2 February 2013 04:49:05 UTC+1, RickHightower wrote:
Also I can see more use of Futures and CompletionHandler where you would like to do something with the cache (put an item), but do not want to block, but still need to know if something bad happen (e.g. log it), but you can do this on a foreign thread, i.e., you don't have to block.

 Future<V>  putWhenYouCan(K key, V value);


In Infinispan we have a slightly similar method called:

void putForExternalRead(K key, V value);

The idea of this put is to store data in the cache read from another persistent store efficiently. We use it extensively in the Hibernate second level cache to cache data read from the database. This put fails fast (waits a minimum time to acquire the lock) and silently (exception is not propagated to client) if another thread is trying to store the same data at the same time. 

This performs particularly well when you have N threads reading the same thing from the database and they're trying to put it in the cache. If they were to use a normal put, you could have up to N-1 threads waiting to acquire the lock to update the same thing. With PFER, this wait is minimal, and eventually one of them will store the data in the cache and will be accessible to others.

It has other consequences for distributed caches, but this is not of interest for this list. Detailed javadoc information can be found in

http://docs.jboss.org/infinispan/5.2/apidocs/org/infinispan/Cache.html#putForExternalRead(K, V)

For our next version, we actually wanna change the signature slightly (https://issues.jboss.org/browse/ISPN-1986) and instead have:

boolean putForExternalRead(K key, V value)

I wonder what the rest of the list thought of such operation for inclusion in JSR-107. This operation would be extremely valuable for a potential JSR-107 implementation of Hibernate Second Level Cache.

Cheers,

Brian Oliver

unread,
Feb 8, 2013, 3:38:23 PM2/8/13
to jsr...@googlegroups.com
Hi Galder, 

It's an interesting idea.   I'd certainly like to know more about the semantics.

eg:  If there are N threads reading the same entry using a Cache that is configured for "read-through", do all N threads hit the database, potentially reading the same value, and then only one places the value in the cache (if they are all the same)?

Wouldn't that then reduce the value of having a cache in the first place?  I'm guessing I'm missing something here.  Sorry :(  

What happens if the database changes during the N threads reading?   How is consistency maintained?   Perhaps this style doesn't allow any consistency?  ie: last write wins?

Would it be possible to have a more detailed example?

Many Thanks

-- Brian

--
You received this message because you are subscribed to the Google Groups "jsr107" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jsr107+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Brian Oliver

unread,
Feb 11, 2013, 4:31:38 PM2/11/13
to jsr...@googlegroups.com
Hi Rick (and everyone).

What do you think of the proposed interfaces on: 


I think there are two approaches.   Both are easy to implement for Java 6, 7 etc, but one makes adopting closures and lambda expressions in Java 8 way easier.

Thoughts, feedback most welcome.

Cheers

-- Brian

Bongjae Chang

unread,
Feb 11, 2013, 10:15:20 PM2/11/13
to jsr...@googlegroups.com
Hi Brian,

Introducing CompletionListener interface is looking fine to me for async ops.

About "instead of/in addition to Futures", 
I think that Future APIs are also needed because users could want to execute a synchronous call for being sure that cache loading is completed and continue to process other operations in their thread.

Thanks!

Regards,
Bongjae Chang


--

Brian Oliver

unread,
Feb 12, 2013, 9:03:41 AM2/12/13
to jsr...@googlegroups.com
Hi Bongjae,

Good point.   I've updated the issue with a suggestion - allowing for CompletionFutures, much like that has been suggested for JMS 2.0.

This would make us Future-friendly, CompletionListener-friendly together with Java 6, 7 and 8.

What do you think?

-- Brian

Bongjae Chang

unread,
Feb 16, 2013, 3:31:08 AM2/16/13
to jsr...@googlegroups.com
Hi Brian,

I am also fine for "Future-friendly" and "CompletionListener-friendly" with Java 6, 7 and 8.

Perhaps could you tell me the reference link for CompletionFutures which suggested for JMS 2.0?
(Unfortunately, I haven't followed JMS 2.0 spec for Java EE 7).

Thanks!

Regards,
Bongjae Chang

galderz

unread,
Feb 18, 2013, 11:45:05 AM2/18/13
to jsr...@googlegroups.com
Hi Brian,

Sorry for the delay getting back, I had some time off...


On Friday, 8 February 2013 21:38:23 UTC+1, Brian Oliver wrote:
Hi Galder, 

It's an interesting idea.   I'd certainly like to know more about the semantics.

eg:  If there are N threads reading the same entry using a Cache that is configured for "read-through", do all N threads hit the database, potentially reading the same value, and then only one places the value in the cache (if they are all the same)?

^ Yup.
 
Wouldn't that then reduce the value of having a cache in the first place?  I'm guessing I'm missing something here.  Sorry :(  

^ In Hibernate/2LC experience and relatively lengthy transactions, we've seen burst of concurrent user requests going to the database and trying to store the same data in paralel. 

So, it could happen that you have N threads, all hitting the cache and seeing that the entry is not present and all N of them going to the persistent store, loading the data and trying to store that entry in the cache. If all N threads are doing lengthy transactions, 1 of them will succeed in updating the cache, and the rest of N-1 threads could potentially wait until they can acquire the lock. If the transaction is lengthy, you could be potentially slowing down other threads for no reason, particularly if the thread that went through does not actually update the data stored in the cache.

Having the cache does of course help, once it's been loaded with data from the persistent store, in which case data is resolved from the cache directly and the persistent stored is not queried. 
 
What happens if the database changes during the N threads reading?   How is consistency maintained?   Perhaps this style doesn't allow any consistency?  ie: last write wins?

^ The responsibility here lays with the persistent store, since in these situations (i.e. Hibernate second level cache), they're the data owners and they have the ultimate decision on whether data is valid or not. In case of databases, you'd need some kind of versioning/optimistic locking mechanism to detect that if a transaction comes with stale data in it, it will throw it back.
 
Would it be possible to have a more detailed example?

^ What exactly are you looking for? Code showing this operation in action? (potentially alongside a database to show effects?)

Cheers,
Reply all
Reply to author
Forward
0 new messages