r3855 - in trunk: . src/main/java/fr/ifremer/isisfish src/main/java/fr/ifremer/isisfish/util
Author: bpoussin Date: 2013-11-27 15:42:28 +0100 (Wed, 27 Nov 2013) New Revision: 3855 Url: http://forge.codelutin.com/projects/isis-fish/repository/revisions/3855 Log: add support for different backend for IsisCache available: - old with commons-collection and Soft reference - new with guava cache (and space computation) Added: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCache.java trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackend.java trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnGuava.java trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnReferenceMap.java Removed: trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java Modified: trunk/pom.xml trunk/src/main/java/fr/ifremer/isisfish/IsisConfig.java trunk/src/main/java/fr/ifremer/isisfish/IsisFish.java Modified: trunk/pom.xml =================================================================== --- trunk/pom.xml 2013-11-27 10:36:14 UTC (rev 3854) +++ trunk/pom.xml 2013-11-27 14:42:28 UTC (rev 3855) @@ -392,6 +392,14 @@ <scope>compile</scope> </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + <version>15.0</version> + </dependency> + + + <!-- Tests --> <dependency> <groupId>junit</groupId> Modified: trunk/src/main/java/fr/ifremer/isisfish/IsisConfig.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/IsisConfig.java 2013-11-27 10:36:14 UTC (rev 3854) +++ trunk/src/main/java/fr/ifremer/isisfish/IsisConfig.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -58,6 +58,8 @@ import fr.ifremer.isisfish.simulator.launcher.SSHSimulatorLauncher; import fr.ifremer.isisfish.simulator.launcher.SimulationService; import fr.ifremer.isisfish.simulator.launcher.SubProcessSimulationLauncher; +import fr.ifremer.isisfish.util.IsisCacheBackend; +import fr.ifremer.isisfish.util.IsisCacheBackendOnGuava; import fr.ifremer.isisfish.vcs.VCS; /** @@ -928,7 +930,7 @@ /** * L'implementation de la class gérant les implémentations de vecteur de * matrice pour les fichiers mappés. - * + * * @return * @since 4.2.1.1 */ @@ -937,6 +939,18 @@ return result; } + /** + * Retourne la factory a utilise pour le cache + * + * @return factory a utilise pour le backend de cache + * @since 4.2.1.2 + */ + public IsisCacheBackend.Factory getCacheBackendFactoryClass() { + IsisCacheBackend.Factory result = getOptionAsObject( + IsisCacheBackend.Factory.class, Option.CACHE_BACKEND_FACTORY_CLASS.key); + return result; + } + ////////////////////////////////////////////////// // Toutes les options disponibles ////////////////////////////////////////////////// @@ -1043,7 +1057,8 @@ USER_NAME("user.name", n_("isisfish.config.main.userName.description"), System.getProperty("user.name")), SMTP_SERVER("smtpServer", n_("isisfish.config.main.smtpServer.description"), "smtp"), USER_MAIL("userMail", n_("isisfish.config.main.userMail.description"), USER_NAME.key + "@" + VCS_HOST_NAME.key), - MAPPED_RESULT_MATRIX_VECTOR_CLASS("mapped.result.matrix.vector.class", n_("isisfish.config.mapped.result.matrix.vector.class.description"), DoubleBigVector.class.getName()); + MAPPED_RESULT_MATRIX_VECTOR_CLASS("mapped.result.matrix.vector.class", n_("isisfish.config.mapped.result.matrix.vector.class.description"), DoubleBigVector.class.getName()), + CACHE_BACKEND_FACTORY_CLASS("cache.backend.factory.class", n_("isisfish.config.cache.backend.factory.class.description"), IsisCacheBackendOnGuava.IsisCacheBackendOnGuavaFactory.class.getName()); public String key; public String description; Modified: trunk/src/main/java/fr/ifremer/isisfish/IsisFish.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/IsisFish.java 2013-11-27 10:36:14 UTC (rev 3854) +++ trunk/src/main/java/fr/ifremer/isisfish/IsisFish.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -78,6 +78,7 @@ import fr.ifremer.isisfish.ui.WelcomeTabUI; import fr.ifremer.isisfish.ui.WelcomeUI; import fr.ifremer.isisfish.ui.util.ErrorHelper; +import fr.ifremer.isisfish.util.IsisCache; import fr.ifremer.isisfish.util.IsisMatrixSemanticMapper; import fr.ifremer.isisfish.vcs.VCS; import fr.ifremer.isisfish.vcs.VCSActionEvent; @@ -243,6 +244,9 @@ I18n.init(new ClassPathI18nInitializer(), config.getLocale()); } + // init cache backend + IsisCache.defaultFactory = config.getCacheBackendFactoryClass(); + // after init shutdown hook Runtime.getRuntime().addShutdownHook(new IsisQuitHook()); } Deleted: trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java 2013-11-27 10:36:14 UTC (rev 3854) +++ trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -1,291 +0,0 @@ -/* - * #%L - * IsisFish - * - * $Id$ - * $HeadURL$ - * %% - * Copyright (C) 2006 - 2010 Ifremer, Code Lutin, Cédric Pineau, Benjamin Poussin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -package fr.ifremer.isisfish.util; - -import fr.ifremer.isisfish.IsisFishRuntimeException; -import fr.ifremer.isisfish.simulator.SimulationContext; -import fr.ifremer.isisfish.types.TimeStep; -import java.lang.reflect.Method; -import java.util.Map; -import org.apache.commons.collections.map.ReferenceMap; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.codehaus.aspectwerkz.joinpoint.JoinPoint; -import org.nuiton.topia.persistence.TopiaEntity; - -/** - * Cache utilise pour mettre les resultats de methode durant la simulation - * pour minimiser les appels - * - * Created: 25 août 06 22:42:47 - * - * @author poussin - * @version $Revision$ - * - * Last update: $Date$ - * by : $Author$ - */ -public class Cache { - - /** to use log facility, just put in your code: log.info(\"...\"); */ - static private Log log = LogFactory.getLog(Cache.class); - - // la longueur du package pour minimiser la longueur des topiaId - static final private int entityPackageLenght = "fr.ifremer.isisfish.entities.".length(); - // la valeur NULL a utilise a la place de null pour les timeStep - static final private Object NULL = new Object(); - -// static private List<CacheAspect> instances = new ArrayList<CacheAspect>(); - - protected long totalCall = 0; - protected long cacheUsed = 0; - - /** - * map<TimeStep, Map<Key, Value>> - * TimeStep peut etre null via l'objet NULL - * Key est la cle calcule par computeKey - * Value est la valeur du cache - * - * TimeStep est en WEAK pour que des que l'on passe au pas de temps suivant - * ils soit efface de la memoire si plus personne n'a de reference sur - * ce pas de temps. L'autre moyen est de force l'effacement via clear(TimeStep) - * - * Value est en SOFT reference pour que les valeurs soit effacee du cache - * lorsqu'il n'y a plus de place memoire - */ - protected Map cache = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD); -// protected Map cache = new AdaptaptativeCache(1000, 95); - - public Cache() { - } - - /** - * Return trace object from context. - * - * @return trace object from context - */ - protected Trace getTrace() { - SimulationContext context = SimulationContext.get(); - Trace result = context.getTrace(); - return result; - } - - /** - * Recupere pour un pas de temps donnes une valeur calcule pour une cle - * @param step le pas de temps pour lequel on souhaite ajouter (ou null) - * @param key la cle de storage - * @param defaultValue la valeur par defaut a retourner si elle n'est pas en cache - * si defaultValue est une JoinPoint alors un proceed est appele dessus et le - * resultat de l'appel est utiliser comme valeur par defaut - * @return la valeur dans le cache ou defaultValue - */ - public Object get(Method method, Object[] args, Object defaultValue) throws Throwable { - totalCall++; - - Object result = null; - if (method.getAnnotation(Nocache.class) != null || - method.getDeclaringClass().getAnnotation(Nocache.class) != null) { - result = realCall(defaultValue); - } else { - // compute key and keep TimeStep objet - StringBuilder sbKey = new StringBuilder(); - // le pas de temps trouve dans les arguments - TimeStep step = computeKey(sbKey, method, args); - - // on recupere le intern de la String car normalement en cache on - // retrouve souvent les memes chaines comme cle (sinon le cache - // servirait a rien :D) - Object key = sbKey.toString().intern(); - result = get(step, key); - if (result == null) { - - // computation increment (/ by 0) - // FIXME need to be called, but fail with empty stack - //getTrace().traceAfterComputation(method); - - result = realCall(defaultValue); - if (result != null) { // util pour les methodes retournant void, ne fonctionne pas si on met AND !execute(void *(..)) dans l'aspect. En fait fonction seulement si utilisé avec les traces :( - put(step, key, result); - } - } else { - cacheUsed++; - } - } - return result; - } - - protected TimeStep computeKey(StringBuilder sbKey, Method method, Object[] args) { - TimeStep result = null; - sbKey.append(method.getDeclaringClass().getSimpleName()); - sbKey.append("."); - sbKey.append(method.getName()); - for (Object o : args) { - sbKey.append(";"); - if (o == null) { - sbKey.append("null"); - } else if (o instanceof Number || o instanceof String) { - sbKey.append(o.toString()); - } else if (o instanceof TimeStep) { - result = (TimeStep)o; - sbKey.append(((TimeStep)o).getStep()); - } else if (o instanceof TopiaEntity) { - sbKey.append( ((TopiaEntity)o).getTopiaId().substring(entityPackageLenght)); - } else { - // on minimise en prenant que le nom de la classe (pas le package) - sbKey.append(o.getClass().getSimpleName()); - sbKey.append('@'); - // et en lui ajoutant son adresse memoire en Hexa - sbKey.append(Integer.toHexString(System.identityHashCode(o))); - } - } - return result; - } - - protected Map getCacheTimeStep(TimeStep step) { - Object key = step; - if (step == null) { - key = NULL; - } - Map result = (Map)cache.get(key); - if (result == null) { - result = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); - cache.put(key, result); - } - return result; - } - - protected Object get(TimeStep step, Object key) { - Object result = null; - Map cacheTimeStep = getCacheTimeStep(step); - if (cacheTimeStep != null) { - result = cacheTimeStep.get(key); - } - return result; - } - - protected void put(TimeStep step, Object key, Object value) { - getCacheTimeStep(step).put(key, value); - } - - /** - * On fait l'appel reel dans une autre methode pour pouvoir le savoir - * dans les traces - * - * @param jp - * @return ? - * @throws Throwable - */ - protected Object realCall(Object defaultValue) throws Throwable { - Object result = defaultValue; - if (defaultValue instanceof JoinPoint) { - result = ((JoinPoint)defaultValue).proceed(); - } - return result; - } - - /** - * remove all values in cache - */ - public void clear() { - cache.clear(); - } - - /** - * remove all values in cache for the specied TimeStep - */ - public void clear(TimeStep step) { - Object key = step; - if (key == null) { - key = NULL; - } - cache.remove(key); - } - - /** - * @return Returns the cacheUsed. - */ - public long getCacheUsed() { - long result = cacheUsed; - return result; - } - - /** - * @return Returns the totalCall. - */ - public long getTotalCall() { - long result = totalCall; - return result; - } - - /** - * Affiche les statistiques - * - */ - public String printStatistiqueAndClear() { - StringBuilder result = new StringBuilder(); - result.append("--- Cache Statistiques ---\n"); - result.append("Total call: ").append(totalCall).append("\n"); - result.append("Cache used: ").append(cacheUsed).append("\n"); - long percent = 0; - if (totalCall != 0) { - percent = 100*cacheUsed/totalCall; - } - result.append("Cache usage: ").append(percent).append("%\n"); - result.append("--------------------\n"); - cache.clear(); - - System.out.println(result.toString()); - return result.toString(); - } - - // EN COURS D'ECRITURE MAIS JAMAIS FINI :( - // l'idee est de prendre la place memoire qu'il y a, mais s'il n'y en - // a plus on commence par enlever les objets les plus vieux -// class AdaptaptativeCache extends LinkedHashMap<String, Object> { -// protected int maxMemory = 95; -// /** -// * -// * @param capacity initial capacity -// * @param maxMemory maximum memory used (0-100) -// */ -// public AdaptaptativeCache(int capacity, int maxMemory) { -// super(capacity, 0.75f, true); -// this.maxMemory = maxMemory; -// } -// -// /* (non-Javadoc) -// * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) -// */ -// @Override -// protected boolean removeEldestEntry(Entry<String, Object> eldest) { -// double free = 100.0 * Runtime.getRuntime().freeMemory() / Runtime.getRuntime().maxMemory() ; -// boolean result = 100 - free > maxMemory; -// return result; -// } -// } -} - - Copied: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCache.java (from rev 3844, trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java) =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/IsisCache.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/IsisCache.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -0,0 +1,264 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2006 - 2010 Ifremer, Code Lutin, Cédric Pineau, Benjamin Poussin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ +package fr.ifremer.isisfish.util; + +import fr.ifremer.isisfish.simulator.SimulationContext; +import fr.ifremer.isisfish.types.TimeStep; +import java.lang.reflect.Method; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codehaus.aspectwerkz.joinpoint.JoinPoint; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * IsisCacheOnReferenceMap utilise pour mettre les resultats de methode durant + * la simulation pour minimiser les appels + * <p> + * Created: 25 août 06 22:42:47 + * <p> + * @author poussin + * @version $Revision$ + * <p> + * Last update: $Date$ by : + * $Author$ + */ +public class IsisCache { + + /** + * to use log facility, just put in your code: log.info(\"...\"); + */ + static private Log log = LogFactory.getLog(IsisCacheAbstract.class); + + static public IsisCacheBackend.Factory defaultFactory + = IsisCacheBackendOnGuava.factory; + + // la longueur du package pour minimiser la longueur des topiaId + static final private int entityPackageLenght = "fr.ifremer.isisfish.entities.".length(); + // la valeur NULL a utilise a la place de null pour les timeStep + static final private Object NULL = new Object(); + + protected long totalCall = 0; + protected long cacheUsed = 0; + + protected IsisCacheBackend cacheBackend; + + public IsisCache() { + this(defaultFactory.createNew()); + } + + public IsisCache(IsisCacheBackend cacheBackend) { + this.cacheBackend = cacheBackend; + } + + /** + * Return trace object from context. + * <p> + * @return trace object from context + */ + protected Trace getTrace() { + SimulationContext context = SimulationContext.get(); + Trace result = context.getTrace(); + return result; + } + + /** + * Recupere pour un pas de temps donnes une valeur calcule pour une cle + * <p> + * @param step le pas de temps pour lequel on souhaite ajouter (ou + * null) + * @param key la cle de storage + * @param defaultValue la valeur par defaut a retourner si elle n'est pas en + * cache si defaultValue est une JoinPoint alors un + * proceed est appele dessus et le resultat de l'appel + * est utiliser comme valeur par defaut + * @return la valeur dans le cache ou defaultValue + */ + public Object get(Method method, Object[] args, Object defaultValue) throws Throwable { + totalCall++; + + Object result = null; + if (method.getAnnotation(Nocache.class) != null + || method.getDeclaringClass().getAnnotation(Nocache.class) != null) { + result = realCall(defaultValue); + } else { + // compute key and keep TimeStep objet + StringBuilder sbKey = new StringBuilder(); + // le pas de temps trouve dans les arguments + TimeStep step = computeKey(sbKey, method, args); + + // on recupere le intern de la String car normalement en cache on + // retrouve souvent les memes chaines comme cle (sinon le cache + // servirait a rien :D) + String key = sbKey.toString().intern(); + result = get(step, key); + if (result == null) { + + // computation increment (/ by 0) + // FIXME need to be called, but fail with empty stack + //getTrace().traceAfterComputation(method); + result = realCall(defaultValue); + if (result != null) { // util pour les methodes retournant void, ne fonctionne pas si on met AND !execute(void *(..)) dans l'aspect. En fait fonction seulement si utilisé avec les traces :( + put(step, key, result); + } + } else { + cacheUsed++; + } + } + return result; + } + + protected TimeStep computeKey(StringBuilder sbKey, Method method, Object[] args) { + TimeStep result = null; + sbKey.append(method.getDeclaringClass().getSimpleName()); + sbKey.append("."); + sbKey.append(method.getName()); + for (Object o : args) { + sbKey.append(";"); + if (o == null) { + sbKey.append("null"); + } else if (o instanceof Number || o instanceof String) { + sbKey.append(o.toString()); + } else if (o instanceof TimeStep) { + result = (TimeStep) o; + sbKey.append(((TimeStep) o).getStep()); + } else if (o instanceof TopiaEntity) { + sbKey.append(((TopiaEntity) o).getTopiaId().substring(entityPackageLenght)); + } else { + // on minimise en prenant que le nom de la classe (pas le package) + sbKey.append(o.getClass().getSimpleName()); + sbKey.append('@'); + // et en lui ajoutant son adresse memoire en Hexa + sbKey.append(Integer.toHexString(System.identityHashCode(o))); + } + } + return result; + } + + protected Object get(TimeStep step, String key) { + Object result = cacheBackend.get(step, key); + return result; + } + + protected void put(TimeStep step, String key, Object value) { + cacheBackend.put(step, key, value); + } + + /** + * On fait l'appel reel dans une autre methode pour pouvoir le savoir dans + * les traces + * <p> + * @param jp + * @return ? + * @throws Throwable + */ + protected Object realCall(Object defaultValue) throws Throwable { + Object result = defaultValue; + if (defaultValue instanceof JoinPoint) { + result = ((JoinPoint) defaultValue).proceed(); + } + return result; + } + + /** + * remove all values in cache + */ + public void clear() { + cacheBackend.clear(); + } + + /** + * remove all values in cache for the specied TimeStep + */ + public void clear(TimeStep step) { + Object key = step; + if (key == null) { + key = NULL; + } + cacheBackend.removeStep(key); + } + + /** + * @return Returns the cacheUsed. + */ + public long getCacheUsed() { + long result = cacheUsed; + return result; + } + + /** + * @return Returns the totalCall. + */ + public long getTotalCall() { + long result = totalCall; + return result; + } + + /** + * Affiche les statistiques + * <p> + */ + public String printStatistiqueAndClear() { + StringBuilder result = new StringBuilder(); + result.append("--- Cache Statistiques ---\n"); + result.append("Total call: ").append(totalCall).append("\n"); + result.append("Cache used: ").append(cacheUsed).append("\n"); + long percent = 0; + if (totalCall != 0) { + percent = 100 * cacheUsed / totalCall; + } + result.append("Cache usage: ").append(percent).append("%\n"); + result.append("--------------------\n"); + cacheBackend.clear(); + + System.out.println(result.toString()); + return result.toString(); + } + + // EN COURS D'ECRITURE MAIS JAMAIS FINI :( + // l'idee est de prendre la place memoire qu'il y a, mais s'il n'y en + // a plus on commence par enlever les objets les plus vieux +// class AdaptaptativeCache extends LinkedHashMap<String, Object> { +// protected int maxMemory = 95; +// /** +// * +// * @param capacity initial capacity +// * @param maxMemory maximum memory used (0-100) +// */ +// public AdaptaptativeCache(int capacity, int maxMemory) { +// super(capacity, 0.75f, true); +// this.maxMemory = maxMemory; +// } +// +// /* (non-Javadoc) +// * @see java.util.LinkedHashMap#removeEldestEntry(java.util.Map.Entry) +// */ +// @Override +// protected boolean removeEldestEntry(Entry<String, Object> eldest) { +// double free = 100.0 * Runtime.getRuntime().freeMemory() / Runtime.getRuntime().maxMemory() ; +// boolean result = 100 - free > maxMemory; +// return result; +// } +// } +} Added: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackend.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackend.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackend.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -0,0 +1,27 @@ +package fr.ifremer.isisfish.util; + +import fr.ifremer.isisfish.types.TimeStep; + +/** + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public interface IsisCacheBackend { + + Object get(TimeStep step, String key) ; + + void put(TimeStep step, String key, Object value); + + void clear() ; + + void removeStep(Object key); + + static public interface Factory { + IsisCacheBackend createNew(); + } + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackend.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Added: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnGuava.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnGuava.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnGuava.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -0,0 +1,107 @@ +package fr.ifremer.isisfish.util; + + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.Weigher; +import fr.ifremer.isisfish.types.TimeStep; +import java.util.Collection; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.math.matrix.MatrixND; + +/** + * + * @author poussin + * @version $Revision$ + + Last update: $Date$ + by : $Author$ + */ +public class IsisCacheBackendOnGuava implements IsisCacheBackend { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(IsisCacheBackendOnGuava.class); + + final static public int POINTER_SIZE = 8; + final static public int DOUBLE_SIZE = 8; + final static public int CHAR_SIZE = 2; + + static public class IsisCacheBackendOnGuavaFactory implements IsisCacheBackend.Factory { + @Override + public IsisCacheBackend createNew() { + return new IsisCacheBackendOnGuava(); + } + } + + static public Factory factory = new IsisCacheBackendOnGuavaFactory(); + + protected Cache<String, Object> cache; + + public IsisCacheBackendOnGuava() { + long max = Runtime.getRuntime().maxMemory() - 300*1024*1024; // isis need about 300M + max = Math.max(max, 500*1024*1024); // to do simulation we need 500M minimum + cache = CacheBuilder.newBuilder() + .maximumWeight(max) + .weigher(new Weigher<String, Object>(){ + @Override + public int weigh(String key, Object value) { + int result = key.length() * CHAR_SIZE; + if (value instanceof MatrixND) { + // MatrixND + // on prend le nombre de case de la matrice pour sa taille + // on ne tient pas compte des dimensions qui sont des objets + // utilises ailleurs + int[] dim = ((MatrixND)value).getDim(); + int size = 1; + for (int i=0; i<dim.length; i++) { + size *= dim[i]; + } + result += size * DOUBLE_SIZE; // size is wrong, because depend on matrix type (float or double) + } else if (value instanceof Collection) { + // List<Zone|Pop|Str|Metier|Cell> + // on prend la taille de la collection, car la donnees + // elle meme qu'elle soit dans le cache ou non est + // certainement utilisee ailleur, donc seul la taille + // des pointeurs dans la collection est prise ici + result += ((Collection)value).size() * POINTER_SIZE; + } else if (value instanceof Number) { + // int| double + // seulement une valeur, on ajoute 1 + result += 1 * DOUBLE_SIZE; + } else { + // a priori, il n'y a pas d'autre type de donnee + if (value != null) { + log.info("Cache can't compute value size of " + ClassUtils.getPackageCanonicalName(value, "null")); + } + } + return result; + } + }) + .build(); + } + + @Override + public void clear() { + cache.invalidateAll(); + } + + @Override + public void removeStep(Object o) { + // do nothing, can"t search step in cache without change cache behavior + } + + @Override + public Object get(TimeStep step, String key) { + Object result = cache.getIfPresent(key); + return result; + } + + @Override + public void put(TimeStep step, String key, Object value) { + cache.put(key, value); + } + + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnGuava.java ___________________________________________________________________ Added: svn:keywords + Author Date Id Revision HeadURL Copied: trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnReferenceMap.java (from rev 3854, trunk/src/main/java/fr/ifremer/isisfish/util/Cache.java) =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnReferenceMap.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/IsisCacheBackendOnReferenceMap.java 2013-11-27 14:42:28 UTC (rev 3855) @@ -0,0 +1,141 @@ +/* + * #%L + * IsisFish + * + * $Id$ + * $HeadURL$ + * %% + * Copyright (C) 2006 - 2010 Ifremer, Code Lutin, Cédric Pineau, Benjamin Poussin + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +package fr.ifremer.isisfish.util; + +import fr.ifremer.isisfish.simulator.SimulationContext; +import fr.ifremer.isisfish.types.TimeStep; +import java.util.Map; +import org.apache.commons.collections.map.ReferenceMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * IsisCacheBackendOnReferenceMap utilise pour mettre les resultats de methode durant la simulation + pour minimiser les appels + + Created: 25 août 06 22:42:47 + * + * @author poussin + * @version $Revision$ + + Last update: $Date$ + by : $Author$ + */ +public class IsisCacheBackendOnReferenceMap implements IsisCacheBackend { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(IsisCacheBackendOnReferenceMap.class); + + static public class IsisCacheBackendOnReferenceMapFactory implements IsisCacheBackend.Factory { + @Override + public IsisCacheBackend createNew() { + return new IsisCacheBackendOnReferenceMap(); + } + } + + static public Factory factory = new IsisCacheBackendOnReferenceMapFactory(); + + // la longueur du package pour minimiser la longueur des topiaId + static final private int entityPackageLenght = "fr.ifremer.isisfish.entities.".length(); + // la valeur NULL a utilise a la place de null pour les timeStep + static final private Object NULL = new Object(); + + /** + * map<TimeStep, Map<Key, Value>> + * TimeStep peut etre null via l'objet NULL + * Key est la cle calcule par computeKey + * Value est la valeur du cache + * + * TimeStep est en WEAK pour que des que l'on passe au pas de temps suivant + * ils soit efface de la memoire si plus personne n'a de reference sur + * ce pas de temps. L'autre moyen est de force l'effacement via clear(TimeStep) + * + * Value est en SOFT reference pour que les valeurs soit effacee du cache + * lorsqu'il n'y a plus de place memoire + */ + protected Map cache = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD); + + public IsisCacheBackendOnReferenceMap() { + } + + /** + * Return trace object from context. + * + * @return trace object from context + */ + protected Trace getTrace() { + SimulationContext context = SimulationContext.get(); + Trace result = context.getTrace(); + return result; + } + + protected Map getCacheTimeStep(TimeStep step) { + Object key = step; + if (step == null) { + key = NULL; + } + Map result = (Map)cache.get(key); + if (result == null) { + result = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); + cache.put(key, result); + } + return result; + } + + @Override + public Object get(TimeStep step, String key) { + Object result = null; + Map cacheTimeStep = getCacheTimeStep(step); + if (cacheTimeStep != null) { + result = cacheTimeStep.get(key); + } + return result; + } + + @Override + public void put(TimeStep step, String key, Object value) { + getCacheTimeStep(step).put(key, value); + } + + /** + * remove all values in cache + */ + @Override + public void clear() { + cache.clear(); + } + + /** + * remove all values in cache for the specied TimeStep + */ + @Override + public void removeStep(Object o) { + cache.remove(o); + } + +} + +
participants (1)
-
bpoussin@users.forge.codelutin.com