28

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

そして、ここに私のキャッシュ構成(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>

最初の実行後にディスク上に test.index および test.data ファイルが表示されますが、この関数からの出力は常に次のようになります (ディスクからキャッシュをロードすることはないようです)。

キャッシュが見つかりません。キャッシュを作成しています...
ディスクにキャッシュします。ディスク上のキャッシュ サイズ: 2

私はここでばかげたことをしているに違いありませんが、何がわからないのですか!

4

8 に答える 8

18

さて、これを修正するために私がしたことは、構成ファイルを使用してキャッシュを構成することでした。更新された構成は次のとおりです。

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

したがって、基本的に、コンストラクターを使用してキャッシュを定義しませんでした。

これでうまくいくと思いますが、なぜプログラムで定義されたキャッシュがディスク上に保持できないのか疑問に思っています (特に、まだディスクに書き込まれているためです!)。

コメントありがとうございます。

于 2009-11-13T16:38:59.573 に答える
5

デバッガーで充実した時間を過ごした後、OP に対する答えがあると思います。

問題 (少なくとも私が見たものから) は、クラスター化されていないディスク キャッシュ ファイルと、それらがどのように読み込まれるかを中心にしています。

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

データ ファイルのタイムスタンプをチェックします。私が見ている問題は、どのようにキャッシュ/マネージャーをシャットダウンしても、ファイルが正しく同期されないことです。私の手っ取り早い回避策は、データ ファイルの時刻をインデックス ファイルのタイムスタンプの直後になるように調整することでした。

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

data.setLastModified( index.lastModified() + 1 );

確かに、これはエレガントではありませんが、私たちのプロジェクトはクラスター化されたキャッシュを使用しているため、私のニーズには応えます。これにより、永続的なキャッシュを使用してスタンドアロンでデバッグできます...そして実際に Terracotta をローカルで実行する必要はありません。

1 つの注意点は、クラスター化されていないキャッシュの場合、特に "pullプラグ」。

于 2010-09-10T21:51:48.930 に答える
4

これを理解するのにしばらく時間がかかりましたが、基本的にここで行う必要があるのは、それに応じて CacheManager を作成することです。

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)));
于 2014-11-04T15:56:09.017 に答える
2

これは少し遅れているかもしれませんが、私は同じ問題を抱えていました.何が助けになったかは、キャッシュマネージャーをシャットダウンすることでした.

(ドキュメントから: http://ehcache.org/documentation/code-samples#ways-of-loading-cache-configuration )

シングルトン CacheManager をシャットダウンします。

CacheManager.getInstance().shutdown();

という名前の CacheManager への参照があると仮定して、CacheManager インスタンスをシャットダウンします。

manager.shutdown();
于 2012-12-27T11:03:04.610 に答える
1

テストを削除し、代わりに を使用しmanager.cacheExists(..)てキャッシュを作成する必要があると思います。キャッシュが diskPersistent であっても、最初に取得するまで存在しません。(少なくともそれは私が使用しているだけであり、あなたが探していることを正確に行うと私が思うことです)testCache = manager.getCache("test");new Cache(..)getCache(..)

ノート:

次のようなものを追加して、キャッシュが存在することを確認することもできます。

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

注 2:

構成ファイルの名前が ehcache.xml の場合は、CacheManager.create(url). 代わりに CacheManager シングルトンを使用CacheManager.create(url)してくださいnew CacheManager(url)。それでも、シングルトンを他の目的で使用する必要があり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);

メソッドのいずれかまたはが以前に呼び出された場合、渡された URL を完全に無視する可能性があるため、使用CacheManager.create(..)には問題があります。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;
    }
}

そのため、どのCacheManager.create(..)方法を使用することもお勧めしません。CacheManager.getInstance()またはを使用しnew CacheManager(url)ます。

于 2009-11-13T14:56:29.383 に答える
1

ディスク上のキャッシュが空のままの場合の小さなヒント: キャッシュ内の要素がシリアライズ可能であることを確認してください。そうでない場合でも ehcache はログに記録しますが、私のログ設定ではこれらのログ エントリが出力されませんでした。

于 2012-06-14T10:12:04.137 に答える
0

これでうまくいくと思いますが、なぜプログラムで定義されたキャッシュがディスクに保存されないのか疑問に思っています (特に、まだディスクに書き込まれているためです!)。

私の理解では、プログラムで作成されたキャッシュ (つまり、 で宣言されていないehcache.xml) は、それ自体が永続的な を使用DiskStoreできますが、これは、このキャッシュがCacheManager再起動時に自動的に読み込まれるという意味ではありません。実際、前述のファイルにキャッシュ パラメータが含まれているとは思いません。

ただし、同じパラメーターを使用してプログラムでキャッシュを「再作成」すると、以前にキャッシュされたエントリがDiskStore.

于 2009-11-13T16:52:11.117 に答える