Mercurial > dive4elements > framework
view artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java @ 43:b8516aa3d8a1
Time delta calculation in SQL statement to figure out outdated artifacts
in H2 database was broken.
artifacts/trunk@122 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Thu, 24 Sep 2009 09:15:56 +0000 |
parents | 5e4bc24ea438 |
children | 4ae4dc99127d |
line wrap: on
line source
package de.intevation.artifactdatabase; import de.intevation.artifacts.Artifact; import java.sql.Connection; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.ResultSet; import javax.sql.DataSource; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; /** * @author Sascha L. Teichmann */ public class DatabaseCleaner extends Thread { public interface ArtifactReviver { Artifact reviveArtifact(String factoryName, byte [] bytes); } // interface ArtifactReviver private static Logger logger = Logger.getLogger(DatabaseCleaner.class); public static final int MAX_ROWS = 50; public static final String SQL_OUTDATED = SQL.get("artifacts.outdated"); public static final String SQL_DELETE = SQL.get("artifacts.delete"); public static final String SLEEP_XPATH = "/artifact-database/cleaner/sleep-time/text()"; public static final long SLEEP_DEFAULT = 5 * 60 * 1000L; // 5 minutes protected long sleepTime; protected Object sleepLock = new Object(); protected Object context; protected Id.Filter filter; protected ArtifactReviver reviver; public DatabaseCleaner() { } public DatabaseCleaner(Object context, ArtifactReviver reviver) { setDaemon(true); sleepTime = getSleepTime(); this.context = context; this.reviver = reviver; } public void setFilter(Id.Filter filter) { this.filter = filter; } public void wakeup() { synchronized (sleepLock) { sleepLock.notify(); } } protected static long getSleepTime() { String sleepTimeString = Config.getStringXPath(SLEEP_XPATH); if (sleepTimeString == null) { return SLEEP_DEFAULT; } try { // sleep at least one second return Math.max(Long.parseLong(sleepTimeString), 1000L); } catch (NumberFormatException nfe) { logger.warn("Cleaner sleep time defaults to " + SLEEP_DEFAULT); } return SLEEP_DEFAULT; } private static final class IdData extends Id { byte [] data; String factoryName; public IdData(int id, String factoryName, byte [] data) { super(id); this.factoryName = factoryName; this.data = data; } } // class IdData /** * Cleaning is done in two phases. First we fetch a list of ids * of artifacts. If there are artifacts the cleaning is done. * Second we load the artifacts one by one one and call there * endOfLife() method. In this loop we remove them from database, too. * Each deletion is commited to ensure that a sudden failure * of the artifact database server does delete artifacts twice * or does not delete them at all. After this the first step * is repeated. */ protected void cleanup() { logger.info("database cleanup"); Connection connection = null; PreparedStatement fetchIds = null; PreparedStatement deleteId = null; ResultSet result = null; int removedArtifacts = 0; DataSource dataSource = DBConnection.getDataSource(); try { connection = dataSource.getConnection(); connection.setAutoCommit(false); fetchIds = connection.prepareStatement(SQL_OUTDATED); deleteId = connection.prepareStatement(SQL_DELETE); // some dbms like derby do not support LIMIT // in SQL statements. fetchIds.setMaxRows(MAX_ROWS); for (;;) { List ids = new ArrayList(); result = fetchIds.executeQuery(); while (result.next()) { ids.add(new IdData( result.getInt(1), result.getString(2), result.getBytes(3))); } result.close(); result = null; if (ids.isEmpty()) { break; } if (filter != null) { ids = filter.filterIds(ids); } for (int i = ids.size()-1; i >= 0; --i) { IdData idData = (IdData)ids.get(i); Artifact artifact = reviver.reviveArtifact( idData.factoryName, idData.data); idData.data = null; deleteId.setInt(1, idData.id); deleteId.execute(); connection.commit(); try { if (artifact != null) { artifact.endOfLife(context); } } catch (Exception e) { logger.error(e.getLocalizedMessage(), e); } } // for all fetched data removedArtifacts += ids.size(); } } catch (SQLException sqle) { logger.error(sqle.getLocalizedMessage(), sqle); } finally { if (result != null) { try { result.close(); } catch (SQLException sqle) {} } if (fetchIds != null) { try { fetchIds.close(); } catch (SQLException sqle) {} } if (deleteId != null) { try { deleteId.close(); } catch (SQLException sqle) {} } if (connection != null) { try { connection.close(); } catch (SQLException sqle) {} } } logger.info("artifacts removed: " + removedArtifacts); } public void run() { logger.info("sleep time: " + sleepTime + "ms"); for (;;) { cleanup(); try { synchronized (sleepLock) { sleepLock.wait(sleepTime); } } catch (InterruptedException ie) { } } // for (;;) } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: