Подтвердить что ты не робот

Ehcache сохраняется на дисках

Я хочу сделать что-то с ehcache в Java, которое, я думаю, должно быть предельно простым, но я потратил достаточно времени, разочаровывая себя документами...

  • Введите значение в постоянный кеш диска. Выключите.

  • Запустите еще раз и прочитайте это значение.

Вот моя 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

Я должен делать что-то немое здесь, но я не уверен, что!

4b9b3361

Ответ 1

Хорошо, ну, что я сделал, чтобы исправить это, я сконфигурировал свой кеш, используя файл конфигурации. Вот обновленная конфигурация:

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

В основном я не использовал конструктор для определения кеша.

Я предполагаю, что это сработает, но я все еще задаюсь вопросом, почему программно определенные кеши не могут сохраняться на диске (тем более, что они все еще записаны на диск!).

Спасибо за комментарии ребята.

Ответ 2

Проведя некоторое время с отладчиком, я считаю, что у меня есть ответ для 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());
}

проверяет метки времени на файлах данных. Проблема, которую я вижу, заключается в том, что независимо от того, как я заканчиваю закрытие кэша/менеджера, файлы никогда не синхронизируются должным образом. Моим быстрым и грязным обходным решением было настроить время файла данных как раз мимо метки времени в файле индекса:

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

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

Конечно, это не изящно, но оно служит моим потребностям, так как наш проект использует кластерные кеши, и это позволяет мне отлаживать автономный с постоянным кешем... и без фактического запуска Terracotta локально.

Одно из предостережений заключается в том, что для некластеризованных кешей мне нужно очищать() после каждого put() и remove(), чтобы сохранить образ диска свежим, особенно при отладке из-за отсутствия поддержки завершения, когда вы просто "вытащить вилку".

Ответ 3

это может быть немного поздно, но у меня была та же проблема: что помогло закрыть диспетчер кэша.

(из документа: http://ehcache.org/documentation/code-samples#ways-of-loading-cache-configuration)

Выключение одноэлементного CacheManager:

CacheManager.getInstance().shutdown();

Выключите экземпляр CacheManager, предположив, что у вас есть ссылка на вызываемый CacheManager:

manager.shutdown();

Ответ 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)));

Ответ 5

Я думаю, вы должны удалить тест manager.cacheExists(..) и просто создать свой кеш с помощью testCache = manager.getCache("test"); вместо использования new Cache(..). Даже если ваш кеш является diskPersistent, он не будет существовать, пока вы не получите его в первый раз. (По крайней мере, это то, что я думаю, поскольку я использую только 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);

Использование 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;
    }
}

Вот почему я бы не рекомендовал использовать какой-либо из методов CacheManager.create(..). Используйте CacheManager.getInstance() или new CacheManager(url).

Ответ 6

Небольшая подсказка, если ваш кэш на диске остается пустым: убедитесь, что ваши элементы в кеше сериализуемы. ehcache делает журнал, если это не так, но мои настройки журнала не распечатывали эти записи журнала.

Ответ 7

Я предполагаю, что это сработает, но я все еще задаюсь вопросом, почему программно определенные кеши не могут сохраняться на диске (тем более, что они все еще записаны на диск!)

Я понимаю, что программно созданный кэш (т.е. не объявленный в ehcache.xml) может использовать DiskStore, который может быть постоянным, но это не означает, что этот кеш будет автоматически загружаться с помощью CacheManager uppon перезапуск. На самом деле, я не думаю, что ранее упомянутые файлы содержат параметры кэша.

Но, если вы "обновляете" кэш программно с теми же параметрами, вы найдете ранее кэшированные записи из DiskStore.

Ответ 8

У меня была и разрешена аналогичная проблема.

Я хочу настроить ehcache на наличие заданных элементов кэша на диске. Но я хочу сделать это только в локальной среде (рабочая среда работает с сохранением distributed), поэтому я программно переключаю конфигурацию при запуске приложения (в моем случае веб-приложение)

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

У меня была проблема с прокомментированной строкой siteCacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.LOCALRESTARTABLE)), на самом деле код Ehcache (я использую ehcache-2.6.11) генерирует исключение, если вы используете Strategy.LOCALRESTARTABLE без корпоративной версии jar:

CacheException: You must use an enterprise version of Ehcache to successfully enable enterprise persistence.

Копаясь в коде, я понял, что эти две (устаревшие) строки делают то же самое, что ускользают от версии Entreprise Exception

siteCacheConfiguration.setDiskPersistent(true);
siteCacheConfiguration.setOverflowToDisk(true);

Не забудьте добавить CacheManager.getInstance().shutdown() при завершении работы приложения!

Надеюсь, что это поможет.