abhi
abhi

Reputation: 161

EhCache eternal is not behaving as expected

My requirement is to have disk based cache. If cache is memory is full, i want LRU element to be pushed to the disk. And then if file on disk is full then I want LRU element on disk to evicted. This is pretty simple requirement, however I could not achieve this using EhCache.

I made use of EhCache ( 2.10.1) with following config :

 <defaultCache name="default"
       maxBytesLocalHeap="50m"
       maxBytesLocalDisk="100g"
       eternal="true"
       timeToIdleSeconds="0"        
       timeToLiveSeconds="0"
       diskExpiryThreadIntervalSeconds="120"
       memoryStoreEvictionPolicy="LRU">
       <persistence strategy="localTempSwap"/>
 </defaultCache>

My expectation here is, when cache is filled up (i.e. cache size is exceeding 50M) , i want LRU element(s) to be pushed to the file and hence creating some space for new element in memory.

However this is not how EhCache is working, I did a sample test to check element count in cache:

public static void main(String[] args) throws Exception {

ArrayList<String> keys = new ArrayList<String>();
CacheManager cacheManager;
FileInputStream fis = null;
try {
    fis = new FileInputStream(
            new File("src/config/ehcache.xml").getAbsolutePath());
    cacheManager = CacheManager.newInstance(fis);
}
finally {
    fis.close();
}

  java.lang.Runtime.getRuntime().addShutdownHook(new Thread(){
      @Override
    public void run() {

          try
          {
              System.out.println("Shutting down Eh Cache manager !!");
                 cacheManager.clearAll();
                 cacheManager.shutdown();
                 System.out.println("done !!");

          }catch(Exception e)
          {
              e.printStackTrace();
          }
                      }
  });

System.out.println("starting ...");
System.out.println(System.getProperty("java.io.tmpdir"));

cacheManager.addCache("work_item_111");

Cache ehCache = cacheManager.getCache("work_item_111");

long start_outer = System.currentTimeMillis();
for(int i =0;i<30;i++)
{
    long start = System.currentTimeMillis();
    String key = UUID.randomUUID().toString();
    ehCache.put(new Element(key, getNextRandomString()));
    keys.add(key);
    //System.out.println("time taken : " + (System.currentTimeMillis()- start));
    System.out.println((System.currentTimeMillis()- start) +" - " + (ehCache.getStatistics().getLocalDiskSizeInBytes()/1024/1024) + " - " +(ehCache.getStatistics().getLocalHeapSizeInBytes()/1024/1024));
}
System.out.println("time taken-total : " + (System.currentTimeMillis()- start_outer));
System.out.println(ehCache.getSize());

System.out.println("disk size : " +ehCache.getStatistics().getLocalDiskSizeInBytes()/1024/1024);
System.out.println("memory size : " +ehCache.getStatistics().getLocalHeapSizeInBytes()/1024/1024);

    Iterator<String> itr = keys.iterator();
    int count =0;
    while(itr.hasNext())
    {
        count++;
        String key = itr.next();
        if(ehCache.get(key) == null)
        {
            System.out.println("missingg key : " + key);
        }
    }
    System.out.println("checked for count :" + count);

}

The outcome is quite disappointing, after putting 30 elements in cache ( each element of size appro. 4mb) , I can see only 7 elements in the cache ( ehCache.getSize() returns 7 ) and also i dont see file on disk growing.

Can any EhCache expert help me out here if I am missing anything here. Thanks.

Upvotes: 0

Views: 1024

Answers (2)

Tomas Bilek
Tomas Bilek

Reputation: 1

facing the same problem. In cycle I am adding 10k elements with cache configuration

 cacheConfiguration.maxBytesLocalHeap(1, MemoryUnit.MEGABYTES);
        cacheConfiguration.diskSpoolBufferSizeMB(10);
//        cacheConfiguration.maxEntriesLocalHeap(1);
        cacheConfiguration.name("smallcache");
        config.addCache(cacheConfiguration);
        cacheConfiguration.setDiskPersistent(true);
        cacheConfiguration.overflowToDisk(true);
        cacheConfiguration.eternal(true);

When increasing maxBytesLocalHeap to 10, it is fine, when using maxEntriesLocalHeap instead of maxBytes and it is even set to value 1 (item), it works without problem.

Version 2.6

This is answer Ehcache set to eternal but forgets elements anyway?

Upvotes: 0

Louis Jacomet
Louis Jacomet

Reputation: 14500

First, regarding the Ehcache topology:

  • The tiering model behind Ehcache enforces since at least 2.6 that all mappings are present in the lowest tier, disk in your case, at all times.

This means it is no longer an overflow model.

Now as to why your test behaves differently than what you expect:

  • Ehcache 2.x disk tier leaves the keys in memory and when your heap is memory sized, the amount of space occupied by the key is subtracted from that capacity.
  • Ehcache 2.x writes asynchronously to the disk and has limited queues for doing that. While this is not a problem in most use cases, in such a tight loop in a test, you may hit these limits and have the cache drop puts by evicting inline.

So in order to better understand what's happening, have a look at the Ehcache logs in debug and see what is really going on. If you see evictions, simply loop more slowly or increase some of the settings for the disk write queue such as diskSpoolBufferSizeMB attribute on the cache element.

Upvotes: 1

Related Questions