Bei mir waren es SQLite-Datenbankabfragen, die zu lange dauerten. Nach dem Neubau von pc-kombo war die Seite dadurch erstmal langsamer als vorher. Das lag aber nicht wirklich an der neuen Architektur oder Datenbank an sich, sondern dass durch nicht übernommene Optimierungen weniger direkt im Speicher behalten wurde. Also musste ein Cache her.
Ich will hier als Beispiel zeigen, wie man so etwas aufbauen kann. Anmerkungen zum Code sind gern gesehen. So sind mir im cacheControl-Thread beim Schreiben dieses Eintrags direkt ein paar Logikfehler aufgefallen, die ich jetzt korrigiert habe. War wohl ungenügend getestet...
Ein Singleton, eine Hashmap und einen Thread zum Aufräumen abgelaufener Cacheeinträge, mehr braucht es eigentlich nicht. Beliebige Objekte werden hereingegeben, Strings als ids, zurückgegebene Objekte muss die darüberliegende Programmmlogik casten.
Beispielnutzung
try { return (Vector<Gpu>) Cache.getInstance().get("Warehouse:Gpus"); } catch (CacheIdNotFoundException cinfe) { Vector<Gpu> gpus = Database.getInstance().getGpus(); Cache.getInstance().put("Warehouse:Gpus", gpus.clone(), 3600*24L); return gpus; }
Implementierung
Cache.java:
import java.util.HashMap; import java.util.Map; import java.util.TreeMap; public class Cache { private static Cache instance = new Cache(); private Cache() { Thread cacheControl = new Thread(new Runnable() { public void run() { while(true) { try { Thread.sleep(3600); } catch (InterruptedException ie) { } long now = System.currentTimeMillis() / 1000L; Long time = null; String key = ""; while ((time = ttl.floorKey(now)) != null) { key = ttl.get(time); cache.remove(key); ttl.remove(time); } } } }); cacheControl.start(); } public static Cache getInstance() { return instance; } /** * The memory-cache */ private Map<String, Object> cache = new HashMap<String, Object>(256); /** * moment-to-die for the values corresponding to the given keys */ private TreeMap<Long, String> ttl = new TreeMap<Long, String>(); /** * Put an objekt in the cache * @param key * @param value * @param seconds Time to live */ public void put(String key, Object value, Long seconds) { long now = System.currentTimeMillis() / 1000L; cache.put(key, value); ttl.put(now + seconds, key); } /** * Get a value from the cache * @param key * @return * @throws CacheIdNotFoundException if key not found */ public Object get(String key) throws CacheIdNotFoundException { Object value = cache.get(key); if (value == null) { throw new CacheIdNotFoundException(); } else { return value; } } }
Die CacheIdNotFoundException.java ist natürlich witzlos:
class CacheIdNotFoundException extends Exception {}