# HG changeset patch # User Tim Englich # Date 1271767337 0 # Node ID eb777022b62838a63b80848b7d231115d339bc1c # Parent d674cef2ca0de3793e73737f9dae8cc1ca514c61 Integrated a CacheCleaner that will cleanup the SQL-Cache if necessary geo-backend/trunk@958 c6561f87-3c4e-4783-a992-168aeb5c3f6f diff -r d674cef2ca0d -r eb777022b628 geo-backend/ChangeLog --- a/geo-backend/ChangeLog Sun Apr 18 09:22:38 2010 +0000 +++ b/geo-backend/ChangeLog Tue Apr 20 12:42:17 2010 +0000 @@ -1,3 +1,28 @@ +2010-04-20 Tim Englich + + * src/main/java/de/intevation/gnv/geobackend/base/query/CachingQueryExecutorFactory.java: + Integrated the initialization of the CacheCleaner if an SQl-Cache is used. + Also implemented the Method for CleanUp the SQL-Cache in the extended + QueryExecutor. + + * src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutorBase.java, + src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutor.java: + Extended Interface adding an Method that should do the Cleanup of the + SQL-Cache. + + * src/main/java/de/intevation/gnv/geobackend/base/query/cache/package.html: + Added Documentation. + + * src/main/java/de/intevation/gnv/geobackend/base/query/cache/CacheCleaner.java: + Added Threadimplementation that looks every n-Seconds into the Database + if there are Tables that where updated during the Time to the last Cleanup. + If there are Tables that has been modified the CacheCleaner will call the + used QueryExecutor. The Queryexecutor will clean up it's Cache using the + Names of the affected Tables. + It is Possible to configure the Interval between two cleanups. for this + you have to set the Systemproperty -Dcaching.cleaner.interval using Seconds + as unit. + 2010-04-16 Sascha L. Teichmann * src/main/java/de/intevation/gnv/geobackend/base/connectionpool/exception/ConnectionException.java, diff -r d674cef2ca0d -r eb777022b628 geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/CachingQueryExecutorFactory.java --- a/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/CachingQueryExecutorFactory.java Sun Apr 18 09:22:38 2010 +0000 +++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/CachingQueryExecutorFactory.java Tue Apr 20 12:42:17 2010 +0000 @@ -1,8 +1,7 @@ package de.intevation.gnv.geobackend.base.query; -import de.intevation.gnv.geobackend.base.Result; - import java.util.Collection; +import java.util.Iterator; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; @@ -10,6 +9,9 @@ import org.apache.log4j.Logger; +import de.intevation.gnv.geobackend.base.Result; +import de.intevation.gnv.geobackend.base.query.cache.CacheCleaner; + /** * @author Sascha L. Teichmann */ @@ -30,6 +32,8 @@ ? new CacheManager(configFile) : new CacheManager(); manager.addCache(CACHE_NAME); + CacheCleaner cc = new CacheCleaner(); + cc.start(); } public QueryExecutor getQueryExecutor() { @@ -51,6 +55,27 @@ Cache cache = manager.getCache(CACHE_NAME); cache.put(new Element(query, results)); } + + public void clearCache(String[] tableNames) { + Cache cache = manager.getCache(CACHE_NAME); + Iterator keys = cache.getKeys().iterator(); + while (keys.hasNext()){ + String origKey = (String)keys.next(); + String key = origKey.toUpperCase(); + log.debug(key); + for (int i = 0; i < tableNames.length; i++){ + if (key.contains(tableNames[i])){ + log.debug(tableNames[i]+ " is contained in "+key); + log.debug("Cacheentry will be removed"); + boolean success = cache.remove(origKey); + if (!success){ + log.warn("Object could not be reoved from Cache."); + } + break; + } + } + } + } }; } diff -r d674cef2ca0d -r eb777022b628 geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutor.java --- a/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutor.java Sun Apr 18 09:22:38 2010 +0000 +++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutor.java Tue Apr 20 12:42:17 2010 +0000 @@ -1,11 +1,10 @@ package de.intevation.gnv.geobackend.base.query; +import java.util.Collection; + import de.intevation.gnv.geobackend.base.Result; - import de.intevation.gnv.geobackend.base.query.exception.QueryException; -import java.util.Collection; - /** * This Interface provides the Method to execute Queries * against a Datastore eg. Databases @@ -23,9 +22,27 @@ * @return the fetched Values * @throws QueryException */ - Collection executeQuery(String queryID, String[] filter) throws QueryException; + Collection executeQuery(String queryID, + String[] filter) + throws QueryException; + /** + * Returns the cached results to a given Query. + * @param query the Query that should identify the Result + * @return the Cached results or null if no results are cached. + */ Collection cachedResults(String query); + /** + * Writes the Result into the Cache + * @param query the Query that will be used as Identifier. + * @param results The Results that should be cached. + */ void cacheResults(String query, Collection results); + + /** + * Clears the Cache using the Names of the Database-Tables + * @param tableNames the Tablenames that should be used to Clear the Cache. + */ + void clearCache(String[] tableNames); } diff -r d674cef2ca0d -r eb777022b628 geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutorBase.java --- a/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutorBase.java Sun Apr 18 09:22:38 2010 +0000 +++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/QueryExecutorBase.java Tue Apr 20 12:42:17 2010 +0000 @@ -1,18 +1,17 @@ package de.intevation.gnv.geobackend.base.query; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import de.intevation.gnv.geobackend.base.DefaultResult; import de.intevation.gnv.geobackend.base.DefaultResultDescriptor; import de.intevation.gnv.geobackend.base.Result; import de.intevation.gnv.geobackend.base.ResultDescriptor; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - /** * This is an abstract Basicimplementation of the Interface * QueryExecutor providing several Helpermethods. @@ -99,4 +98,7 @@ public void cacheResults(String query, Collection result) { } + public void clearCache(String[] tableNames) { + } + } diff -r d674cef2ca0d -r eb777022b628 geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/cache/CacheCleaner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/cache/CacheCleaner.java Tue Apr 20 12:42:17 2010 +0000 @@ -0,0 +1,229 @@ +/** + * + */ +package de.intevation.gnv.geobackend.base.query.cache; + +import java.sql.Date; +import java.util.Collection; +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import de.intevation.gnv.geobackend.base.Result; +import de.intevation.gnv.geobackend.base.query.DefaultQueryExceutor; +import de.intevation.gnv.geobackend.base.query.QueryExecutor; +import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; +import de.intevation.gnv.geobackend.base.query.exception.QueryException; +import de.intevation.gnv.geobackend.util.DateUtils; + +/** + * Thread that looks every n - Minutes if an Cache has to be cleanedup. + * You can configure the Timeout in Seconds using the Systemproperty + * @author Tim Englich + * + */ +public class CacheCleaner extends Thread { + + /** + * the logger, used to log exceptions and additonaly information + */ + private static Logger log = Logger.getLogger(CacheCleaner.class); + + /** + * The Systemproperty-identifier for the Configuration of the TimeInterval + */ + public static final String CACHE_CLEANER_INTERVAL = "caching.cleaner.interval"; + + /** + * The Time To wait between two Cleanups. + */ + private long timeout = 1000 * 60; // 1 Minute + + /** + * The Border which has to be used to Query the updated Tables. + */ + private long lowerBorderTime = 0; + + /** + * The Id to Lookup the SQL-Statement for fetchung the Names of the + * updated Tables. + */ + private String queryID = "updated_tables"; + + /** + * Constructor + */ + public CacheCleaner() { + this.setUp(); + } + + /** + * Constructor + * @param arg0 + */ + public CacheCleaner(Runnable arg0) { + super(arg0); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + */ + public CacheCleaner(String arg0) { + super(arg0); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + * @param arg1 + */ + public CacheCleaner(ThreadGroup arg0, Runnable arg1) { + super(arg0, arg1); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + * @param arg1 + */ + public CacheCleaner(ThreadGroup arg0, String arg1) { + super(arg0, arg1); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + * @param arg1 + */ + public CacheCleaner(Runnable arg0, String arg1) { + super(arg0, arg1); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + * @param arg1 + * @param arg2 + */ + public CacheCleaner(ThreadGroup arg0, Runnable arg1, String arg2) { + super(arg0, arg1, arg2); + this.setUp(); + } + + /** + * Constructor + * @param arg0 + * @param arg1 + * @param arg2 + * @param arg3 + */ + public CacheCleaner(ThreadGroup arg0, Runnable arg1, String arg2, long arg3) { + super(arg0, arg1, arg2, arg3); + this.setUp(); + } + + /** + * Sets up the members of the CacheCleaner. + */ + protected void setUp(){ + String intervalValue = System.getProperty(CACHE_CLEANER_INTERVAL); + if (intervalValue != null){ + log.info("Set Interval to "+intervalValue+" Seconds"); + try { + this.timeout = Long.parseLong(intervalValue) * 1000; + } catch (NumberFormatException e) { + log.error(e,e); + } + } + } + + /** + * This Method can be used do run the Main-Mechanism of the Thread e.g + * from a Unittest. + * @return + */ + public boolean test(){ + log.debug("CacheCleaner.test"); + this.cleanup(); + return true; + } + + @Override + public void run() { + log.debug("CacheCleaner.run"); + long requiredTime = 0; + this.lowerBorderTime = System.currentTimeMillis(); + while (true){ + long startTime = 0; + try { + long nextTimeout = timeout-requiredTime; + if (nextTimeout > 0){ + Thread.sleep(nextTimeout); + } + startTime = System.currentTimeMillis(); + log.debug("Sleep "+nextTimeout+"ms cleanup Cache now"); + this.cleanup(); + } catch (InterruptedException e) { + log.error(e,e); + } catch (Exception e){ + log.error(e,e); + } catch (Throwable t){ + log.error(t,t); + }finally{ + requiredTime = System.currentTimeMillis() - startTime; + log.debug("CleanUp required "+requiredTime); + } + } + } + + /** + * Method that do the Cleanup-Work + */ + protected void cleanup(){ + log.debug("CacheCleaner.cleanup"); + try { + // We have to go this Way to avoid using the Cache for this Query. + String[] tableNames = this.getUpdatedTableNames(); + if (tableNames != null){ + QueryExecutorFactory.getInstance() + .getQueryExecutor().clearCache(tableNames); + } + } catch (QueryException e) { + log.error(e,e); + } + + } + + /** + * Returns the Names of the Tables which have been updated. + * @return the Names of the Tables which have been updated. + * @throws QueryException + */ + protected String[] getUpdatedTableNames()throws QueryException { + String[] tableNames = null; + QueryExecutor queryExecutor = new DefaultQueryExceutor(); + Date date = new Date(this.lowerBorderTime); + this.lowerBorderTime = System.currentTimeMillis(); + log.debug("New Lookup at "+DateUtils.getPatternedDateAmer(new Date(lowerBorderTime))); + String queryDate = DateUtils.getPatternedDateAmer(date); + Collection result = queryExecutor. + executeQuery(queryID, + new String[]{queryDate}); + if (result != null && !result.isEmpty()){ + tableNames = new String[result.size()]; + Iterator it = result.iterator(); + int i = 0; + while (it.hasNext()){ + tableNames[i++] = it.next().getString(0).toUpperCase(); + log.debug("Table that was updated: "+tableNames[i-1]); + } + } + return tableNames; + } +} diff -r d674cef2ca0d -r eb777022b628 geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/cache/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/geo-backend/src/main/java/de/intevation/gnv/geobackend/base/query/cache/package.html Tue Apr 20 12:42:17 2010 +0000 @@ -0,0 +1,9 @@ + + + + + +This package contains the CacheCleaner. An Thread that is responsible to +Cleanup the SQL-Cache if the Data in the Database has been updated. + +