2010-03-03 16 views
5

Sto utilizzando una cache con persistenza del disk store. Alle successive repliche di app sto ottenendo il seguente errore:Ehcache disk store unclean shutdown

net.sf.ehcache.store.DiskStore deleteIndexIfCorrupt 
WARNING: The index for data file MyCache.data is out of date, 
probably due to an unclean shutdown. Deleting index file MYCache.index 

C'è un modo per risolvere che, oltre a chiamare esplicitamente net.sf.ehcache.CacheManager.shutdown() da qualche parte in app?

configurazione cache:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:noNamespaceSchemaLocation="ehcache.xsd" 
      updateCheck="true" monitoring="autodetect"> 

    <diskStore path="C:\work"/> 

    <cacheManagerEventListenerFactory class="" properties=""/> 

    <cacheManagerPeerProviderFactory 
      class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory" 
      properties="peerDiscovery=automatic, 
         multicastGroupAddress=230.0.0.1, 
         multicastGroupPort=4446, timeToLive=1" 
      propertySeparator="," 
      /> 

    <cacheManagerPeerListenerFactory 
      class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/> 

    <defaultCache 
      maxElementsInMemory="1" 
      eternal="false" 
      timeToIdleSeconds="0" 
      timeToLiveSeconds="86400" 
      overflowToDisk="true" 
      diskSpoolBufferSizeMB="1" 
      maxElementsOnDisk="10000" 
      diskPersistent="true" 
      diskExpiryThreadIntervalSeconds="120" 
      memoryStoreEvictionPolicy="LFU" 
      /> 

</ehcache> 

Codice di replicare il problema:

import java.util.ArrayList; 
import java.util.List; 

import net.sf.ehcache.Cache; 
import net.sf.ehcache.CacheManager; 
import net.sf.ehcache.Element; 

public class CacheTest { 
    static CacheManager manager = new CacheManager(CacheTest.class 
      .getResource("ehcache.xml")); 
    static Cache cache; 

    public static void main(String[] args) { 

     // Get a default instance 
     manager.addCache("test"); 
     cache = manager.getCache("test"); 

     // Generate some junk so that the 
     // cache properly flushes to disk 
     // as cache.flush() is not working 
     List<String> t = new ArrayList<String>(); 
     for (int i = 0; i < 1000; i++) 
      t.add(null); 
     // Oddly enough fewer elements 
     // do not persist to disk or give 
     // an error 
     for (int i = 0; i < 100000; i++) { 
      cache.put(new Element(i, t)); 
     } 
     cache.flush(); 

     if (cache.get("key1") == null) { 
      System.out.println("key1 not found in cache!"); 
      cache.put(new Element("key1", "value1")); 
     } 

     System.out.println(cache.get("key1")); 
    } 
} 

risposta

12

provare a impostare la proprietà di sistema: net.sf.ehcache.enableShutdownHook = true

Quindi, è possibile aggiungere la seguente riga all'inizio del programma: System.setProperty("net.sf.ehcache.enableShutdownHook","true");

Oppure, dalla riga di comando per passare la proprietà: java -Dnet.sf.ehcache.enableShutdownHook=true ...

Nota, il sito Web di ehcache fa molta attenzione quando si utilizza questo hook di arresto: Shutting Down Ehcache

When a shutdown hook will run, and when it will not

The shutdown hook runs when:

  • a program exists normally. e.g. System.exit() is called, or the last non-daemon thread exits
  • the Virtual Machine is terminated. e.g. CTRL-C. This corresponds to kill -SIGTERM pid or kill -15 pid on Unix systems.

The shutdown hook will not run when:

  • the Virtual Machine aborts
  • A SIGKILL signal is sent to the Virtual Machine process on Unix systems. e.g. kill -SIGKILL pid or kill -9 pid
  • A TerminateProcess call is sent to the process on Windows systems.

spero che funziona :)

+0

Yay, ha funzionato. Grazie! :) – Tomasz

2

Come stai fermando la vostra applicazione?

Dall'esame del codice Ehcache, registra un hook di arresto JVM Runtime.getRuntime().addShutdownHook che chiude la cache all'uscita JVM. Se la JVM viene uccisa o si blocca, il gancio di arresto non verrà chiamato.

Aggiornamento RE tuo commento:

Ecco il commento dal metodo DiskStore dispose:

Shuts down the disk store in preparation for cache shutdown

If a VM crash happens, the shutdown hook will not run. The data file and the index file will be out of synchronisation. At initialisation we always delete the index file after we have read the elements, so that it has a zero length. On a dirty restart, it still will have and the data file will automatically be deleted, thus preserving safety.

Quindi, se il vostro ricreare la cache in un diverso test di unità. Poiché shutdownHook non sarebbe stato eseguito, il file di indice sarà 0. Ehcache pensa che l'indice sia corrotto. Vorrei chiudere la cache usando l'annotazione di @Unit di JUnit in ciascuno dei tuoi test di unità. Oppure, condividi la cache in tutti i test, ma suppongo che questo non ti fornisca test isolati.

+0

Lo sto eseguendo come parte di un test di Junit4. L'errore viene mostrato in una successiva riesecuzione del test. Posso fornire un esempio di codice da replicare se aiuta. – Tomasz

+0

Ho aggiornato la domanda in base al tuo commento. –

+0

no, continuando a ottenere lo stesso errore, anche quando si esegue da una riga di comando in un jar eseguibile. – Tomasz

0

Per quelli di noi utilizzando EHCache con la Primavera 3.1+ e Java di configurazione, è necessario utilizzare:

@Bean(destroyMethod = "shutdown") 
public net.sf.ehcache.CacheManager ehCacheManager() { .. } 

e (supponendo che si sta anche utilizzando Spring ApplicationContext non web, abilita l'hook di shutdown per far sì che il bean venga distrutto in modo elegante:

context = new AnnotationConfigApplicationContext(AppConfig.class); 
((AbstractApplicationContext) context).registerShutdownHook(); 

vedere this per ulteriori informazioni.