Ehcache磁盘存储不干净关机

时间:2010-03-03 17:21:16

标签: java ehcache

我正在使用具有磁盘存储持久性的缓存。在应用程序的后续重新运行中,我收到以下错误:

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

除了在应用程序中的某处明确调用net.sf.ehcache.CacheManager.shutdown()之外,还有什么方法可以解决这个问题吗?

缓存配置:

<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>

复制问题的代码:

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"));
    }
}

3 个答案:

答案 0 :(得分:12)

尝试设置系统属性: 的 net.sf.ehcache.enableShutdownHook =真

因此,您可以在程序开头添加以下行: System.setProperty("net.sf.ehcache.enableShutdownHook","true");

或者,从命令行传递属性: java -Dnet.sf.ehcache.enableShutdownHook=true ...

注意,使用此关闭钩子时,ehcache网站确实提到了一些注意事项: Shutting Down Ehcache

  

当关闭钩子运行时,以及何时不会

     

关闭钩子在以下时间运行:

     
      
  • 程序正常存在。例如调用System.exit(),或者最后一个非守护进程线程退出
  •   
  • 虚拟机已终止。例如CTRL-C。这对应于kill -SIGTERM pid或kill   -15 pid在Unix系统上。
  •   
     

在以下情况下,关闭挂钩不会运行:

     
      
  • 虚拟机中止
  •   
  • 在Unix系统上将SIGKILL信号发送到虚拟机进程。例如杀死-SIGKILL   pid或kill -9 pid
  •   
  • TerminateProcess调用将发送到Windows系统上的进程。
  •   

希望它有效:)

答案 1 :(得分:2)

你是如何停止申请的?

从查看Ehcache代码,它注册了一个JVM关闭钩子Runtime.getRuntime().addShutdownHook,它关闭了JVM出口上的缓存。如果JVM被终止或崩溃,则不会调用关闭挂钩。

更新您的评论:

以下是DiskStore dispose方法的评论:

  

关闭磁盘存储以准备缓存关闭

     

如果发生VM崩溃,则不会运行关闭挂钩。数据文件和索引文件将不同步。初始化时,我们总是在读完元素后删除索引文件,使其长度为零。在脏重启时,它仍然会有,并且数据文件将自动删除,从而保持安全。

因此,如果您在另一个单元测试中重新创建Cache。由于shutdownHook不会运行,索引文件将为0. Ehcache认为索引已损坏。我会在每个单元测试中使用JUnit的@After注释关闭Cache。或者,在所有测试中共享缓存,但我猜这不会给你孤立的测试。

答案 2 :(得分:0)

对于我们这些使用Ehcache with Spring 3.1+和java config的人,你必须使用:

@Bean(destroyMethod = "shutdown")
public net.sf.ehcache.CacheManager ehCacheManager() { .. }

和(假设您还使用非Web Spring ApplicationContext,在那里启用shutdown hook以使bean被优雅地销毁:

context = new AnnotationConfigApplicationContext(AppConfig.class);
((AbstractApplicationContext) context).registerShutdownHook();

有关详细信息,请参阅this