Author: bpoussin Date: 2010-12-19 13:44:26 +0100 (Sun, 19 Dec 2010) New Revision: 629 Url: http://nuiton.org/repositories/revision/wikitty/629 Log: enhance cache feature - we can specify priority extension, less removed from cache that other wikitty) - support cache for extension Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyConfig.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCache.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheJCS.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheSimple.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyServiceCached.java Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyConfig.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyConfig.java 2010-12-19 05:17:12 UTC (rev 628) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyConfig.java 2010-12-19 12:44:26 UTC (rev 629) @@ -229,6 +229,17 @@ _("Indique le composant a utiliser pour le cache"), WikittyCacheJCS.class.getName(), String.class, false, false), + WIKITTY_CACHE_PRIORITY_EXTENSIONS( + "wikitty.service.cache.priority.extensions", + _("Indique la liste des extensions qui doivent etre conservee prioritairement"), + "", String.class, false, false), + + WIKITTY_CACHE_SIMPLE_REFERENCE_TYPE( + "wikitty.service.cache.simple", + _("Indique le type de reference a utiliser pour les extensions" + + " non prioritaires dans le WikittyCacheSimple (soft ou hard)"), + "soft", String.class, false, false), + WIKITTY_WIKITTYSERVICEACCESSSTAT_COMPONENTS( "wikitty.WikittyServiceAccessStat.components", _("Indique le composant a utiliser pour le stockage des acces"), Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCache.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCache.java 2010-12-19 05:17:12 UTC (rev 628) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCache.java 2010-12-19 12:44:26 UTC (rev 629) @@ -1,9 +1,14 @@ package org.nuiton.wikitty.services; import org.nuiton.wikitty.entities.Wikitty; +import org.nuiton.wikitty.entities.WikittyExtension; /** + * Interface commune a toutes les implantations du cache. Les implantations + * doivent faire le moins de travail possible, donc s'il y a des choses communes + * il faut les coder dans {@link WikittyServiceCached} * + * * @author poussin * @version $Revision$ * @@ -28,7 +33,7 @@ Wikitty getWikitty(String id); /** - * Only realy put wikitty in cache, if not in cache or version is newer than + * put wikitty in cache * one in cache * @param e */ @@ -41,4 +46,32 @@ */ void removeWikitty(String id); + public boolean existsExtension(String id); + + /** + * Return extension object if is in the cache, null otherwize. + * + * @param id + * @return extension object or null + */ + public WikittyExtension getExtension(String id); + + /** + * put extension in cache + * @param e + */ + public void putExtension(WikittyExtension e); + + /** + * Remove extension from cache. + * + * @param id wikitty id to remove + */ + public void removeExtension(String id); + + /** + * Clear all cache. + */ + public void clearExtension(); + } Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheJCS.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheJCS.java 2010-12-19 05:17:12 UTC (rev 628) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheJCS.java 2010-12-19 12:44:26 UTC (rev 629) @@ -25,16 +25,21 @@ package org.nuiton.wikitty.services; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.nuiton.wikitty.entities.Wikitty; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.jcs.JCS; import org.apache.jcs.access.GroupCacheAccess; import org.apache.jcs.access.exception.CacheException; import org.apache.jcs.engine.control.CompositeCacheManager; import org.nuiton.util.ApplicationConfig; +import org.nuiton.wikitty.WikittyConfig; import org.nuiton.wikitty.WikittyException; +import org.nuiton.wikitty.entities.WikittyExtension; /** * Implantation du cache base sur le projet apache JCS @@ -48,19 +53,40 @@ public class WikittyCacheJCS implements WikittyCache { static private Log log = LogFactory.getLog(WikittyCacheJCS.class); - + + protected Set<String> priorityExtensions = new HashSet<String>(); + + /** + * cache ou sont stocke les objects qui doivent rester le plus possible + * en memoire + */ + protected GroupCacheAccess priorityCache; + /** + * cache pour les autres wikitties + */ protected GroupCacheAccess wikittyCache; /** + * cache pour les extensions + */ + protected GroupCacheAccess extensionCache; + + /** * * @param config not used currently but necessary in futur to configure the cache * Create a soft cache. */ public WikittyCacheJCS(ApplicationConfig config) { try { + List<String> priorityExtensions = config.getOptionAsList( + WikittyConfig.WikittyOption.WIKITTY_CACHE_PRIORITY_EXTENSIONS.getKey()).getOption(); + this.priorityExtensions.addAll(priorityExtensions); + CompositeCacheManager cacheMgr = CompositeCacheManager.getUnconfiguredInstance(); cacheMgr.configure(config.getFlatOptions()); + priorityCache = new GroupCacheAccess(cacheMgr.getCache("priority")); wikittyCache = new GroupCacheAccess(cacheMgr.getCache("wikitty")); + extensionCache = new GroupCacheAccess(cacheMgr.getCache("extension")); // JCS ne permet pas de passer un Properties mais seulement un nom de fichier :( // JCS.setConfigFilename(config.getConfigFileName()); @@ -73,8 +99,13 @@ @Override public boolean existsWikitty(String id) { - Object o = wikittyCache.get(id); + Object o = priorityCache.get(id); boolean result = (o != null); + if (!result) { + o = wikittyCache.get(id); + result = (o != null); + } + return result; } @@ -86,7 +117,10 @@ */ @Override public Wikitty getWikitty(String id) { - Wikitty result = (Wikitty)wikittyCache.get(id); + Wikitty result = (Wikitty)priorityCache.get(id); + if (result == null) { + result = (Wikitty) wikittyCache.get(id); + } return result; } @@ -99,7 +133,13 @@ public void putWikitty(Wikitty e) { if (e != null) { try { - wikittyCache.put(e.getId(), e); + if (Collections.disjoint(priorityExtensions,e.getExtensionNames())) { + // le wikitty ne contient pas d'extension prioritaire + // on le met dans le cache commun + wikittyCache.put(e.getId(), e); + } else { + priorityCache.put(e.getId(), e); + } } catch (CacheException eee) { log.error(String.format("Can't put wikitty %s in cache", e), eee); } @@ -114,6 +154,7 @@ @Override public void removeWikitty(String id) { try { + priorityCache.remove(id); wikittyCache.remove(id); } catch (CacheException eee) { log.error(String.format("Can't remove wikitty %s in cache", id), eee); @@ -126,10 +167,71 @@ @Override public void clearWikitty() { try { + priorityCache.clear(); wikittyCache.clear(); } catch (CacheException eee) { log.error(String.format("Can't clear wikitty cache"), eee); } } + @Override + public boolean existsExtension(String id) { + Object o = extensionCache.get(id); + boolean result = (o != null); + return result; + } + + /** + * Return wikitty object if is in the cache, null otherwize. + * + * @param id + * @return wikitty object or null + */ + @Override + public WikittyExtension getExtension(String id) { + WikittyExtension result = (WikittyExtension)extensionCache.get(id); + return result; + } + + /** + * Only realy put wikitty in cache, if not in cache or version is newer than + * one in cache + * @param e + */ + @Override + public void putExtension(WikittyExtension e) { + if (e != null) { + try { + extensionCache.put(e.getId(), e); + } catch (CacheException eee) { + log.error(String.format("Can't put extension %s in cache", e), eee); + } + } + } + + /** + * Remove wikitty from cache. + * + * @param id wikitty id to remove + */ + @Override + public void removeExtension(String id) { + try { + extensionCache.remove(id); + } catch (CacheException eee) { + log.error(String.format("Can't remove extensions %s in cache", id), eee); + } + } + + /** + * Clear all cache. + */ + @Override + public void clearExtension() { + try { + extensionCache.clear(); + } catch (CacheException eee) { + log.error(String.format("Can't clear extension cache"), eee); + } + } } Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheSimple.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheSimple.java 2010-12-19 05:17:12 UTC (rev 628) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyCacheSimple.java 2010-12-19 12:44:26 UTC (rev 629) @@ -25,14 +25,20 @@ package org.nuiton.wikitty.services; +import java.util.Collections; import org.nuiton.wikitty.entities.Wikitty; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.collections.map.ReferenceMap; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.util.ApplicationConfig; +import org.nuiton.wikitty.WikittyConfig; +import org.nuiton.wikitty.entities.WikittyExtension; /** * Cette classe sert a introduire du cache dans wikitty. Elle sert a centraliser @@ -49,36 +55,58 @@ static private Log log = LogFactory.getLog(WikittyCacheSimple.class); - /** keys are wikitty ids */ + protected Set<String> priorityExtensions = new HashSet<String>(); + + /** + * cache ou sont stocke les objects qui doivent rester le plus possible + * en memoire. + * ATTENTION: ce ne sont que des references HARD, donc il ne faut pas + * qu'il y ait trop d'objet prioritaire, sinon l'application risque de + * manquer de memoire + * keys are wikitty ids + */ + protected Map<String, Wikitty> priorityCache = new HashMap<String, Wikitty>(); + + /** + * cache pour les autres wikitties + * keys are wikitty ids + */ protected Map<String, Wikitty> wikittyCache; + protected Map<String, WikittyExtension> extensionCache; + /** * * @param config not used currently but necessary in futur to configure the cache * Create a soft cache. */ public WikittyCacheSimple(ApplicationConfig config) { - this(true); - } + List<String> priorityExtensions = config.getOptionAsList( + WikittyConfig.WikittyOption.WIKITTY_CACHE_PRIORITY_EXTENSIONS.getKey()).getOption(); + this.priorityExtensions.addAll(priorityExtensions); - /** - * Init cache with specific reference type. - * - * @param soft si vrai utilise un cache avec des reference Soft, sinon - * utilise des references static (utile pour les transactions) - */ - public WikittyCacheSimple(boolean soft) { - if (soft) { + String refType = config.getOption( + WikittyConfig.WikittyOption.WIKITTY_CACHE_SIMPLE_REFERENCE_TYPE.getKey()); + if ("soft".equalsIgnoreCase(refType)) { wikittyCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); + extensionCache = new ReferenceMap(ReferenceMap.HARD, ReferenceMap.SOFT); } else { + // HARD reference use normal map wikittyCache = new HashMap<String, Wikitty>(); - } + extensionCache = new HashMap<String, WikittyExtension>(); + } + } @Override public boolean existsWikitty(String id) { - Object o = wikittyCache.get(id); + Object o = priorityCache.get(id); boolean result = (o != null); + if (!result) { + o = wikittyCache.get(id); + result = (o != null); + } + return result; } @@ -90,7 +118,10 @@ */ @Override public Wikitty getWikitty(String id) { - Wikitty result = wikittyCache.get(id); + Wikitty result = (Wikitty)priorityCache.get(id); + if (result == null) { + result = (Wikitty) wikittyCache.get(id); + } return result; } @@ -102,7 +133,13 @@ @Override public void putWikitty(Wikitty e) { if (e != null) { - wikittyCache.put(e.getId(), e); + if (Collections.disjoint(priorityExtensions, e.getExtensionNames())) { + // le wikitty ne contient pas d'extension prioritaire + // on le met dans le cache commun + wikittyCache.put(e.getId(), e); + } else { + priorityCache.put(e.getId(), e); + } } } @@ -113,6 +150,7 @@ */ @Override public void removeWikitty(String id) { + priorityCache.remove(id); wikittyCache.remove(id); } @@ -121,7 +159,38 @@ */ @Override public void clearWikitty() { + priorityCache.clear(); wikittyCache.clear(); } + @Override + public boolean existsExtension(String id) { + Object o = extensionCache.get(id); + boolean result = (o != null); + return result; + } + + @Override + public WikittyExtension getExtension(String id) { + WikittyExtension result = (WikittyExtension)extensionCache.get(id); + return result; + } + + @Override + public void putExtension(WikittyExtension e) { + if (e != null) { + extensionCache.put(e.getId(), e); + } + } + + @Override + public void removeExtension(String id) { + extensionCache.remove(id); + } + + @Override + public void clearExtension() { + extensionCache.clear(); + } + } Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyServiceCached.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyServiceCached.java 2010-12-19 05:17:12 UTC (rev 628) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/services/WikittyServiceCached.java 2010-12-19 12:44:26 UTC (rev 629) @@ -142,6 +142,23 @@ // } } + /** + * Retourne le nombre de solicitation du cache + * @return + */ + public long getAsked() { + return asked; + } + + /** + * Retourne le nombre de fois que l'element dans le cache demande n'y etait + * pas + * @return + */ + public long getMissed() { + return missed; + } + /** wrap the wikitty or copy it according to allwaysRestoreCopies value */ protected Wikitty wrapWikitty(Wikitty wikitty) { Wikitty result = null; @@ -176,21 +193,25 @@ // son access // - protected void clearCache() { + protected void cacheClearWikitty() { cache.clearWikitty(); } + protected void cacheClearExtension() { + cache.clearExtension(); + } + /** * Only WikittyImpl can be put in real cache implementation. If argument * is WikittyCopyOnWrite, we must take internal wikitty to put in cache */ - protected void putInCache(Wikitty w) { + protected void cachePutWikitty(Wikitty w) { if (w != null) { if (w instanceof WikittyCopyOnWrite) { w = ((WikittyCopyOnWrite) w).getTarget(); } - Wikitty old = getFromCache(w.getId()); + Wikitty old = cache.getWikitty(w.getId()); if (old == null || WikittyUtil.versionGreaterThan(w.getVersion(), old.getVersion())) { cache.putWikitty(w); @@ -208,30 +229,72 @@ } } } - - protected void putInCache(Collection<Wikitty> wikitties) { + + /** + * Only WikittyImpl can be put in real cache implementation. If argument + * is WikittyCopyOnWrite, we must take internal wikitty to put in cache + */ + protected void cachePutExtension(WikittyExtension w) { + if (w != null) { + if (!cache.existsExtension(w.getId())) { + cache.putExtension(w); + + if (log.isTraceEnabled()) { + log.trace(String.format( + "Replace cached wikitty extension '%s'", w.getId())); + } + } else { + if (log.isTraceEnabled()) { + log.trace(String.format( + "Ignoring put wikitty extension for '%s'",w.getId())); + } + } + } + } + + protected void cachePutWikitty(Collection<Wikitty> wikitties) { for (Wikitty w : wikitties) { - putInCache(w); + cachePutWikitty(w); } } - protected void removeInCache(String id) { + protected void cachePutExtension(Collection<WikittyExtension> wikitties) { + for (WikittyExtension w : wikitties) { + cachePutExtension(w); + } + } + protected void cacheRemoveWikitty(String id) { cache.removeWikitty(id); } - protected void removeInCache(Collection<String> ids) { + protected void cacheRemoveExtension(String id) { + cache.removeWikitty(id); + } + + protected void cacheRemoveWikitty(Collection<String> ids) { for (String id : ids) { - removeInCache(id); + cacheRemoveWikitty(id); } } - protected Wikitty getFromCache(String id) { + protected void cacheRemoveExtension(Collection<String> ids) { + for (String id : ids) { + cacheRemoveWikitty(id); + } + } + + protected Wikitty cacheGetWikitty(String id) { Wikitty result = cache.getWikitty(id); // all time wrap, inly WikittyImpl are in cache result = wrapWikitty(result); return result; } + protected WikittyExtension cacheGetExtensions(String id) { + WikittyExtension result = cache.getExtension(id); + return result; + } + // // surcharge des methodes du WikittyService // @@ -239,7 +302,7 @@ @Override public WikittyEvent clear(String securityToken) { WikittyEvent result = ws.clear(securityToken); - clearCache(); + processEvent(result); return result; } @@ -250,7 +313,7 @@ @Override public WikittyEvent delete(String securityToken, Collection<String> ids) { WikittyEvent result = ws.delete(securityToken, ids); - removeInCache(ids); + processEvent(result); return result; } @@ -291,7 +354,8 @@ */ @Override public List<String> getAllExtensionIds(String securityToken) { - // TODO poussin 20100412: perhaps use cache for extension ? + // NOTE poussin 20101219: si on veut utiliser le cache il faut une + // methode specifique return ws.getAllExtensionIds(securityToken); } @@ -322,7 +386,7 @@ LinkedHashMap<String, Wikitty> fromCache = new LinkedHashMap<String, Wikitty>(); for (String id : ids) { - Wikitty w = getFromCache(id); + Wikitty w = cacheGetWikitty(id); fromCache.put(id, w); // put all to maintains order if (w == null) { // if not found on cache, ask the server notInCache.add(id); @@ -332,7 +396,7 @@ // retrieve missing object List<Wikitty> missingInCache = ws.restore(securityToken, notInCache); - putInCache(missingInCache); + cachePutWikitty(missingInCache); for (Wikitty w : missingInCache) { // add missing object @@ -377,8 +441,16 @@ @Override public WikittyExtension restoreExtensionLastVersion( String securityToken, String name) { - // TODO poussin 20100412: perhaps use cache for extension ? - return ws.restoreExtensionLastVersion(securityToken, name); + // NOTE poussin 20100412: comment faire pour utiliser le cache ? on ne + // peut que stocker le resultat sinon il faudrait etre sur d'avoir toutes + // les extensions dans le cache. + // Sinon il faudrait mettre des methodes specifiques dans le cache pour + // cette methode, mise en cache lors du 1er appel, et restitution du + // meme resultat pour les appels suivants tant que pas de modification + // de l'extension (ou de clear/remove) + WikittyExtension result = ws.restoreExtensionLastVersion(securityToken, name); + cachePutExtension(result); + return result; } /** @@ -415,7 +487,9 @@ */ @Override public WikittyEvent deleteTree(String securityToken, String wikittyId) { - return ws.deleteTree(securityToken, wikittyId); + WikittyEvent result = ws.deleteTree(securityToken, wikittyId); + processEvent(result); + return result; } /** @@ -431,10 +505,7 @@ Collection<Wikitty> wikitties, boolean force) { WikittyEvent result = ws.store(securityToken, wikitties, force); - Map<String, Wikitty> wikittiesToCache = result.getWikitties(); - if (wikittiesToCache != null) { - putInCache(wikittiesToCache.values()); - } + processEvent(result); return result; } @@ -442,21 +513,24 @@ @Override public WikittyEvent storeExtension(String securityToken, Collection<WikittyExtension> exts) { - // TODO poussin 20101029: perhaps use cache for extension ? - return ws.storeExtension(securityToken, exts); + WikittyEvent result = ws.storeExtension(securityToken, exts); + processEvent(result); + return result; } @Override public WikittyEvent deleteExtension( String securityToken, Collection<String> extNames) { - // TODO poussin 20101115: perhaps use cache for extension ? - return ws.deleteExtension(securityToken, extNames); + WikittyEvent result = ws.deleteExtension(securityToken, extNames); + processEvent(result); + return result; } @Override public WikittyExtension restoreExtension(String securityToken, String id) { - // TODO poussin 20101029: perhaps use cache for extension ? - return ws.restoreExtension(securityToken, id); + WikittyExtension result = ws.restoreExtension(securityToken, id); + cachePutExtension(result); + return result; } @Override @@ -466,6 +540,14 @@ return ws.restoreVersion(securityToken, wikittyId, version); } + @Override + public WikittyEvent replay( + String securityToken, List<WikittyEvent> events, boolean force) { + WikittyEvent result = ws.replay(securityToken, events, force); + processEvent(result); + return result; + } + // // Just delegate method // @@ -511,12 +593,6 @@ } @Override - public WikittyEvent replay( - String securityToken, List<WikittyEvent> events, boolean force) { - return ws.replay(securityToken, events, force); - } - - @Override public boolean exists(String securityToken, String wikittyId) { return ws.exists(securityToken, wikittyId); } @@ -526,7 +602,30 @@ return ws.isDeleted(securityToken, wikittyId); } - + protected void processEvent(WikittyEvent e) { + // check clear must be the first, if event have clear and other type + // clear is all time play first + if (e.getType().contains( + WikittyEvent.WikittyEventType.CLEAR_WIKITTY) + || e.getType().contains( + WikittyEvent.WikittyEventType.CLEAR_EXTENSION)) { + cacheClearWikitty(); + cacheClearExtension(); + } else { + if (e.getType().contains(WikittyEvent.WikittyEventType.PUT_WIKITTY)) { + cachePutWikitty(e.getWikitties().values()); + } + if (e.getType().contains(WikittyEvent.WikittyEventType.REMOVE_WIKITTY)) { + cacheRemoveWikitty(e.getRemoveDate().keySet()); + } + if (e.getType().contains(WikittyEvent.WikittyEventType.PUT_EXTENSION)) { + cachePutExtension(e.getExtensions().values()); + } + if (e.getType().contains(WikittyEvent.WikittyEventType.REMOVE_EXTENSION)) { + cacheRemoveExtension(e.getDeletedExtensions()); + } + } + } /** * Classe permettant de recevoir les events distants et mettre a jour le cache */ @@ -543,7 +642,7 @@ */ @Override public void clearWikitty(WikittyEvent event) { - wsCached.clearCache(); + wsCached.processEvent(event); } /* @@ -551,8 +650,7 @@ */ @Override public void putWikitty(WikittyEvent event) { - Collection<Wikitty> wikitties = event.getWikitties().values(); - wsCached.putInCache(wikitties); + wsCached.processEvent(event); } /* @@ -560,10 +658,7 @@ */ @Override public void removeWikitty(WikittyEvent event) { - if (event.getRemoveDate() != null) { - Collection<String> ids = event.getRemoveDate().keySet(); - wsCached.removeInCache(ids); - } + wsCached.processEvent(event); } /* @@ -571,10 +666,12 @@ */ @Override public void putExtension(WikittyEvent event) { + wsCached.processEvent(event); } @Override public void removeExtension(WikittyEvent event) { + wsCached.processEvent(event); } /* @@ -582,7 +679,7 @@ */ @Override public void clearExtension(WikittyEvent event) { - wsCached.clearCache(); + wsCached.processEvent(event); } }