web-dev-qa-db-fra.com

eHcache persiste aux problèmes de disque

Je veux faire quelque chose avec Ehcache in Java que je pense être extrêmement simple, mais j'ai passé assez de temps frustrant moi-même avec les docs ...

  1. Écrivez une valeur à un cache persistant disque. Fermer.

  2. Commencez à nouveau et lisez cette valeur.

Voici mon Java Fonction:

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

Et voici ma configuration de cache (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>

Même si je vois des fichiers test.index et test.data sur disque après la première exécution, la sortie de cette fonction est toujours ce qui suit (il ne semble jamais charger le cache du disque):

Aucun cache trouvé. Création de cache ...
Cache sur le disque. Taille de cache sur le disque: 2

Je dois faire quelque chose d'idiot ici, mais je ne suis pas sûr de quoi!

26
hross

Ok, bien ce que j'ai fait pour résoudre ce problème, configurez mon cache à l'aide du fichier de configuration. Voici la configuration mise à jour:

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

Donc, fondamentalement, je n'ai pas utilisé le constructeur pour définir le cache.

Je suppose que cela fonctionnera, mais je me demande toujours pourquoi les caches définies par programme ne peuvent pas persister sur le disque (surtout car ils sont toujours écrits sur le disque!).

Merci pour les commentaires, les gens.

17
hross

Après avoir passé du temps de qualité avec le débogueur, je crois avoir une réponse pour l'OP.

Le problème (au moins de ce que j'ai vu) centres autour des fichiers de cache de disque non cluster et comment ils sont rétablis dans le fichier net.sf.ehcache.store.compound.factories.diskpersistentStorageFactory.java, la méthode:

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

vérifie les horodatages sur les fichiers de données. Le problème que je vois, c'est que peu importe la façon dont je finis par fermer le cache/gestionnaire, les fichiers ne sont jamais synchronisés correctement. Ma solution de contournement rapide et sale était d'ajuster l'heure du fichier de données pour être juste après l'horodatage sur le fichier d'index:

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

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

Certes, ce n'est pas élégant, mais cela sert mes besoins, comme notre projet utilise des caches en clusters, ce qui me permet de déboguer autonome avec un cache persistant ... et sans avoir à courir en terre cuite localement.

Une mise en garde est que pour les caches non groupées, je dois affleurer () après chaque put () et supprimer () afin de garder l'image disque fraîche, en particulier lors du débogage en raison du manque de support d'arrêt lorsque vous venez de "tirer la prise".

5
Eric Thorbjornsen

Cela m'a pris un certain temps pour comprendre, mais essentiellement ce qui doit être fait ici, c'est la création du Cachemanager en conséquence.

Si vous créez le responsable du cache et les caches de la même manière ainsi que vous l'avez créée dans le XML, cela fonctionnera.

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)));
3
Christian

cela pourrait être un peu en retard mais j'avais le même problème: ce qui a contribué à arrêter le responsable du cache.

(de la docum: - http://ehcache.org/documentation/code-samples#ways-ofloading-cache-configuration )

Shutdown The Singleton Cachemanager:

CacheManager.getInstance().shutdown();

Arrêtez une instance Cachemanager, en supposant que vous avez une référence au Cachemanager appelé:

manager.shutdown();
2
fabian

J'avais et résolu un problème similaire.

Je veux configurer EHCache pour avoir un cache donné des éléments persistants sur le disque. Mais je veux le faire uniquement dans l'environnement local (l'environnement de production fonctionne avec une persistance distributed), donc je change la configuration par programme lorsque l'application commence (une application Web dans mon cas)

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

J'ai eu un problème avec la ligne commentée siteCacheConfiguration.addPersistence(new PersistenceConfiguration().strategy(Strategy.LOCALRESTARTABLE)), le code ehcache (j'utilise ehcache-2.6.11) jette une exception si vous utilisez Strategy.LOCALRESTARTABLE sans une version d'entreprise du pot:

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

Creuser dans le code que j'ai réalisé que ces deux lignes (obsolètes) font la même chose éludant l'exception de la version Entreprise

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

N'oubliez pas d'ajouter CacheManager.getInstance().shutdown() sur l'arrêt de l'application!

J'espère que cela t'aides.

1
fustaki

Petit indice Si votre cache sur disque reste vide: assurez-vous que vos éléments dans le cache sont sérialisables. Ehcache connecte si ce n'est pas le cas, mais mes paramètres de journal n'ont pas imprimé ces entrées de journal.

1
Bruno Eberhard

Je pense que vous devriez supprimer le test manager.cacheExists(..) _ et créer simplement votre cache à l'aide de testCache = manager.getCache("test"); au lieu d'utiliser new Cache(..). Même si votre cache est diskpercersiste, il n'existe pas avant de l'obtenir la première fois. (Au moins c'est ce que je pense que je pense que je n'utilise que getCache(..) et cela fait exactement ce que vous recherchez)

Noter:

Vous pouvez également ajouter quelque chose comme ça pour vous assurer que le cache existe:

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:

Si votre fichier de configuration est appelé ehcache.xml, vous ne devez pas utiliser CacheManager.create(url). Utilisez plutôt le Cachemanager Singleton: Je pense que j'ai confondu avec CacheManager.create(url) avec et en utilisant new CacheManager(url). Pourtant, vous devez utiliser le singleton pour ehcache.xml Et new CacheManager(url) pour autre chose.

// ehcache.xml - shared between different invocations
CacheManager defaultManager = CacheManager.getInstance();
// others - avoid calling twice with same argument
CacheManager manager = CacheManager.create(url);

L'utilisation de CacheManager.create(..) est problématique comme elle pourrait ignorer complètement l'URL transcédée Si l'une des méthodes create(..) ou getInstance() ont été appelées avant:

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

C'est pourquoi je ne recommanderais pas d'utiliser l'une des méthodes CacheManager.create(..). Utilisez CacheManager.getInstance() ou new CacheManager(url).

1
sfussenegger

Je suppose que cela fonctionnera, mais je me demande toujours pourquoi les caches définies par programme ne peuvent pas persister sur le disque (surtout car ils sont toujours écrits sur le disque!)

Ma compréhension est qu'un cache créé par programme (c'est-à-dire non déclaré dans ehcache.xml) Peut utiliser un DiskStore qui peut lui-même persister, mais cela ne signifie pas que ce cache sera chargé automatiquement par le redémarrage CacheManager UPPON. En fait, je ne pense pas que les fichiers mentionnés précédemment contiennent les paramètres de cache.

Mais si vous "recréez" le cache de manière programmatique avec les mêmes paramètres, vous trouverez les entrées précédemment mises en cache à partir du DiskStore.

0
Pascal Thivent