Search code examples
javacachingguava

How to avoid evicting entries from Guava Cache


I'm using Guava Cache to cache about 100K records in memory. I use cache.putAll(Map<K,V>) to pre-load the cache. After loading about 20K records, I see removal notifications with cause 'REPLACED'. Max size is 1GB and weigher returns 1 for all entries, expireAfterAccess is 24 hours. 1GB is enough for all records. How can I ensure that no entry is replaced before 24 hrs ?

MyCacheLoader cacheLoader = new MyCacheLoader();
CacheBuilder<Long, Map<String, List<String>>> cacheBuilder = CacheBuilder.newBuilder().
        initialCapacity(1024 * 1024 * 1024).
        //maximumSize(1024 * 1024 * 1024).
        maximumWeight(1000000).
        weigher(new Weigher<Long, Map<String, List<String>>>(){
            public int weigh(Long arg0, Map<String, List<String>> arg1) {
                return 1;
            }
        }).
        concurrencyLevel(1).
        expireAfterAccess(24, TimeUnit.HOURS);

cache = cacheBuilder.build(cacheLoader);

Solution

  • My guess is that you might be adding duplicate keys.

    UPDATE

    From JavaDocs for RemovalCause.REPLACED:

    The entry itself was not actually removed, but its value was replaced by the user. This can result from the user invoking Cache.put(K, V), LoadingCache.refresh(K), Map.put(K, V), Map.putAll(java.util.Map), ConcurrentMap.replace(Object, Object), or ConcurrentMap.replace(Object, Object, Object).

    So since it's not a LoadingCache, judging by a doc, this leaves only two possibilities: a duplicate or a bug.


    From the source of LocalCache, zero weight means non-evictable objects:

    ReferenceEntry<K, V> getNextEvictable() {
      for (ReferenceEntry<K, V> e : accessQueue) {
        int weight = e.getValueReference().getWeight();
        if (weight > 0) {
          return e;
        }
      }
      throw new AssertionError();
    }