javaconcurrencyjbossjboss6.xinfinispan

Infinispace Cache: Inconsistent writes concurrent actions


I have searched for solution to this issue everywhere but I could not find any hint.

My application is deployed on JBOSS EAP 6.4 and built using JDK 1.8. I have configured one local infinispan cache in standalone xml as:

<subsystem xmlns="urn:jboss:domain:infinispan:1.5">
    <cache-container name="test-cache" default-cache="test-data-cache" jndi-name="java:jboss/infinispan/test-cache" statistics-enabled="true">
        <transport lock-timeout="60000"/>
        <local-cache name="test-data-cache" statistics-enabled="true">
            <!-- <transaction locking="PESSIMISTIC"/> -->
            <locking isolation="READ_COMMITTED"/>
            <expiration lifespan="3600000"/>
        </local-cache>
    </cache-container>
</subsystem>

I put the data into the Cache as:

package com.comp.test;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;

import org.apache.commons.collections4.MapUtils;
import org.infinispan.Cache;

@Stateless
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class CacheTest {

    @Resource(lookup = "java:jboss/infinispan/test-cache")
    private org.infinispan.manager.CacheContainer container;
    
    public void putData(String k, String v) {
        final Map<String, String> tmap = getDataCache().get(k);
        if (!containsData(k)) {
            final HashMap<String, String> rmap = new HashMap<>();
            rmap.put(k+"_"+v, v); 
            getDataCache().put(k, rmap);
        } else {
            getDataCache().get(k).put(k+"_"+v, v);
        }
    }
    
    public boolean containsData(String k) {
        return getDataCache().containsKey(k);
    }

    private Cache<String, Map<String, String>> getDataCache() {
        return container.getCache("test-data-cache");
    }
}

I have stateless beans which puts collection of data into the cache concurrently (@Asyncronous annotation). When I retrieve the data from the Cache once all concurrent operations are over, Cache always has the less number of values. If I put 20 values, only 16 / 17 values are present in the cache.

I tried to find out if I can put a lock on the key before I star putting data into the cache for that particular key. But I learnt that it is handled internally by the Infinispan. I found another similar question on SO. But this question is unanswered as well. Infinispan cache inconsistency for massive concurrent operations

Please let me know how to make sure that data put concurrently into the infinispan local cache is consistent at the end. If you need more information, please let me know.


Solution

  • You have two options that work with pessimistic locking:

    1. getDataCache().getAdvancedCache().lock(k)
    2. getDataCache().getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK)

    There is a third option: use optimistic locking instead, and retry the transaction if another transaction modifies the key. But this would not work with @TransactionalAttribute, you would have to call TransactionManager.commit() yourself and catch the WriteSkewException.