Ehcache磁盘存储非正常关闭

6

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

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个回答

13

尝试设置系统属性:

net.sf.ehcache.enableShutdownHook=true

因此,您可以在程序开头添加以下行:

System.setProperty("net.sf.ehcache.enableShutdownHook","true");

或者,在命令行中传递属性:

java -Dnet.sf.ehcache.enableShutdownHook=true ...

请注意,ehcache网站在使用此关闭挂钩时提到了一些注意事项:

关闭Ehcache

关闭挂钩何时运行,何时不运行

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

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

当以下情况发生时,关闭挂钩将不会运行:

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

希望它能起作用:)


2

你是如何停止应用程序的?

从查看Ehcache代码来看,它注册了一个JVM关闭钩子Runtime.getRuntime().addShutdownHook,在JVM退出时关闭缓存。如果JVM被杀死或崩溃,关闭钩子将不会被调用。

关于您的评论的更新:

这里是DiskStore dispose方法的注释:

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

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

因此,如果您在不同的单元测试中重新创建缓存。由于关闭钩子不会运行,索引文件将为0。Ehcache认为索引已损坏。我建议在每个单元测试中使用JUnit的@After注释关闭缓存。或者,共享缓存跨所有测试,但我猜这不会给您提供隔离的测试。


我将它作为 Junit4 测试的一部分运行。错误会在测试的后续重跑中显示。如果有帮助的话,我可以提供一个代码示例来复制。 - Tomasz
不行,即使在可运行的JAR文件中从命令行运行,仍然会出现相同的错误。 - Tomasz
我猜一些示例代码可能会很有用。您也可以尝试仅运行单个测试,并检查索引文件的大小。根据ehcache代码中的注释,它应该是非零值。 - Steve K
添加了一些代码来复制问题。.data文件被正确创建,但.index文件仍停留在0。 - Tomasz

1
对于使用Spring 3.1+和java配置的Ehcache用户,您需要使用以下内容:
@Bean(destroyMethod = "shutdown")
public net.sf.ehcache.CacheManager ehCacheManager() { .. }

假设您也使用了非Web Spring应用上下文,则需要在那里启用关闭挂钩以使bean能够优雅地被销毁:
context = new AnnotationConfigApplicationContext(AppConfig.class);
((AbstractApplicationContext) context).registerShutdownHook();

请参见this以获取更多信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接