jsr107 / jsr107spec

JSR107 Cache Specification
Apache License 2.0
413 stars 164 forks source link

async API #307

Closed RuedigerMoeller closed 9 years ago

RuedigerMoeller commented 9 years ago

There should be an asynchronous variant of most important operations such as get(), getAndPut(), putIFAbsent(), .. using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a direct connection of throughput and network latency, so an application deployed in the cloud will perform like 100 times worse compared to a deployment running a 10GB lowlat network LAN.

e.g. see https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

gregrluck commented 9 years ago

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller notifications@github.com wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307.

RuedigerMoeller commented 9 years ago

good to know, looking forward to the spec update :)

alexsnaps commented 9 years ago

Hey @gregrluck So there is a plan for a new JSR to be submitted? I don't remember seeing this on the mailing yet, do you think you could update us (all?) on what the plans here are? Obviously nailing the scope of that new JSR before submitting it would be... nice. Not only to us implementers, but to make sure we convey a clear message to the EC. But I guess you know all that way too well already. Anyways, just trying to get a sense of what is coming up. Thanks, Alex

On Mon Feb 09 2015 at 4:57:33 PM Greg Luck notifications@github.com wrote:

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller notifications@github.com wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java < https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java> for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038.

gregrluck commented 9 years ago

Alex

Sure. Happy to. The conversation started with Peter Lawrey, a member of the now withdrawn JSR347 a few months back. We looked at the async API proposed there. This was the main feature he wanted from 347. Brian Oliver and I then discussed it in December when I was there doing an update to the TCK.

The general idea is to add async methods to cache that work with the style of the rest of the API. We can add those without changing any of the method signatures. While it feels like a big jump in usefulness it is a pretty small change in the spec and API. As such it can be done with the rules as a maintenance release to JSR107.

As most implementations are async underneath there is a large performance gain to using an async API which we can unleash for users just by adding this.

There are two main approaches:

  1. get notified when an async operation finishes - see the async put method below. We add a CompletionListener to the parameters
  2. get a way to iterate over results for operations that return a collection - see getAll. We add a new Collector as the return type

Sync put void put(K key, V value);

