Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ehcache disk store unclean shutdown

Tags:

java

ehcache

I'm using a cache with disk store persistence. On subsequent reruns of the app I'm getting the following error:

net.sf.ehcache.store.DiskStore deleteIndexIfCorrupt
WARNING: The index for data file MyCache.data is out of date,
probably due to an unclean shutdown. Deleting index file MYCache.index

Is there any way to fix that apart from explicitly calling net.sf.ehcache.CacheManager.shutdown() somewhere in the app?

Cache configuration:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd"
             updateCheck="true" monitoring="autodetect">

    <diskStore path="C:\work"/>

    <cacheManagerEventListenerFactory class="" properties=""/>

    <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="peerDiscovery=automatic,
                        multicastGroupAddress=230.0.0.1,
                        multicastGroupPort=4446, timeToLive=1"
            propertySeparator=","
            />

    <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>

    <defaultCache
            maxElementsInMemory="1"
            eternal="false"
            timeToIdleSeconds="0"
            timeToLiveSeconds="86400"
            overflowToDisk="true"
            diskSpoolBufferSizeMB="1"
            maxElementsOnDisk="10000"
            diskPersistent="true"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LFU"
            />

</ehcache>

Code to replicate the issue:

import java.util.ArrayList;
import java.util.List;

import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

public class CacheTest {
    static CacheManager manager = new CacheManager(CacheTest.class
            .getResource("ehcache.xml"));
    static Cache cache;

    public static void main(String[] args) {

        // Get a default instance
        manager.addCache("test");
        cache = manager.getCache("test");

        // Generate some junk so that the
        // cache properly flushes to disk
        // as cache.flush() is not working
        List<String> t = new ArrayList<String>();
        for (int i = 0; i < 1000; i++)
            t.add(null);
        // Oddly enough fewer elements
        // do not persist to disk or give
        // an error
        for (int i = 0; i < 100000; i++) {
            cache.put(new Element(i, t));
        }
        cache.flush();

        if (cache.get("key1") == null) {
            System.out.println("key1 not found in cache!");
            cache.put(new Element("key1", "value1"));
        }

        System.out.println(cache.get("key1"));
    }
}
like image 670
Tomasz Avatar asked Mar 03 '10 17:03

Tomasz


People also ask

How do I get rid of Ehcache?

To remove an element from a cache we first need to built the key. This is a collection of type “Object” which will contain 1 or more values that will uniquely identify the element. First we will check that the key exists in the cache. If it does, we can call the “remove” method on the cache.

Is Ehcache persistent?

Open-source Ehcache offers a limited version of persistence, as noted in this document. Fast Restart provides enterprise-ready crash resilience with an option to store a fully consistent copy of the cache on the local disk at all times.

How do I turn off Old CacheManager?

The recommended way to shutdown the Ehcache is: to call CacheManager. shutdown()

Is Ehcache in memory cache?

In this article, we will introduce Ehcache, a widely used, open-source Java-based cache. It features memory and disk stores, listeners, cache loaders, RESTful and SOAP APIs and other very useful features.


2 Answers

Try setting the system property: net.sf.ehcache.enableShutdownHook=true

So, either you can add the following line in the beginning of your program: System.setProperty("net.sf.ehcache.enableShutdownHook","true");

Or, from the command line to pass the property: java -Dnet.sf.ehcache.enableShutdownHook=true ...

Note, the ehcache website does mention some caution when using this shutdown hook: Shutting Down Ehcache

When a shutdown hook will run, and when it will not

The shutdown hook runs when:

  • a program exists normally. e.g. System.exit() is called, or the last non-daemon thread exits
  • the Virtual Machine is terminated. e.g. CTRL-C. This corresponds to kill -SIGTERM pid or kill -15 pid on Unix systems.

The shutdown hook will not run when:

  • the Virtual Machine aborts
  • A SIGKILL signal is sent to the Virtual Machine process on Unix systems. e.g. kill -SIGKILL pid or kill -9 pid
  • A TerminateProcess call is sent to the process on Windows systems.

Hope it works :)

like image 71
niran Avatar answered Sep 23 '22 14:09

niran


How are you stopping your application?

From looking at the Ehcache code, it registers a JVM shutdown hook Runtime.getRuntime().addShutdownHook that closes the cache on JVM exit. If the JVM is killed, or crashes, the shutdown hook will not be called.

Update RE your comment:

Here is the comment from the DiskStore dispose method:

Shuts down the disk store in preparation for cache shutdown

If a VM crash happens, the shutdown hook will not run. The data file and the index file will be out of synchronisation. At initialisation we always delete the index file after we have read the elements, so that it has a zero length. On a dirty restart, it still will have and the data file will automatically be deleted, thus preserving safety.

So, if your recreating the Cache in a different Unit test. Since the shutdownHook wouldn't have run, the index file will be 0. Ehcache thinks the index is corrupt. I would shutdown the Cache using JUnit's @After annotation in each of your unit tests. Or, share the Cache across all tests, but I'm guessing this would not give you isolated tests.

like image 28
Steve K Avatar answered Sep 26 '22 14:09

Steve K