ehcache坚持磁盘问题

hro*_*oss 27 java persistence ehcache ehcache-2

我想用Java中的ehcache做一些我认为应该非常简单的事情,但是我花了足够的时间来挫败自己的文档......

  1. 将值写入磁盘永久缓存.关掉.

  2. 再次启动并读取该值.

这是我的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();
}
Run Code Online (Sandbox Code Playgroud)

这是我的缓存配置(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>
Run Code Online (Sandbox Code Playgroud)

即使我在第一次运行后在磁盘上看到test.index和test.data文件,此函数的输出始终如下(它似乎永远不会从磁盘加载缓存):

找不到缓存.创建缓存...
缓存到磁盘.磁盘上的缓存大小:2

我必须在这里做一些蠢事,但我不确定是什么!

hro*_*oss 17

好吧,我所做的就是使用配置文件配置我的缓存.这是更新的配置:

<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>
Run Code Online (Sandbox Code Playgroud)

所以基本上我没有使用构造函数来定义缓存.

我想这可行,但我仍然想知道为什么编程定义的缓存不能在磁盘上持久存在(特别是因为它们仍然写入磁盘!).

谢谢你的评论.


Eri*_*sen 5

在花了一些时间与调试器,我相信我有一个OP的答案.

问题(至少从我所看到的)围绕非群集磁盘缓存文件以及它们如何被读回.在文件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());
}
Run Code Online (Sandbox Code Playgroud)

检查数据文件的时间戳.我看到的问题是,无论我最终如何关闭缓存/管理器,文件永远不会正确同步.我快速而又肮脏的解决方法是将数据文件的时间调整为刚刚超过索引文件的时间戳:

File index = new File( path, name + ".index" );
File data  = new File( path, name + ".data"  );

data.setLastModified( index.lastModified() + 1 );
Run Code Online (Sandbox Code Playgroud)

当然,这并不优雅,但它满足了我的需求,因为我们的项目使用集群缓存,这使我可以使用持久缓存独立调试......而无需在本地运行Terracotta.

需要注意的是,对于非群集缓存,我必须在每次put()和remove()之后刷新()以保持磁盘映像新鲜,特别是在调试时由于缺少关闭支持而导致插头".