Java ehcache 持续到磁盘问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1729605/
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 persist to disk issues
提问by hross
I want to do something with ehcache in Java that I think should be extremely simple, but I've spent enough time frustrating myself with the docs...
我想用 Java 中的 ehcache 做一些我认为应该非常简单的事情,但我已经花了足够多的时间让自己对文档感到沮丧......
Write a value to a disk persistent cache. Shut down.
Start up again and read that value.
将值写入磁盘持久缓存。关掉。
再次启动并读取该值。
Here is my Java function:
这是我的 Java 函数:
private static void testCacheWrite() {
// create the cache manager from our configuration
URL url = TestBed.class.getClass().getResource("/resource/ehcache.xml");
CacheManager manager = CacheManager.create(url);
// check to see if our cache exits, if it doesn't create it
Cache testCache = null;
if (!manager.cacheExists("test")) {
System.out.println("No cache found. Creating cache...");
int maxElements = 50000;
testCache = new Cache("test", maxElements,
MemoryStoreEvictionPolicy.LFU, true, null, true, 60, 30,
true, Cache.DEFAULT_EXPIRY_THREAD_INTERVAL_SECONDS, null);
manager.addCache(testCache);
// add an element to persist
Element el = new Element("key", "value");
testCache.put(el);
testCache.flush();
System.out.println("Cache to disk. Cache size on disk: " +
testCache.getDiskStoreSize());
} else {
// cache exists so load it
testCache = manager.getCache("test");
Element el = testCache.get("key");
if (null == el) {
System.out.print("Value was null");
return;
}
String value = (String) el.getObjectValue();
System.out.println("Value is: " + value);
}
manager.shutdown();
}
And here is my cache configuration (ehcache.xml):
这是我的缓存配置(ehcache.xml):
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="C:/mycache"/><!-- java.io.tmpdir -->
<defaultCache
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" />
</ehcache>
Even though I see test.index and test.data files on disk after the first run, output from this function is always the following (it never seems to load the cache from disk):
即使我在第一次运行后在磁盘上看到 test.index 和 test.data 文件,该函数的输出始终如下(它似乎从未从磁盘加载缓存):
No cache found. Creating cache...
Cache to disk. Cache size on disk: 2
未找到缓存。正在创建缓存...
缓存到磁盘。磁盘缓存大小:2
I must be doing something dumb here, but I 'm not sure what!
我一定在这里做了一些愚蠢的事情,但我不确定是什么!
采纳答案by hross
Okay, well what I did to fix this was configure my cache using the configuration file. Here is the updated config:
好的,我为解决这个问题所做的是使用配置文件配置我的缓存。这是更新的配置:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="C:/mycache" />
<defaultCache
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
maxElementsOnDisk="10000000"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU" />
<cache
name="test"
maxElementsInMemory="500"
eternal="true"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="1"
memoryStoreEvictionPolicy="LFU" />
</ehcache>
So basically I didn't use the constructor to define the cache.
所以基本上我没有使用构造函数来定义缓存。
I suppose this will work, but I still wonder why programatically defined caches can't persist on disk (especially since they are still written to disk!).
我想这会起作用,但我仍然想知道为什么以编程方式定义的缓存不能保留在磁盘上(尤其是因为它们仍然写入磁盘!)。
Thanks for the comments guys.
谢谢你们的评论。
回答by sfussenegger
I think you should remove the manager.cacheExists(..)
test and simply create your cache using testCache = manager.getCache("test");
instead of using new Cache(..)
. Even if your cache is diskPersistent, it won't exist until you get it the first time. (At least that's what I think as I'm only using getCache(..)
and it does exactly what you are looking for)
我认为您应该删除manager.cacheExists(..)
测试并简单地使用testCache = manager.getCache("test");
而不是使用来创建缓存new Cache(..)
。即使您的缓存是 diskPersistent,它也不会存在,直到您第一次获得它。(至少这是我的想法,因为我只是在使用getCache(..)
它并且它完全符合您的要求)
Note:
笔记:
You could also add something like this to make sure the cache exists:
您还可以添加类似的内容以确保缓存存在:
Cache cache = manager.getCache(name);
if (cache == null) {
throw new NullPointerException(String.format("no cache with name %s defined, please configure it in %s", name, url));
}
Note 2:
笔记2:
If your configuration file is called ehcache.xml, you shouldn't use I think I've confused using CacheManager.create(url)
. Instead use the CacheManager singleton:CacheManager.create(url)
with and using new CacheManager(url)
. Still, you should use the singleton for ehcache.xml
and new CacheManager(url)
for anything else.
如果您的配置文件名为 ehcache.xml,则不应使用我想我混淆了 usingCacheManager.create(url)
. 而是使用 CacheManager 单例:CacheManager.create(url)
和 using new CacheManager(url)
。不过,你应该使用Singleton的ehcache.xml
和new CacheManager(url)
做别的事情。
// ehcache.xml - shared between different invocations
CacheManager defaultManager = CacheManager.getInstance();
// others - avoid calling twice with same argument
CacheManager manager = CacheManager.create(url);
Using CacheManager.create(..)
is problematic as it might completely ignore the passed URLif any of the create(..)
methods or getInstance()
have been called before:
使用CacheManager.create(..)
是有问题的,因为它可能会完全忽略传递的 URL,如果任何create(..)
方法或getInstance()
之前已被调用:
public static CacheManager create(URL configurationFileURL) throws CacheException {
synchronized (CacheManager.class) {
if (singleton == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating new CacheManager with config URL: " + configurationFileURL);
}
singleton = new CacheManager(configurationFileURL);
}
return singleton;
}
}
That's why I wouldn't recommend using any of the CacheManager.create(..)
methods. Use CacheManager.getInstance()
or new CacheManager(url)
.
这就是为什么我不建议使用任何CacheManager.create(..)
方法。使用CacheManager.getInstance()
或new CacheManager(url)
。
回答by Pascal Thivent
I suppose this will work, but I still wonder why programatically defined caches can't persist on disk (especially since they are still written to disk!)
我想这会起作用,但我仍然想知道为什么以编程方式定义的缓存不能保留在磁盘上(尤其是因为它们仍然写入磁盘!)
My understanding is that a programmatically created cache (i.e. not declared in ehcache.xml
) can use a DiskStore
that can itself be persistent but this doesn't mean that this cache will be loaded automatically by the CacheManager
uppon restart. Actually, I don't think the previously mentioned files do contain the cache parameters.
我的理解是,一个程序创建的缓存(即未声明ehcache.xml
),可以使用DiskStore
本身可以持续的,但这并不意味着该缓存将被自动加载CacheManager
uppon重启。实际上,我不认为前面提到的文件确实包含缓存参数。
But, if you "recreate" the cache programmatically with the same parameters, you'll find the previously cached entries back from the DiskStore
.
但是,如果您使用相同的参数以编程方式“重新创建”缓存,您会从DiskStore
.
回答by Eric Thorbjornsen
After spending some quality time with the debugger, I believe I have an answer for the OP.
在调试器上度过了一段美好的时光后,我相信我对 OP 有了一个答案。
The issue (at least from what I have seen) centers around the non-clustered disk cache files and how they get read back in. In the file net.sf.ehcache.store.compound.factories.DiskPersistentStorageFactory.java, the method:
问题(至少从我所看到的)集中在非集群磁盘缓存文件以及它们如何被读回。在文件 net.sf.ehcache.store.compound.factories.DiskPersistentStorageFactory.java 中,方法:
public DiskPersistentStorageFactory(Ehcache cache, String diskPath) {
super(getDataFile(diskPath, cache), cache.getCacheConfiguration().getDiskExpiryThreadIntervalSeconds(),
cache.getCacheConfiguration().getDiskSpoolBufferSizeMB(), cache.getCacheEventNotificationService(), false);
indexFile = new File(getDataFile().getParentFile(), getIndexFileName(cache));
flushTask = new IndexWriteTask(indexFile, cache.getCacheConfiguration().isClearOnFlush());
if (!getDataFile().exists() || (getDataFile().length() == 0)) {
LOG.debug("Matching data file missing (or empty) for index file. Deleting index file " + indexFile);
indexFile.delete();
} else if (getDataFile().exists() && indexFile.exists()) {
if (getDataFile().lastModified() > (indexFile.lastModified() + TimeUnit.SECONDS.toMillis(1))) {
LOG.warn("The index for data file {} is out of date, probably due to an unclean shutdown. "
+ "Deleting index file {}", getDataFile(), indexFile);
indexFile.delete();
}
}
diskCapacity = cache.getCacheConfiguration().getMaxElementsOnDisk();
memoryCapacity = cache.getCacheConfiguration().getMaxElementsInMemory();
memoryPolicy = determineEvictionPolicy(cache.getCacheConfiguration());
}
checks the timestamps on the data files. The problem I am seeing is that no matter how I end up shutting down the cache/manager, the files are never get synchronized properly. My quick and dirty workaround was to adjust the time of the data file to be just past the timestamp on the index file:
检查数据文件上的时间戳。我看到的问题是,无论我最终如何关闭缓存/管理器,文件都无法正确同步。我快速而肮脏的解决方法是将数据文件的时间调整为刚好超过索引文件上的时间戳:
File index = new File( path, name + ".index" );
File data = new File( path, name + ".data" );
data.setLastModified( index.lastModified() + 1 );
Granted, this is not elegant, but it serves my needs, as our project uses clustered caches, and this allows me to debug standalone with a persistent cache...and without having to actually run Terracotta locally.
诚然,这并不优雅,但它满足了我的需求,因为我们的项目使用集群缓存,这允许我使用持久缓存进行独立调试……而无需在本地实际运行 Terracotta。
One caveat is that for non-clustered caches, I do have to flush() after every put() and remove() in order to keep the disk image fresh, especially when debugging due to the lack of shutdown support when you just "pull the plug".
一个警告是,对于非集群缓存,我必须在每次 put() 和 remove() 之后刷新() 以保持磁盘映像新鲜,尤其是在调试时,由于缺少关闭支持而您只是“拉”插头”。
回答by Bruno Eberhard
Small hint if your cache on disk stays empty: Be sure your elements in the cache are serializable. ehcache does log if thats not the case but my log settings did not print out these log entries.
如果您在磁盘上的缓存保持为空的小提示:确保缓存中的元素是可序列化的。如果情况并非如此,ehcache 会记录日志,但我的日志设置没有打印出这些日志条目。
回答by fabian
this might be a little late but i had the same problem: what helped was to shutdown the cache manager.
这可能有点晚了,但我遇到了同样的问题:关闭缓存管理器有帮助。
(from the docu: http://ehcache.org/documentation/code-samples#ways-of-loading-cache-configuration)
(来自文档:http: //ehcache.org/documentation/code-samples#ways-of-loading-cache-configuration)
Shutdown the singleton CacheManager:
关闭单例 CacheManager:
CacheManager.getInstance().shutdown();
Shutdown a CacheManager instance, assuming you have a reference to the CacheManager called :
关闭 CacheManager 实例,假设您有一个对 CacheManager 的引用,称为:
manager.shutdown();
回答by Christian
This took me a while to figure out, but basically what needs to be done here is creating the CacheManager accordingly.
这花了我一段时间才弄明白,但基本上这里需要做的是相应地创建 CacheManager。
If you create the cache manager and the caches the same way how you created it in the xml it will work.
如果您创建缓存管理器和缓存的方式与您在 xml 中创建它的方式相同,它将起作用。
net.sf.ehcache.CacheManager manager = net.sf.ehcache.CacheManager
.create(new Configuration().diskStore(
new DiskStoreConfiguration().path("C:/mycache")
)
.cache(new CacheConfiguration()
.name(testName)
.eternal(true)
.maxBytesLocalHeap(10000, MemoryUnit.BYTES)
.maxBytesLocalDisk(1000000, MemoryUnit.BYTES)
.diskExpiryThreadIntervalSeconds(0)
.diskPersistent(true)));
回答by fustaki
I had and resolved a similar issue.
我有并解决了一个类似的问题。
I want to configure ehcache to have a given cache persisting elements on disk.
But I want to do it only in local environment (production environment works with a distributed
persistence) so I switch the configuration programmatically when the application starts (a web application in my case)
我想将 ehcache 配置为在磁盘上具有给定的缓存持久化元素。但是我只想在本地环境中执行此操作(生产环境具有distributed
持久性),因此我在应用程序启动时以编程方式切换配置(在我的情况下为 Web 应用程序)
File configurationFile = new File(event.getServletContext().getRealPath(EHCACHE_CONFIG_PATH));
Configuration configuration = ConfigurationFactory.parseConfiguration(configurationFile);
//...doing other stuff here...
CacheConfiguration cacheConfiguration = configuration.getCacheConfigurations().get("mycachename");
if(localEnvironment){
cacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.DISTRIBUTED));
}else{
//siteCacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.LOCALRESTARTABLE));
//deprecated lines..
siteCacheConfiguration.setDiskPersistent(true);
siteCacheConfiguration.setOverflowToDisk(true);
}
I had problem with the commented line siteCacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.LOCALRESTARTABLE))
, in fact Ehcache code (I'm using ehcache-2.6.11
) throws an Exception if you use Strategy.LOCALRESTARTABLE
without an enterprise version of the jar:
我对注释行有问题siteCacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.LOCALRESTARTABLE))
,实际上,ehcache-2.6.11
如果您在Strategy.LOCALRESTARTABLE
没有企业版 jar 的情况下使用 Ehcache 代码(我正在使用),则会抛出异常:
CacheException: You must use an enterprise version of Ehcache to successfully enable enterprise persistence.
Digging into the code I realized that these two (deprecated) lines do the same eluding the entreprise version Exception
深入研究代码,我意识到这两条(已弃用)行在避开企业版异常的情况下也做同样的事情
siteCacheConfiguration.setDiskPersistent(true);
siteCacheConfiguration.setOverflowToDisk(true);
Remember to add CacheManager.getInstance().shutdown()
on the shutdown of the application!
记得CacheManager.getInstance().shutdown()
在关闭应用时添加!
Hope this helps.
希望这可以帮助。