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
Я должен делать что-то немое здесь, но я не уверен, что!
Ответы
Ответ 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()
при завершении работы приложения!
Надеюсь, что это поможет.