java Ehcache 磁盘存储非正常关机
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2373431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ehcache disk store unclean shutdown
提问by Tomasz
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?
除了显式调用net.sf.ehcache.CacheManager.shutdown()应用程序中的某个地方之外,还有什么方法可以解决这个问题?
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"));
}
}
回答by niran
Try setting the system property: net.sf.ehcache.enableShutdownHook=true
尝试设置系统属性: 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");
因此,您可以在程序的开头添加以下行:
System.setProperty("net.sf.ehcache.enableShutdownHook","true");
Or, from the command line to pass the property:
java -Dnet.sf.ehcache.enableShutdownHook=true ...
或者,从命令行传递属性:
java -Dnet.sf.ehcache.enableShutdownHook=true ...
Note, the ehcache website does mention some caution when using this shutdown hook: Shutting Down Ehcache
请注意,ehcache 网站在使用此关闭挂钩时确实提到了一些注意事项: 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.
关闭钩子什么时候运行,什么时候不运行
关闭挂钩在以下情况下运行:
- 程序正常存在。例如 System.exit() 被调用,或者最后一个非守护线程退出
- 虚拟机终止。例如CTRL-C。这对应于 Unix 系统上的 kill -SIGTERM pid 或 kill -15 pid。
在以下情况下,关闭挂钩将不会运行:
- 虚拟机中止
- 一个 SIGKILL 信号被发送到 Unix 系统上的虚拟机进程。例如 kill -SIGKILL pid 或 kill -9 pid
- TerminateProcess 调用被发送到 Windows 系统上的进程。
Hope it works :)
希望它有效:)
回答by Steve K
How are you stopping your application?
你如何停止你的应用程序?
From looking at the Ehcache code, it registers a JVM shutdown hook Runtime.getRuntime().addShutdownHookthat closes the cache on JVM exit. If the JVM is killed, or crashes, the shutdown hook will not be called.
从 Ehcache 代码来看,它注册了一个 JVM 关闭钩子Runtime.getRuntime().addShutdownHook,在 JVM 退出时关闭缓存。如果 JVM 被杀死或崩溃,则不会调用关闭挂钩。
Update RE your comment:
更新 RE 您的评论:
Here is the comment from the DiskStore disposemethod:
这是来自 DiskStore dispose方法的注释:
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.
关闭磁盘存储以准备关闭缓存
如果发生 VM 崩溃,则关闭挂钩将不会运行。数据文件和索引文件将不同步。在初始化时,我们总是在读取元素后删除索引文件,使其长度为零。在脏重启时,它仍然会有,并且数据文件将被自动删除,从而保护安全。
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.
因此,如果您在不同的单元测试中重新创建缓存。由于shutdownHook 不会运行,索引文件将为0。Ehcache 认为索引已损坏。我会在每个单元测试中使用 JUnit 的 @After 注释关闭缓存。或者,在所有测试中共享缓存,但我猜这不会给你单独的测试。
回答by ben3000
For those of us using Ehcache with Spring 3.1+ and java config, you have to use:
对于我们这些在 Spring 3.1+ 和 java 配置中使用 Ehcache 的人,您必须使用:
@Bean(destroyMethod = "shutdown")
public net.sf.ehcache.CacheManager ehCacheManager() { .. }
and (assuming you're also using a non-web Spring ApplicationContext, enable the shutdown hook there to cause the bean to be destroyed gracefully:
并且(假设您还使用非 Web 的 Spring ApplicationContext,请在那里启用关闭钩子以使 bean 被优雅地销毁:
context = new AnnotationConfigApplicationContext(AppConfig.class);
((AbstractApplicationContext) context).registerShutdownHook();
see thisfor more information.
请参阅此了解更多信息。