Async put /**

Sync getAll Map<K, V> getAll(Set<? extends K> keys);

Async getAll

void getAll(Set<? extends K> keys, Collector<? extends Entry<? super K,? super V>> collector);

I should have a complete sketch of this API including the JavaDoc with the nuances of the programming contract in the next few weeks. Happy to work with anyone on the EG on this elaboration in the meantime.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 8:23 am, Alex Snaps notifications@github.com wrote:

Hey @gregrluck So there is a plan for a new JSR to be submitted? I don't remember seeing this on the mailing yet, do you think you could update us (all?) on what the plans here are? Obviously nailing the scope of that new JSR before submitting it would be... nice. Not only to us implementers, but to make sure we convey a clear message to the EC. But I guess you know all that way too well already. Anyways, just trying to get a sense of what is coming up. Thanks, Alex

On Mon Feb 09 2015 at 4:57:33 PM Greg Luck notifications@github.com wrote:

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller notifications@github.com wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java < https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java> for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73603597.

alexsnaps commented 9 years ago

I'm sure I (and probably others) will have further questions and remarks, but one more important question comes to my mind right now: how would one get a handle to an async Cache? Or are these methods new ones directly on the Cache interface? On Mon, Feb 9, 2015 at 6:02 PM Greg Luck notifications@github.com wrote:

Alex

Sure. Happy to. The conversation started with Peter Lawrey, a member of the now withdrawn JSR347 a few months back. We looked at the async API proposed there. This was the main feature he wanted from 347. Brian Oliver and I then discussed it in December when I was there doing an update to the TCK.

The general idea is to add async methods to cache that work with the style of the rest of the API. We can add those without changing any of the method signatures. While it feels like a big jump in usefulness it is a pretty small change in the spec and API. As such it can be done with the rules as a maintenance release to JSR107.

As most implementations are async underneath there is a large performance gain to using an async API which we can unleash for users just by adding this.

There are two main approaches:

  1. get notified when an async operation finishes - see the async put method below. We add a CompletionListener to the parameters
  2. get a way to iterate over results for operations that return a collection - see getAll. We add a new Collector as the return type

Sync put void put(K key, V value);

Async put /**

  • Asynchronously associates the specified value with the specified key in the cache.
  • If the {@link Cache} previously contained a mapping for the key, the old
  • value is replaced by the specified value. (A cache c is said to
  • contain a mapping for a key k if and only if {@link
  • containsKey(Object) c.containsKey(k)} would return true.)

  • On completion, the CompletionListener is notified. The state of the entry
  • in the cache, until the CompletionListener is notified, is undefined.
  • The order of application of repeated calls to this method is monotonic
  • within the scope of the calling thread, and undefined across threads. *
  • @param key key with which the specified value is to be associated
  • @param value value to be associated with the specified key
  • @param completionListener notified on completion *
  • @throws NullPointerException if key is null or if value is null
  • @throws IllegalStateException if the cache is {@link #isClosed()}
  • @throws CacheException if there is a problem doing the put
  • @throws ClassCastException if the implementation is configured to perform
  • runtime-type-checking, and the key or value
  • types are incompatible with those that have been
  • configured for the {@link Cache}
  • @see java.util.Map#put(Object, Object)
  • @see #getAndPut(Object, Object)
  • @see #getAndReplace(Object, Object)
  • @see CacheWriter#write / void put(K key, V value, CompletionListener completionListener);

Sync getAll Map<K, V> getAll(Set<? extends K> keys);

Async getAll

void getAll(Set<? extends K> keys, Collector<? extends Entry<? super K,? super V>> collector);

I should have a complete sketch of this API including the JavaDoc with the nuances of the programming contract in the next few weeks. Happy to work with anyone on the EG on this elaboration in the meantime.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 8:23 am, Alex Snaps notifications@github.com wrote:

Hey @gregrluck So there is a plan for a new JSR to be submitted? I don't remember seeing this on the mailing yet, do you think you could update us (all?) on what the plans here are? Obviously nailing the scope of that new JSR before submitting it would be... nice. Not only to us implementers, but to make sure we convey a clear message to the EC. But I guess you know all that way too well already. Anyways, just trying to get a sense of what is coming up. Thanks, Alex

On Mon Feb 09 2015 at 4:57:33 PM Greg Luck notifications@github.com wrote:

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller < notifications@github.com> wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see

https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java <

https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java

for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307>.

— Reply to this email directly or view it on GitHub <https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038 .

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73603597>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73609987.

gregrluck commented 9 years ago

Hey Alex, hey Greg,

Sad that CompletableFuture is Java 8+ only. I would prefer a more “Java standard” way especially because it easily offers the option to register multiple listeners to work in a more reactive way but this would tie JCache to Java 8 and I don’t actually like that.

Christoph Engelbert Technical Evangelist / Senior Solutions Architect 350 Cambridge Ave Suite #50, Palo Alto, CA 94306 USA (based in Germany) chris@hazelcast.com mailto:chris@hazelcast.com +49 160 9648 2677 @noctarius2k skype: noctarius_

Am 10.02.2015 um 00:01 schrieb Greg Luck gluck@gregluck.com:

Alex

Sure. Happy to. The conversation started with Peter Lawrey, a member of the now withdrawn JSR347 a few months back. We looked at the async API proposed there. This was the main feature he wanted from 347. Brian Oliver and I then discussed it in December when I was there doing an update to the TCK.

The general idea is to add async methods to cache that work with the style of the rest of the API. We can add those without changing any of the method signatures. While it feels like a big jump in usefulness it is a pretty small change in the spec and API. As such it can be done with the rules as a maintenance release to JSR107.

As most implementations are async underneath there is a large performance gain to using an async API which we can unleash for users just by adding this.

There are two main approaches:

  1. get notified when an async operation finishes - see the async put method below. We add a CompletionListener to the parameters
  2. get a way to iterate over results for operations that return a collection - see getAll. We add a new Collector as the return type

Sync put void put(K key, V value);

Async put /**

  • Asynchronously associates the specified value with the specified key in the cache.
  • If the {@link Cache} previously contained a mapping for the key, the old
  • value is replaced by the specified value. (A cache c is said to
  • contain a mapping for a key k if and only if {@link
  • containsKey(Object) c.containsKey(k)} would return true.)

  • On completion, the CompletionListener is notified. The state of the entry
  • in the cache, until the CompletionListener is notified, is undefined.
  • The order of application of repeated calls to this method is monotonic
  • within the scope of the calling thread, and undefined across threads. *
  • @param key key with which the specified value is to be associated
  • @param value value to be associated with the specified key
  • @param completionListener notified on completion *
  • @throws NullPointerException if key is null or if value is null
  • @throws IllegalStateException if the cache is {@link #isClosed()}
  • @throws CacheException if there is a problem doing the put
  • @throws ClassCastException if the implementation is configured to perform
  • runtime-type-checking, and the key or value
  • types are incompatible with those that have been
  • configured for the {@link Cache}
  • @see java.util.Map#put(Object, Object)
  • @see #getAndPut(Object, Object)
  • @see #getAndReplace(Object, Object)
  • @see CacheWriter#write / void put(K key, V value, CompletionListener completionListener);

Sync getAll Map<K, V> getAll(Set<? extends K> keys);

Async getAll

void getAll(Set<? extends K> keys, Collector<? extends Entry<? super K,? super V>> collector);

I should have a complete sketch of this API including the JavaDoc with the nuances of the programming contract in the next few weeks. Happy to work with anyone on the EG on this elaboration in the meantime.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 8:23 am, Alex Snaps <notifications@github.com mailto:notifications@github.com> wrote:

Hey @gregrluck So there is a plan for a new JSR to be submitted? I don't remember seeing this on the mailing yet, do you think you could update us (all?) on what the plans here are? Obviously nailing the scope of that new JSR before submitting it would be... nice. Not only to us implementers, but to make sure we convey a clear message to the EC. But I guess you know all that way too well already. Anyways, just trying to get a sense of what is coming up. Thanks, Alex

On Mon Feb 09 2015 at 4:57:33 PM Greg Luck <notifications@github.com mailto:notifications@github.com> wrote:

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ <http://gregluck.com/ http://gregluck.com/> skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller <notifications@github.com mailto:notifications@github.com> wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java < https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java> for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307 https://github.com/jsr107/jsr107spec/issues/307>.

— Reply to this email directly or view it on GitHub <https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038 https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73603597.

noctarius commented 9 years ago

Oops the last post was mine but I answered to the email, therefore it looks like Greg's answer. :)

gregrluck commented 9 years ago

Alex

Yes, methods added to Cache. The only other thing added would be a new interface, Collector.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 9:43 am, Alex Snaps notifications@github.com wrote:

I'm sure I (and probably others) will have further questions and remarks, but one more important question comes to my mind right now: how would one get a handle to an async Cache? Or are these methods new ones directly on the Cache interface? On Mon, Feb 9, 2015 at 6:02 PM Greg Luck notifications@github.com wrote:

Alex

Sure. Happy to. The conversation started with Peter Lawrey, a member of the now withdrawn JSR347 a few months back. We looked at the async API proposed there. This was the main feature he wanted from 347. Brian Oliver and I then discussed it in December when I was there doing an update to the TCK.

The general idea is to add async methods to cache that work with the style of the rest of the API. We can add those without changing any of the method signatures. While it feels like a big jump in usefulness it is a pretty small change in the spec and API. As such it can be done with the rules as a maintenance release to JSR107.

As most implementations are async underneath there is a large performance gain to using an async API which we can unleash for users just by adding this.

There are two main approaches:

  1. get notified when an async operation finishes - see the async put method below. We add a CompletionListener to the parameters
  2. get a way to iterate over results for operations that return a collection - see getAll. We add a new Collector as the return type

Sync put void put(K key, V value);

Async put /**

  • Asynchronously associates the specified value with the specified key in the cache.
  • If the {@link Cache} previously contained a mapping for the key, the old
  • value is replaced by the specified value. (A cache c is said to
  • contain a mapping for a key k if and only if {@link
  • containsKey(Object) c.containsKey(k)} would return true.)

  • On completion, the CompletionListener is notified. The state of the entry
  • in the cache, until the CompletionListener is notified, is undefined.
  • The order of application of repeated calls to this method is monotonic
  • within the scope of the calling thread, and undefined across threads. *
  • @param key key with which the specified value is to be associated
  • @param value value to be associated with the specified key
  • @param completionListener notified on completion *
  • @throws NullPointerException if key is null or if value is null
  • @throws IllegalStateException if the cache is {@link #isClosed()}
  • @throws CacheException if there is a problem doing the put
  • @throws ClassCastException if the implementation is configured to perform
  • runtime-type-checking, and the key or value
  • types are incompatible with those that have been
  • configured for the {@link Cache}
  • @see java.util.Map#put(Object, Object)
  • @see #getAndPut(Object, Object)
  • @see #getAndReplace(Object, Object)
  • @see CacheWriter#write / void put(K key, V value, CompletionListener completionListener);

Sync getAll Map<K, V> getAll(Set<? extends K> keys);

Async getAll

void getAll(Set<? extends K> keys, Collector<? extends Entry<? super K,? super V>> collector);

I should have a complete sketch of this API including the JavaDoc with the nuances of the programming contract in the next few weeks. Happy to work with anyone on the EG on this elaboration in the meantime.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 8:23 am, Alex Snaps notifications@github.com wrote:

Hey @gregrluck So there is a plan for a new JSR to be submitted? I don't remember seeing this on the mailing yet, do you think you could update us (all?) on what the plans here are? Obviously nailing the scope of that new JSR before submitting it would be... nice. Not only to us implementers, but to make sure we convey a clear message to the EC. But I guess you know all that way too well already. Anyways, just trying to get a sense of what is coming up. Thanks, Alex

On Mon Feb 09 2015 at 4:57:33 PM Greg Luck notifications@github.com wrote:

Actually we are planning to add this. I have a draft done which I should get out to the list in the next few weeks.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 10 Feb 2015, at 6:05 am, RuedigerMoeller < notifications@github.com> wrote:

There should be at least asynchronous variants of most important operations such as get(), getAndPut(), putIFAbsent() using a functional style callback or a Future alike return object. Considering most implementations will be implemented in a distributed fashion, an enforced synchronous API creates a dirct connection of throughput and network latency, so an application deployed in a 10GB lowlat network LAN will perform like 100 times worse e.g. when ran on a cloud platform.

e.g. see

https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java <

https://github.com/RuedigerMoeller/advcalendar2014/blob/master/src/main/java/keyvalue/KVServer.java

for an example of an completely async kv-store example. Throughput of this example is completely independent of network latency.

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307>.

— Reply to this email directly or view it on GitHub <https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73599038 .

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73603597>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73609987.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73615724.

alexsnaps commented 9 years ago

This sounds like a binary incompatible approach, certainly for implementors... Now a jcache 1.0 implementation would be incompatible with jcache 1.0.1. What are people's thought on that? My understanding certainly was that it couldn't happen as part of a MR. One example that comes to my mind is JTA, but iirc that didn't break binary compatibility (despite the new interface introduced). Did such incompatibilities ever happened under a MR?

noctarius commented 9 years ago

Well under Java 8 you could use default methods to evolve the interface but this is probably not what we want, tie JCache 1.00001 (or whatever version it will be ;-)) to Java 8? Otherwise, to not break binary compatibility this would require a Cache2 interface.

PS: Yes we also have people asking about JTA.

alexsnaps commented 9 years ago

Default methods wouldn't be of any other use than throw new UnsupportedOperationException() though. Arguably this would be better than what's about to happen. But 107 isn't Java8 only anyways... But, yes, some AsyncCache interface maybe... that you could .unwrap(Class<T>) to? That would not break binary compatibility... But I'm not even arguing for that here. This seems like such a big "improvement" over the existing, that I think it should NOT happen within a MR imho. Even more to the point, this very discussion: we're just trying to game the binary compatibility issue... We should keep users in mind here. JSRs should make all of this simpler for them... but this all feels like we're about to put all the burden on the user.

alexsnaps commented 9 years ago

btw, when I mentioned JTA, I meant the JSR's MR (1.0.0 -> 1.0.1)... I wouldn't add TX to a MR neither obviously!

RuedigerMoeller commented 9 years ago

Its easy to use CompletionListener callback-alike style in the API (would like to see it for "get" also) and provide a Java 8 only uility Cache wrapper transforming e.g. "putAndGet( key, completionListener )" to "[Completable]Future putAndGet( key )". Futures are just a more convenient form of a callback and can be added on top easily.

RuedigerMoeller commented 9 years ago

Would like to see a draft version as the synchronous API is not really of use throughput wise.

RuedigerMoeller commented 9 years ago

Regarding evolving: Just add AsyncCache interface, apps may instanceof or use the "featureSupported " mechanism. I'd encourage a quick update as the synchronous version puts such a heavy penalty on performance (depending on network latency and implementation quality slow down is > factor 10), its really not usable for me currently. Again: a draft would be great.

gregrluck commented 9 years ago

JCP 2.7 says in 5.1: "Changes introduced in Maintenance Releases – for example, modifications to existing APIs or the addition of new APIs - must not break binary compatibility as defined by the Java Language Specification. Changes that would break binary compatibility should therefore be deferred to a new JSR."

If a use is using JCache 1.0 his code will continue to work with a JCache 1.1 interface without requiring a recompile. So it is binary compatible.

As an implementer of JCache, you would be required to change your implementation to adopt JCache 1.1. But that will be true whether we add these methods or not.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 2:10 am, Alex Snaps notifications@github.com wrote:

This sounds like a binary incompatible approach, certainly for implementors... Now a jcache 1.0 implementation would be incompatible with a 1.0.1. What are people's thought on that? My understanding certainly was that it couldn't happen as part of a MR. One example that comes to my mind is JTA, but iirc that didn't break binary compatibility (despite the new interface introduced). Did such incompatibilities ever happened under a MR?

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73727211.

alexsnaps commented 9 years ago

Greg, As per 2.9 (as this is what 107 is using): "Changes appropriate for a Maintenance Release include bug-fixes, clarifications of the Specification, changes to the implementation of existing APIs, and implementation-specific enhancements." It seems fairly obvious that new features aren't part of this, and so did Heather's reply confirm as well... Do we really need to discuss this further? How's the PMO answer not clear? I don't see why anyone would want to introduce such fragmentation in a JSR... Why can't just a new JSR be filed? I'm really confused by the thought process here... Alex

On Tue Feb 10 2015 at 7:52:45 PM Greg Luck notifications@github.com wrote:

JCP 2.7 says in 5.1: "Changes introduced in Maintenance Releases – for example, modifications to existing APIs or the addition of new APIs - must not break binary compatibility as defined by the Java Language Specification. Changes that would break binary compatibility should therefore be deferred to a new JSR."

If a use is using JCache 1.0 his code will continue to work with a JCache 1.1 interface without requiring a recompile. So it is binary compatible.

As an implementer of JCache, you would be required to change your implementation to adopt JCache 1.1. But that will be true whether we add these methods or not.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 2:10 am, Alex Snaps notifications@github.com wrote:

This sounds like a binary incompatible approach, certainly for implementors... Now a jcache 1.0 implementation would be incompatible with a 1.0.1. What are people's thought on that? My understanding certainly was that it couldn't happen as part of a MR. One example that comes to my mind is JTA, but iirc that didn't break binary compatibility (despite the new interface introduced). Did such incompatibilities ever happened under a MR?

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73727211>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73816562.

gregrluck commented 9 years ago

The thought process is trying to minimise the work involved in a new JSR.

On 11 Feb 2015, at 11:08 am, Alex Snaps notifications@github.com wrote:

Greg, As per 2.9 (as this is what 107 is using): "Changes appropriate for a Maintenance Release include bug-fixes, clarifications of the Specification, changes to the implementation of existing APIs, and implementation-specific enhancements." It seems fairly obvious that new features aren't part of this, and so did Heather's reply confirm as well... Do we really need to discuss this further? How's the PMO answer not clear? I don't see why anyone would want to introduce such fragmentation in a JSR... Why can't just a new JSR be filed? I'm really confused by the thought process here... Alex

On Tue Feb 10 2015 at 7:52:45 PM Greg Luck notifications@github.com wrote:

JCP 2.7 says in 5.1: "Changes introduced in Maintenance Releases – for example, modifications to existing APIs or the addition of new APIs - must not break binary compatibility as defined by the Java Language Specification. Changes that would break binary compatibility should therefore be deferred to a new JSR."

If a use is using JCache 1.0 his code will continue to work with a JCache 1.1 interface without requiring a recompile. So it is binary compatible.

As an implementer of JCache, you would be required to change your implementation to adopt JCache 1.1. But that will be true whether we add these methods or not.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 2:10 am, Alex Snaps notifications@github.com wrote:

This sounds like a binary incompatible approach, certainly for implementors... Now a jcache 1.0 implementation would be incompatible with a 1.0.1. What are people's thought on that? My understanding certainly was that it couldn't happen as part of a MR. One example that comes to my mind is JTA, but iirc that didn't break binary compatibility (despite the new interface introduced). Did such incompatibilities ever happened under a MR?

— Reply to this email directly or view it on GitHub < https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73727211>.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73816562.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73818148.

alexsnaps commented 9 years ago

In this context, changes like these wouldn't be beneficial to the users, the implementors and eventually would hurt the JSR's adoption as a whole. Fragmentation wouldn't benefit anyone... Again, I'm very unclear why the PMO's answer (here & here ) on this isn't convincing enough for you? If this MR goes to a vote, that eventually happens to be turned down, I don't think that'd be less work really... So I'll let you both, @gregrluck @brianoliver, sort this out with the PMO and get back to the EG. Does that sound fair? Besides, I think that some bake time for the spec as it stands now would actually help nailing the content of v2 release better, don't you think (e.g. CacheLoader & CacheWriter contracts)? Or do you guys plan on introducing new features like these with MR overtime? I do seem to remember the plan exposed at J1 was actually to have a v2 in 2015/2016, no?

gregrluck commented 9 years ago

Alex

I have clarified this point with Patrick Curran. We are using version 2.9 of the Process Document. The EC is responsible for voting on whether to accept these changes.

From JCP 2.9, Changes introduced in Maintenance Releases – for example, modifications to existing APIs or the addition of new APIs - must not break binary compatibility as defined by the Java Language Specification. Changes that would break binary compatibility should therefore be deferred to a new JSR.

So the clause explicitly contemplates additions. The practice of the EC in its voting has been to generally allow this to go in. So, in summary I think we can propose this. Now the vote on the maintenance release contents gets done ahead of us actually delivering the work, so it is a small effort to see if the EC will allow the 1.1 maintenance release.

Back to your point on fragmentation. Why would there be fragmentation? There are only 4 implementations which are all being actively maintained. I am pretty sure that everyone will implement the async methods if they are well-designed. I am convinced of their performance advantages. Are you saying that Terracotta would not implement them even though you are async underneath anyway?

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 12:14 pm, Alex Snaps notifications@github.com wrote:

In this context, changes like these wouldn't be beneficial to the users, the implementors and eventually would hurt the JSR's adoption as a whole. Fragmentation wouldn't benefit anyone... Again, I'm very unclear why the PMO's answer on this isn't convincing enough for you? If this MR goes to a vote, that eventually happens to be turned down, I don't think that'd be less work really... So I'll let you both, @gregrluck https://github.com/gregrluck @brianoliver https://github.com/brianoliver, sort this out with the PMO and get back to the EG. Does that sound fair? Besides, I think that some bake time for the spec as it stands now would actually help nailing the content of v2 release better, don't you think (e.g. CacheLoader & CacheWriter contracts)? Or do you guys plan on introducing new features like these with MR overtime? I do seem to remember the plan exposed at J1 was actually to have a v2 in 2015/2016, no?

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73823985.

cruftex commented 9 years ago

Adding methods to an interface always breaks binary compatibility.

The Cache interface is a public interface. There may be more implementors of that interface, not only the Cache implementations. For example there can be tools and applications that implement proxies to trace caching activity.

I would propose:

interface AsyncFunctions { ... }

and

interface AdvancedCache implements Cache, AsyncFunctions { }

noctarius commented 9 years ago

That is almost what already came up with interface AsyncCache extends Cache :)

cruftex commented 9 years ago

Yep, quick walkrthrough of alternatives:

add methods to exisiting Cache interface -> breaking change

interface AsyncCache extends Cache Pro: You can overwrite some methods in the base interface and narrow semantics of existing methods for the async use case.

interface AsyncCache Pro: Exposes only async functions and enforces the use Con: Basic functionality (e.g. close()) may need to be replicated, so the interface is completely usable

interface AsyncFuntions interface AdvancedCache implements Cache, AsyncFunctions {} Con: Interface AsyncFunctions not usable alone Pro: Optional functions clearly separated in interface

When I look at it now, having a "AsyncCache" interface which does not include the non-async methods seems to me most appealing right now. It guides the developer and the code is easier to review, since one knows there could be no "false uses" of that interface.

keilw commented 9 years ago

AsyncCache, but still no transaction support? Seems that could be more than a MR, but to be a worthy addition to Java EE 8 (unless we'd prune JTA and transactions from it or make them optional;-) it would be hard without.

alexsnaps commented 9 years ago

@keilw Agreed, there is more that should/could be evaluated indeed. An MR seems not appropriate for this. @gregrluck Right, additions or changes to the API, in the context of the sentence before that. But I don't want to argue this further. I do think the language is ambiguous and sought clarification from the PMO, from which we got different feedback it seems. Obviously this will got to vote, and we may be my concerns are not well grounded. But I really think this will lead to fragmentation. Whether or not all current implementations do followup with these non-neglectable additions is irrelevant (and, no, I'm not saying Terracotta wouldn't follow with the specs' evolutions, just to clear that up). When the API comes bundled with "something" (container of some kind or whatever), all the confusion is now on the user. More so, I fear this could slow adoption down too... Would have it been better it all went in 1.0? I don't think so... I'd argue again that giving the spec some bake time; address the known issues in the spec (e.g. the whole integration w/ CacheLoader & CacheWriter - see issue #303), the actual concrete classes in the spec (e.g. the MutableConfiguration 's no arg constructor & generics - see #301); and finally I like to hope for further feedback from implementors and users...

Can you point to other JSRs that have done these feature additions in MR? Looks like my memory fails me...

On the async feature itself, it's merely one solution to a problem, and such there are others. But no discussion around any of this has happened within the (supposedly disbanded) EG as far as I know... That being said, if the feature is worth that much to people, I'd hate to see it being driven in its API by the "we can't introduce it without breaking backwards compatibility in a MR"-argument.

RuedigerMoeller commented 9 years ago

@alexsnaps I am smelling politics here, trying to avoid being rude ..

1) Your keep repeating it introduces binary incompatibility. That's wrong (see my AsyncCache proposal above) 2) Its not a new feature, its just another way invoking existing features. 3) Citation:"More so, I fear this could slow adoption down too.". Its vice versa: who will adopt a pure synchronous API to access a remote cache ? For every dev/architect having some experience with distributed systems, there is a big red "No" sign on that. Just checkout comments on twitter by e.g. Marting Thompson and Peter Lawrey.

4) Citation: "On the async feature itself, it's merely one solution to a problem" Are you serious ? Just some simple computation:

A typical RTT in an enterprise network is easily >400 micros (some network hops, proxy), for the Cloud, its usually in the 1-10 millisecond range. A typical duration of a cache lookup is 1-10 microseconds (if not => go work on it). So a remote lookup overall will take worst case 410 microseconds (that's 400 micros waiting for network, 10 micros for the actual operation). So assuming 10 microsecond lookup duration, an async lookup will yield 100000 lookups per second form a single client, a synchronous lookup will have only ~ 2500 lookups per second. If you choose to deploy your cache to the cloud, sync performance is likely to drop to <100 lookups per second (>10ms RTT).

I think one does not have to be a computer science genious to understand this is a fundamental issue.

The only "advantage" of a pure synchronous API is: An underperforming cache implementation is hidden by network latency. I really hope (for your best) this is not the case.

Going the buerocratic route (=new JSR) will usually take > 1 year of time. The market will move using proprietary API or keep posting "Node.js is faster than Java" (its not, but they strictly follow the async route). Its not 2005 anymore, stuff like this really hurts the Java platform as a whole.

regards, Rüdiger Möller Solution Architect Deutsche Börse AG.

PS: screenshot taken :-)

alexsnaps commented 9 years ago

@RuedigerMoeller Actually not politics, but trying to make a schedule, yes... But I certainly find it surprising this feature comes out of the blue without ever involving the EG... I wear two hats here: Implementor & EC member (I'm Software AG's alternate there). And funnily enough, I really care about this JSR succeeding!

  1. It does break compatibility with the implementations, I understand adding these methods won't break user code. But effectively you will need to know the exact (dot|minor) version to use.
  2. It is a new feature, it'll require quite some spec'ing I think actually... e.g. what will it mean in terms of threads in a EE environment? Or do we simply ignore this for now?
  3. I'm not saying the feature would slow down adoption, I'm saying the fragmented implementations would
  4. Yes, I'm serious... I actually know the problem quite well as it turns out (I've been working on such systems for over 10 years now, the last 6 on the Terracotta platform). What I'm saying is that there are other ways to address that latency "problem"... It could really well be an async API is the best way in this context, but I haven't seen anything else being considered. And it's actually funny you mention node.js, as the one big drawback, is exactly callback hell... As a couple have noted, not being Java8 is unfortunate (with regard to that very feature though, don't get me wrong; I actually think it's nice jcache support earlier releases!)

I hope this clarifies my view a bit. That being said I certainly called for your point 4 there! I really wanted to avoid opening that can of worms until the actual timeline is settled (MR vs. new JSR)... Now I understand we'd like to get it all now... I even mean get it all by yesterday! But these are specifications we're talking about, not any random project... We'll have to live with these for a long time. And, yes, I want to Java platform to still be relevant in 5 years time!

PS: Not sure what you meant with the screenshot?

gregrluck commented 9 years ago

Jens

Binary Compatibility as it relates to Java is defined in Chapter 13 of the JLS. I am using https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf.

See section 13.4.12:

13.4.12 Method and Constructor Declarations Adding a method or constructor declaration to a class will not break compatibility with any pre-existing binaries, even in the case where a type could no longer be recompiled because an invocation previously referenced a method or constructor of a superclass with an incompatible type

Also see 13.2

The Java programming language is designed to prevent additions to contracts and accidental name collisions from breaking binary compatibility. Specifically, addition of more methods overloading a particular method name does not break compatibility with pre-existing binaries. The method signature that the pre-existing binary will use for method lookup is chosen by the overload resolution algorithm at compile time (§15.12.2).

You are right that a sub-interface of Cache would be broken. However that is not what is meant by Binary Compatibilty in Chapter 13.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 6:06 pm, Jens Wilke notifications@github.com wrote:

Adding methods to an interface always breaks binary compatibility.

The Cache interface is a public interface. There may be more implementors of that interface, not only the Cache implementations. For example there can be tools and applications that implement proxies to trace caching activity.

I would propose:

interface AsyncFunctions { ... }

and

interface AdvancedCache implements Cache, AsyncFunctions { }

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73845455.

gregrluck commented 9 years ago

Transaction Support is a ton of work even though we have written the spec and the API. This is something large which would have to be done in a new JSR.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 11 Feb 2015, at 7:27 pm, Werner Keil notifications@github.com wrote:

AsyncCache, but still no transaction support?;-)

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73853397.

gregrluck commented 9 years ago

Guys

Here is the internal testing we did on Hazelcast to show the benefits of async. What got me started on this was our users requesting async methods. So we added them to ICache, the Hazelcast interface which extends javax.cache.Cache.

My thought here is that everyone is going to end up with a very commonly used async API for the basic operations. This will defeat the purpose of the spec covering the very common cases.

See perf results below. Note: Hazelcast is now faster than this, but the ratios should be the same.

Peter asked me to run a test demonstrating batching effect when async operations are executed on ICache. I presume you will use the results to reason why it's a good idea to have async JCache API.

The scenario is very simple: 4 members, each on a dedicated machine (=our lab cluster)

Each member has a single thread calling ICache::asyncPut in a loop. This call is obviously non-blocking and returns a future. Each N operations the calling thread is waiting for futures to complete. Therefore when N is equal to 1 then it's effectively the same as sync API. When N > 1 then batching effect kicks in, pipelines are better utilized and overall throughput goes up drastically. Let the result talks:

batchSize: 1 Throughput: 13,328.29 ops/s

batchSize: 10 Throughput: 86,958.38 ops/s

batchSize: 100 Throughput: 298,961.52 ops/s

batchSize: 1000 Throughput: 465,161.58 ops/s

I assume our network is very close to be saturated with BatchSize = 1000.

Any question - just give me a shout!

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 12 Feb 2015, at 9:35 am, Alex Snaps notifications@github.com wrote:

@RuedigerMoeller https://github.com/RuedigerMoeller Actually not politics, but trying to make a schedule, yes... But I certainly find it surprising this feature comes out of the blue without ever involving the EG... I wear two hats here: Implementor & EC member (I'm Software AG's alternate there). And funnily enough, I really care about this JSR succeeding!

It does break compatibility with the implementations, I understand adding these methods won't break user code. But effectively you will need to know the exact (dot|minor) version to use. It is a new feature, it'll require quite some spec'ing I think actually... e.g. what will it mean in terms of threads in a EE environment? Or do we simply ignore this for now? I'm not saying the feature would slow down adoption, I'm saying the fragmented implementations would Yes, I'm serious... I actually know the problem quite well as it turns out (I've been working on such systems for over 10 years now, the last 6 on the Terracotta platform). What I'm saying is that there are other ways to address that latency "problem"... It could really well be an async API is the best way in this context, but I haven't seen anything else being considered. And it's actually funny you mention node.js, as the one big drawback, is exactly callback hell... As a couple have noted, not being Java8 is unfortunate (with regard to that very feature though, don't get me wrong; I actually think it's nice jcache support earlier releases!) I hope this clarifies my view a bit. That being said I certainly called for your point 4 there! I really wanted to avoid opening that can of worms until the actual timeline is settled (MR vs. new JSR)... Now I understand we'd like to get it all now... I even mean get it all by yesterday! But these are specifications we're talking about, not any random project... We'll have to live with these for a long time. And, yes, I want to Java platform to still be relevant in 5 years time!

PS: Not sure what you meant with the screenshot?

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-73988659.

alexsnaps commented 9 years ago

@gregrluck 4 members means? Data sharded across these 4 nodes? Or is there some replication? The reason I ask, is effectively what I was telling @RuedigerMoeller, such an async API effectively is a fire & ... get back to me when done. But when is it really done? Or wouldn't the spec address that? Also, is there a "happens-before" relationship mandated between these async ops? (i.e. when the last future returns, all other previously "enqueued ops" are supposed to be done too? So that the "client" needs to coordinates multiple stripes? I may understand it wrong, but the N'th Future.get() above seems to imply there is)

The spec until now expected "strong consistency" (i.e. per JMM). But we're opening a much wider range of options here... I said I didn't want to open this can of worms, but looks like it's open now anyways... As you know very well, given the architecture behind TC, we offer a much wider range of guarantees (so do others I'm sure too). Introducing async, is leaking the distributed aspect into the spec. I don't think this is neither good or bad, but it makes it all much more... complex. Especially given the different topologies the spec tries to support. From the usecase above, I guess we're mainly targeting warm up scenarios? @RuedigerMoeller other usecases you care about?

gregrluck commented 9 years ago

Alex

You are now moving on to the programming contract - which is good.

I finished the draft API changes. Please see GitHub.

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

I have a few todos but should get to those tomorrow.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 12 Feb 2015, at 12:31 pm, Alex Snaps notifications@github.com wrote:

@gregrluck https://github.com/gregrluck 4 members means? Data sharded across these 4 nodes? The reason I ask, is effectively what I was telling @RuedigerMoeller https://github.com/RuedigerMoeller, such an async API effectively is a fire & ... get back to me when done. But when is it really done? Or wouldn't the spec address that? Also, is there a "happens-before" relationship mandated between these async ops? (i.e. when the last future returns, all other previously registered ones are done too? So that the "client" needs to coordinates multiple stripes?)

The spec until now expected "strong consistency" (i.e. per JMM). But we're opening a much wider range of options here... I said I didn't want to open this can of worms, but looks like it's open now anyways... As you know very well, given the architecture behind TC, we offer a much wider range of guarantees (so do others I'm sure too). Introducing async, is leaking the distributed aspect into the spec. I don't think this is neither good or bad, but it makes it all much more... complex. Especially given the different topologies the spec tries to support. From the usecase above, I guess we're mainly targeting warm up scenarios?

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-74007228.

cruftex commented 9 years ago

@RuedigerMoeller

I totally agree that an async API is missing and there should be a standard adressing this.

Its not a new feature, its just another way invoking existing features.

For async operations the cache must have a suitable internal architecture and use thread pools. IMHO it is a disruptive feature.

noctarius commented 9 years ago

@gregrluck The problem I see with extending the current interface is not that it breaks binary compatibility since, as you stated, for already compiled classes it is no deal if methods are added afterwards since those new methods would never be called anyways but that people wrapping the cache for some reason would have to change their source to recompile. One may argue that if you update to a new version 1.1 or whatever it will be might go into with slightly code changes (even to semantic versioning) but I'm not sure we should go this way. My personal favor would be an AsnycCache interface extending Cache and therefore give the user the choice to take either one or the other but this is just my personal humble 2 cents :)

cruftex commented 9 years ago

@gregrluck

Just looked on the proposal. (Sidenote: It would be nice to see alternative approaches also.) E.g.:

void put(K key, V value, CompletionListener completionListener);

Questions: Is it legal for the application to leave completionListener empty? Is it legal for the cache to execute this in the callers thread? The way it is introduced now, does mean it is not an optional feature and every implementation must support the new methods, correct?

gregrluck commented 9 years ago

Chris

The spec only came out in March. And the implementations just came out. I think it we get this done quickly it will cause minimal disruption, particularly if we signal to people, e..g blog that this change is coming.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 12 Feb 2015, at 5:13 pm, noctarius aka Christoph Engelbert notifications@github.com wrote:

@gregrluck https://github.com/gregrluck The problem I see with extending the current interface is not that it breaks binary compatibility since, as you stated, for already compiled classes it is no deal if methods are added afterwards since those new methods would never be called anyways but that people wrapping the cache for some reason would have to change their source to recompile. One may argue that if you update to a new version 1.1 or whatever it will be might go into with slightly code changes (even to semantic versioning) but I'm not sure we should go this way. My personal favor would be an AsnycCache interface extending Cache and therefore give the user the choice to take either one or the other but this is just my personal humble 2 cents :)

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-74027524.

noctarius commented 9 years ago

Yeah ok, valid point :)

cruftex commented 9 years ago

There is a tiny bug in the CompletionListenerFuture. It must be notifyAll() and not only notify(). There can be more then one threads waiting on the completion.

cruftex commented 9 years ago

Another thing on the approach of CompletionListenerFuture:

The JCache API now ships with a concrete implmentation of the future. This means every provider is bound to this implementaton. I think that will cause some trouble...

cruftex commented 9 years ago

A remark about Completion.onException()

I did implement some variants of exception handling for bulk operations in the past. Finally I came to the conclusion that the application never can do something useful with an exception on a bulk operation and that it is the best to defer any exception until the value for an entry is explicidly accessed.

OTOH it is always important to have a channel to communicate and propagate exceptions. If this is needed, an application may stop its operation and further propagate the problem (to the user).

My concerns would be, that if one cache implemenation does eagerly communicate exceptions, the typical code would be that the application is doing the same for onComplete and onException.

Here is a try:

onComplete() Notifies the application that the operation completed successfully. For a load operation there are no guarantees at all, so the cache implementation should call onComplete() even if the load was completed partially or an error of temporary nature occured.

onException() Notifies the application that an exception occured, that needs to be propagated. Applications never should ignore this exception.

cruftex commented 9 years ago

An async variant of CacheLoader and CacheWriter seems to be missing.

tristantarrant commented 9 years ago

I believe that the following signature:

void put(K key, V value, CompletionListener completionListener);

does not encourage "fluency", so I'd prefer

CompletionListener put(K key, V value, CompletionListener completionListener);

gregrluck commented 9 years ago

Why is fluency important here?

In Configuration fluency is important. if chaining it is important. Buti don’t see how we would every follow one operation with another so I do not see this as a good idea.

Regards

Greg Luck

web: http://gregluck.com http://gregluck.com/ skype: gregrluck yahoo: gregrluck mobile: +61 408 061 622

On 24 Feb 2015, at 2:32 pm, Tristan Tarrant notifications@github.com wrote:

I believe that the following signature:

void put(K key, V value, CompletionListener completionListener);

does not encourage "fluency", so I'd prefer

CompletionListener put(K key, V value, CompletionListener completionListener);

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-75756328.

tristantarrant commented 9 years ago

Because the CompletableFuture (and the Javascript promise/deferred API) are meant to be used in a fluent manner. Useless example:

put("key", "value", cf) .exceptionally(e -> { System.err.println(e.getMessage()); return false; }) .thenAcceptAsync(b -> { System.out.printf("Got %b\n", b); });

brianoliver commented 9 years ago

A few things to remember.

  1. The JCache Specification is targeted at Java 6. (even though we asked for Java 8, the community voted “no”)
  2. CompleteableFuture was introduced in Java 8. (so we can’t use it and we certainly shouldn’t copy it into JCache)
  3. Just because one API provides “fluent manners”, doesn’t mean JCache should or must.

As Greg alludes, there’s really no place in the JCache specification where the community has decided that JCache “must be fluent”. That is a style left for implementations / vendors to choose for configuration.

Ultimately I think the major problem with use of CompletableFuture is that it’s designed to control asynchronous execution of background tasks. It’s not designed as a clean mechanism for collecting the results of asynchronous processing. They sound the same but there’s a very significant difference.

eg: you can call .cancel(); on a CompletableFuture!

Assuming the put method returned a CompletableFuture, what exactly is the semantics of the following?

asyncCache.put(“key”, “value”).cancel();

This would compile but the semantics are clearly undefined. How does one even start to test this?

My biggest concern with the discussions I’m seeing thus far are the seemingly important rush to define some type of asynchronous behavior / API for JCache, using what ever the favorite “flavor of the month programming style”, with almost complete disregard for making an attempt to clearly define the semantics of such an API.

As a community we must make a concerted effort to clearly define and specify, even in Java Doc, the semantics of these proposals, especially the interaction between such calls (as we attempted to do so in the existing specification). Without doing so it’s impossible for “providers” to implement the specification, the specification leads to develop “tests” to ensure “implementations” are correct and lastly, that application developers (in the community) can rationalize about the semantics of the API when used in their applications. It’s very easy to develop an API in isolation. It’s significantly more challenging to solve for each of these audiences and their fundamental requirements.

Here’s a very trivial example, that raises a lot of challenging questions.

asyncCache.put(“key”, “value1”);
asyncCache.put(“key”, “value2”);
asyncCache.put(“key”, “value3”);
asyncCache.put(“key”, “value4”);

Future future = asyncCache.get(“key”);

i). What is the result of a call to future.get();

ii). Could an implementation coalesce these updates against the same key into a single update?

iii). Would CacheListeners registered against the Cache “see” all of the updates?

iv). In what time-frame would CacheListeners see the updates?

v). As they are asynchronous, can the updates occur in any order? Is there any implied ordering of updates based on a key? How is ordering defined? It is based on a Thread, ThreadGroup, ClassLoader, URI, Cache, CacheManager?

vi). How are synchronous CacheWriters effected? If a Cache has a synchronous CacheWriter configured, does it become asynchronous? Can it then perform batching? If one update/wrtie fails, can it be assumed all writes will then fail? How is failure communicated?

I can thing of any number of “reasonable” answers to these questions that I’m sure there will be at least one individual/organization/vendor will strongly disagree with.

Bottom line: None of this is trivial and as such I expect it will take a long time to resolve / document these things. It’s awesome the community is starting the discussion but I really think we should start by answering some of the simplest things first, not worrying about whether it’s fluent or not.

Given how much work is in this I’m certain this can’t / won’t appear as part of a “maintenance release”. It really is a tremendous change, not only to the API, but also to the SPEC document and TCK.

— Brian

On Feb 24, 2015, at 3:04 PM, Tristan Tarrant notifications@github.com wrote:

Because the CompletableFuture (and the Javascipt promise/deferred API) are meant to be used in a fluent manner: put("key", "value", cf) .exceptionally(e -> { System.err.println(e.getMessage()); return false; }) .thenAcceptAsync(b -> { System.out.printf("Got %b\n", b); });

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-75834453.

chrisdennis commented 9 years ago

+1

It is exactly this kind of complexity that @alexsnaps has hinted at in previous emails, and that I think both he and I are scared of. An Asynchronous API is a classic example where the Java surface of the API in terms of signatures can be tiny, and therefore on the surface spec-ing the API seems simple, but the signatures are the very smallest part of the work here.

brianoliver commented 9 years ago

Likewise! I completely agree with what Alex alluded to. It’s been a concern of mine for sometime; there simply aren’t any clear answers (as yet).

Greg and I invested a few hours looking into it and researching various approaches. What often seems reasonable in a JVM, often doesn’t translate well to multi-JVM systems (and vice-versa).

The good thing is that we’re having a discussion. Like other challenged we’ve hit in the past, we’ll resolve this as well. My only thinking is that it may require some significant face-to-face time, which is often a big expense.

On Feb 24, 2015, at 3:51 PM, Chris Dennis notifications@github.com wrote:

+1

It is exactly this kind of complexity that @alexsnaps https://github.com/alexsnaps has hinted at in previous emails, and that I think both he and I are scared of. An Asynchronous API is a classic example where the Java surface of the API in terms of signatures can be tiny, and therefore on the surface spec-ing the API seems simple, but the signatures are the very smallest part of the work here.

— Reply to this email directly or view it on GitHub https://github.com/jsr107/jsr107spec/issues/307#issuecomment-75842965.

dsetrakyan commented 9 years ago

While I agree with Brian about all the outstanding questions about contracts of the Async API, I want to suggest that there is no need to add yet another AsyncCache API which is a mirror image of the Sync API. It just smells like API proliferation.

Apache Ignite project, for example, chose a much more elegant approach in my view by saying that any API can be either synchronous or asynchronous. The approach is documented here: http://apacheignite.readme.io/v1.0/docs/async-support

Here is a brief example.

Synchronous Call

// Get a handle on cache.
Cache<String, Integer> cache = ...;

Integer val = cache.getAndPut("mykey", 123);

Asynchronous Call

// Enable async mode.
cache = cache.withAsync();

// Asynchronous call (notice the same API)
cache.getAndPut("mykey", 123);

// Get future for the previous call.
IgniteFuture<Integer> fut = cache.future();

// Asynchronously listen to the result.
fut.listenAsync(f -> System.out.println("Previous cache value: " + f.get()));

I believe that this approach would be absolutely backward compatible from user standpoint. It would require, however, adding some concept of a Future into JCache. IgniteFuture, for example, extends java.util.concurrrent.Future.

Having said that, I do see the point others made that asynchronous APIs only make sense for distributed caches, while JSR 107 is about local caches only. Are we now adding distribution semantics to the spec? I also don't see Greg's argument about better performance for Asynchronous operations because, again, it applies only to distributed caches.

noctarius commented 9 years ago

I don't agree with the point that JSR107 is about local caches only. The spec itself definitely talks about both:

The Java Caching API’s objectives are to:
    ● support both in-process and distributed cache implementations;

What it doesn't specify is how a distributed cache has to be implemented or what guarantees are available.

It is also not true, that async operations are meant to be distributed only since reactive style programming is also used in local system (or well let's call it event based systems in that case).

What I agree with is that it is interesting to have a similar API but it means to have more internal context when you call withAsync and this cache instance couldn't be used concurrently anymore since you have to keep track of the last operation (or you end up with an internalThreadLocal to make sure every thread'll see its own operation future). On the other hand it was already said that Future::cancel is hard to define for mutating operations in a cache.

dsetrakyan commented 9 years ago

Several points:

  1. About JCache spec being local-only. If you take a look at EntryProcessor, for example, it is not Serializable because apparently JCache is local-only and cannot have distributed semantics on the API. Take a look at the thread https://github.com/jsr107/jsr107spec/issues/309 . It does not seem fair to pick and choose on a case by case basis when the spec should be local-only and when it should be distributed.
  2. Asynchronous operations are only useful when synchronous operations take a long time. For caches this is only true for distributed operations. For example, there is a reason that java.util.HashMap does not have Async API - it just does not make sense there.
  3. As far as Apache Ignite way of handling asynchronous operations, yes, you are right about the internal context. Whenever you create an asynchronous instance of Cache API in Apache Ignite, it does store the future for the previous invocation inside the internal ThreadLocal state. However, I am not sure why it would be a big deal. When it comes to APIs, elegant design and usability should come first in my view.
  4. Future.cancel() should return true or false. If a future cannot be canceled, then its cancel method should return false. Providers should be able to implement this.