[JBoss JIRA] (ISPN-3128) Better support for (Spring) read caching
by Mathieu Lachance (JIRA)
[ https://issues.jboss.org/browse/ISPN-3128?page=com.atlassian.jira.plugin.... ]
Mathieu Lachance commented on ISPN-3128:
----------------------------------------
After running in the same issue myself yesterday, I think this is in no way related to Infinispan but instead a poor design decision of Spring.
Here is a [horrible] workaround by decorating the {{org.springframework.cache.Cache}} interface:
{code}
public class InvalidationAwareSpringCacheDecorator implements Cache {
private Cache cache;
private boolean invalidationCache;
public InvalidationAwareSpringCacheDecorator(Cache cache) {
this.cache = cache;
invalidationCache = isInvalidationCache();
}
private boolean isInvalidationCache() {
CacheMode cacheMode = getNativeCache().getCacheConfiguration().clustering().cacheMode();
if (CacheMode.INVALIDATION_SYNC.equals(cacheMode) ||
CacheMode.INVALIDATION_ASYNC.equals(cacheMode)) {
return true;
}
return false;
}
@Override
public String getName() {
return cache.getName();
}
@Override
public AdvancedCache<Object, Object> getNativeCache() {
return (AdvancedCache) cache.getNativeCache();
}
@Override
public ValueWrapper get(Object key) {
return cache.get(key);
}
/**
* <p> fix for https://issues.jboss.org/browse/ISPN-3128
* <p> when incoming from:
* <li> {@link Cacheable} delegates to {@link AdvancedCache#putForExternalRead(Object, Object)}
* <li> {@link CachePut} delegates to {@link AdvancedCache#put(Object, Object)}
*/
@Override
public void put(Object key, Object value) {
if (invalidationCache && isCalledFromCacheableAnnotatedMethod()) {
getNativeCache().putForExternalRead(key, value);
}
else {
cache.put(key, value);
}
}
private boolean isCalledFromCacheableAnnotatedMethod() {
for (StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {
String className = stackTraceElement.getClassName();
if (! className.startsWith("YOUR_PACKAGE_NAME_GOES_HERE")) {
// skip
continue;
}
// strip off the Spring CGLIB proxy to get the non-proxied class name
int cglibProxyIndex = className.lastIndexOf("$$EnhancerBySpringCGLIB$$");
if (cglibProxyIndex != -1) {
className = className.substring(0, cglibProxyIndex);
}
Class<?> clazz = getClass(className);
List<Method> methods = getMethods(clazz, stackTraceElement.getMethodName());
if (isAnyMethodAnnotatedWith(methods, Cacheable.class)) {
return true;
}
if (isAnyMethodAnnotatedWith(methods, CachePut.class)) {
return false;
}
}
return false;
}
private Class<?> getClass(String className) {
try {
return Class.forName(className);
}
catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
private List<Method> getMethods(Class<?> clazz, String methodName) {
List<Method> methods = new ArrayList<>(1);
for (Method method : clazz.getMethods()) {
if (method.getName().equals(methodName)) {
methods.add(method);
}
}
return methods;
}
private boolean isAnyMethodAnnotatedWith(List<Method> methods, Class<? extends Annotation> annotationClass) {
for (Method method : methods) {
if (method.isAnnotationPresent(annotationClass)) {
return true;
}
}
return false;
}
@Override
public void evict(Object key) {
cache.evict(key);
}
@Override
public void clear() {
cache.clear();
}
}
{code}
Using spring-context-3.2.11.RELEASE, in {{org.springframework.cache.interceptor.CacheAspectSupport#update(Map<CacheOperationContext, Object> updates, Object retVal)}}, the API voluntary get rid of the context which had the information if the actual intercepted method was annotated with either {{@Cacheble}} or {{@CachePut}} making it impossible to then know in which of these two cases we are.
I would suggest closing this issue and opening a new one in Spring linking back to this one.
> Better support for (Spring) read caching
> ----------------------------------------
>
> Key: ISPN-3128
> URL: https://issues.jboss.org/browse/ISPN-3128
> Project: Infinispan
> Issue Type: Feature Request
> Components: Spring Integration
> Affects Versions: 5.3.0.Beta2
> Environment: Spring 3.1+
> Reporter: Mike Noordermeer
> Assignee: Gustavo Fernandes
>
> We're having a bit of an issue using Infinispan as backing cache for Spring's Caching annotations. The reasons are clear, but I haven't found a proper solution yet. I thought I would describe the issues in a feature request, so we can try to make the necessary changes to fix the situation.
> As already described in [the forums|https://community.jboss.org/thread/201086], an Infinispan cache in invalidation mode sends an invalidation message to other cache nodes if something is put into the cache. This conflicts with Spring's idea of {{@Cacheable}} annotations, which are ment to provide read caching for methods. Imagine the following scenario:
> - Method A is annotated with {{@Cacheable}}, backed by a cache in invalidation mode
> - Node X calls Method A, the method is executed and the return value is locally cached (and an invalidation message is sent to Node Y)
> - Node Y calls Method A, the method is executed and the return value is locally cached, *also, the cache of Node X is invalidated*
> - Node X calls Method A and has to execute the method again, since its cache is gone, etc... etc...
> The reason we want to be able to invalidate the read cache, is because if the application executed an update method for the underlying data (usually marked with {{@CacheEvict}} or {{@CachePut}}) we *do* want to invalidate the other ndoes.
> In Infinispan, this problem can be solved by caching using {{cache.putForExternalRead()}}. That will not invalidate other caches on a put, but will invalidate the cache when asked explicitly. However, simply changing {{put()}} to {{putForExternalRead()}} in {{SpringCache}} leads to a couple of other issues:
> - This is probably not the behaviour everyone wants (people that do not use Spring annotations, but expect the usual Infinispan behaviour).
> - Changing {{put()}} to {{putForExternalRead()}} would break the expected {{@CachePut}} behaviour (a new value is generated, so the old values should be invalidated), but it would fix {{@Cacheable}} behaviour.
> Maybe there should be an option in the factory bean to switch between {{put()}} and {{putForExternalRead()}}? Maybe Spring should change or amend its interface so we can differentiate between calls coming from {{@CachePut}} and calls coming from {{@Cacheable}}? An other option is to make the invalidation behaviour configurable in Infinispan (that's the way Ehcache handles this issue, you can choose if puts or updates should be replicated, or just replicate invalidations).
--
This message was sent by Atlassian JIRA
(v6.3.1#6329)
10 years, 2 months
[JBoss JIRA] (ISPN-4873) Statetransfer thread pool deadlock
by Dan Berindei (JIRA)
[ https://issues.jboss.org/browse/ISPN-4873?page=com.atlassian.jira.plugin.... ]
Dan Berindei reopened ISPN-4873:
--------------------------------
[~pruivo] noticed that my fix doesn't work, because I haven't made {{StateRequestCommand}} implement {{TopologyAffectedCommand}} and the extracted topology is always {{0}}.
> Statetransfer thread pool deadlock
> ----------------------------------
>
> Key: ISPN-4873
> URL: https://issues.jboss.org/browse/ISPN-4873
> Project: Infinispan
> Issue Type: Bug
> Components: Core
> Affects Versions: 6.0.2.Final
> Reporter: Takayoshi Kimura
> Assignee: Dan Berindei
> Fix For: 7.0.0.Final
>
>
> During massive state transfer with 300 nodes and 3000 caches, the OOB and/or infinispan thread pool gets deadlock, similar to ISPN-2808.
> The thread pool is configured with max 1400 threads now and increasing them is not a realistic workaround as the user is planning to add more caches.
--
This message was sent by Atlassian JIRA
(v6.3.1#6329)
10 years, 2 months