[
https://issues.apache.org/jira/browse/IGNITE-5030?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15978260#comment-15978260
]
Vyacheslav Daradur edited comment on IGNITE-5030 at 4/21/17 9:10 AM:
---------------------------------------------------------------------
bq. @Cacheable(sync=true) guarantee that only one thread (across the cluster)
will fetch value for a key on get, even in case of some simultaneous gets.
The main idea is using EntryProcessor to provide such guarantee.
{code}
IgniteCache#invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object...
arguments)
{code}
It works well when we call #invoke directly.
But, there is an issue when using @Cachable(sync = true) with a cluster with 2+
nodes.
The main reason of the issue is that "args0" (in the code below) is an instance
of CacheAspectSupport$1,
which can't be deserialized properly at another node after transfering,
because it contains classes wich were generated at runtime by JVM.
{code}
class ValueLoaderEntryProcessor<T> implements CacheEntryProcessor<Object,
Object, T> {
@Override public T process(MutableEntry<Object, Object> entry,
Object... args) throws EntryProcessorException {
Callable<T> valueLoader = (Callable<T>)args[0];
// working logic according to the documentations
}
}
{code}
Another solutions is using a lock on a key, for example:
{code}
@Override public <T> T get(Object key, Callable<T> valueLoader) {
Object val = cache.get(key);
if (val != null)
return (T)fromStoreValue(val);
Lock lock = cache.lock(key);
try {
lock.lock();
try {
val = valueLoader.call();
}
catch (Exception e) {
throw new ValueRetrievalException(key, valueLoader, e);
}
if (val != null)
cache.put(key, val);
return (T)val;
}
finally {
lock.unlock();
}
}
{code}
But it works only with TRANSACTIONAL atomicity mode.
was (Author: daradurvs):
bq. @Cacheable(sync=true) guarantee that only one thread (across the cluster)
will fetch value for a key on get, even in case of some simultaneous gets.
The main idea is using EntryProcessor to provide such guarantee.
{code}
IgniteCache#invoke(K key, EntryProcessor<K, V, T> entryProcessor, Object...
arguments)
{code}
It works well when we call #invoke directly.
But, there is an issue when using @Cachable(sync = true) with a cluster with 2+
nodes.
The main reason of the issue is that "args0" (in the code below) is an instance
of CacheAspectSupport$1,
which can't be deserialized properly at another node after a transfering,
because it contains classes wich are generated runtime by JVM.
{code}
class ValueLoaderEntryProcessor<T> implements CacheEntryProcessor<Object,
Object, T> {
@Override public T process(MutableEntry<Object, Object> entry,
Object... args) throws EntryProcessorException {
Callable<T> valueLoader = (Callable<T>)args[0];
// working logic according to the documentations
}
}
{code}
Another solutions is using a lock on a key, for example:
{code}
@Override public <T> T get(Object key, Callable<T> valueLoader) {
Object val = cache.get(key);
if (val != null)
return (T)fromStoreValue(val);
Lock lock = cache.lock(key);
try {
lock.lock();
try {
val = valueLoader.call();
}
catch (Exception e) {
throw new ValueRetrievalException(key, valueLoader, e);
}
if (val != null)
cache.put(key, val);
}
finally {
lock.unlock();
}
}
{code}
But it works only with TRANSACTIONAL atomicity mode.
> Support Spring @Cacheable(sync=true) annotation
> -----------------------------------------------
>
> Key: IGNITE-5030
> URL: https://issues.apache.org/jira/browse/IGNITE-5030
> Project: Ignite
> Issue Type: Task
> Reporter: Anton Vinogradov
> Assignee: Vyacheslav Daradur
>
> @Cacheable(sync=true) guarantee that only one thread (across the cluster)
> will fetch value for a key on get, even in case of some simultaneous gets.
> So,
> org.apache.ignite.cache.spring.SpringCache#get(java.lang.Object,
> java.util.concurrent.Callable<T>)
> should be implemented to provide such guarantee.
--
This message was sent by Atlassian JIRA
(v6.3.15#6346)