0

The following EhCache code, with maps as values and off-heap memory, fails a simple put/get unit test (see below).

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;

import java.io.Serializable;
import java.util.HashMap;


public class EhCacheMappedCache {

    private static final CacheManager CACHE_MANAGER = CacheManagerBuilder.newCacheManagerBuilder()
            .with(CacheManagerBuilder.persistence(".\\quantity-cache"))
            .build(true);

    private final Cache<Integer, CacheMap> cache;

    private static class CacheMap extends HashMap<Integer, Double> implements Serializable {}

    EhCacheMappedCache() {
        CacheConfigurationBuilder<Integer, CacheMap> cacheCfgBuilder = CacheConfigurationBuilder
                .newCacheConfigurationBuilder(Integer.class, CacheMap.class,
                        ResourcePoolsBuilder.newResourcePoolsBuilder()
                                .heap(1, MemoryUnit.GB)
                                .offheap(2, MemoryUnit.GB));
        this.cache = CACHE_MANAGER.createCache(toString(), cacheCfgBuilder);
    }

    public void put(Integer cacheId, Integer key, Double value) {
        cache.putIfAbsent(cacheId, new CacheMap());
        cache.get(cacheId).put(key, value);
    }

    public Double get(Integer cacheId, Integer key) {
        cache.putIfAbsent(cacheId, new CacheMap());
        return cache.get(cacheId).get(key);
    }

}

The following simple unit test fails:
java.lang.AssertionError:
Expected :1234.0
Actual :null

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class EhCacheMappedCacheTest {

    private EhCacheMappedCache cache;

    @Before
    public void doBefore() {
        cache = new EhCacheMappedCache();
    }

    @Test
    public void testPutGet() {
        final Double value = 1234D;

        cache.put(1, 2, value);
        final Double valueFromCache = cache.get(1, 2);

        Assert.assertEquals(value, valueFromCache);
    }

}

The simple version of have a Cache<Integer, Double> instead of Cache<Integer, HashMap> works fine with off-heap memory, as does the mapped version above with only on-heap memory.

Any ideas on how to make the Map version work?
Thanks.

  • The `put` is modifying a cached value. If on-heap then you are always getting the same instance, but if off-heap then it deserializes a new instance each time. This new instance is then modified before being returned, but is never itself stored in the cache. It is best to treat cached values as immutable objects to avoid race conditions and other surprises. – Ben Manes Mar 22 '22 at 21:10
  • Thanks @BenManes. Replacing the put method with following solved the issue: ```public void put(Integer cacheId, Integer key, Double value) { cache.putIfAbsent(cacheId, new CacheMap()); CacheMap cacheMap = cache.get(cacheId); cacheMap.put(key, value); cache.put(cacheId, cacheMap); }``` – user3562318 Mar 23 '22 at 09:37
  • @BenManes, if you convert your comment to an answer I can mark it as the solution. – user3562318 Mar 23 '22 at 09:43

0 Answers0