# HG changeset patch # User Sascha L. Teichmann # Date 1441287247 -7200 # Node ID 3b1e48d22ce00ede83592d95e647f436592bab97 # Parent 91b1435fb9eaaa9b342886df1e7b275ddc92621c Experimentally let database cleaner and backend share the same sql executor. diff -r 91b1435fb9ea -r 3b1e48d22ce0 artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java Thu Sep 03 11:46:24 2015 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java Thu Sep 03 15:34:07 2015 +0200 @@ -70,7 +70,10 @@ bootstrap, backend); DatabaseCleaner cleaner = new DatabaseCleaner( - bootstrap.getContext(), backend, backend.getConfig()); + bootstrap.getContext(), + backend, + backend.getSQLExecutor(), + backend.getConfig()); HTTPServer httpServer = bootstrap.getHTTPServer(); diff -r 91b1435fb9ea -r 3b1e48d22ce0 artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java Thu Sep 03 11:46:24 2015 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java Thu Sep 03 15:34:07 2015 +0200 @@ -273,6 +273,10 @@ setupSQL(config.getSQL()); } + public SQLExecutor getSQLExecutor() { + return sqlExecutor; + } + /** * Constructor to create a backend with a link to the database cleaner. * @param cleaner The clean which periodically removes outdated @@ -706,6 +710,7 @@ final int [] id = new int[1]; SQLExecutor.Instance exec = sqlExecutor.new Instance() { + @Override public boolean doIt() throws SQLException { prepareStatement(SQL_NEXT_ID); result = stmnt.executeQuery(); diff -r 91b1435fb9ea -r 3b1e48d22ce0 artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java Thu Sep 03 11:46:24 2015 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java Thu Sep 03 15:34:07 2015 +0200 @@ -14,6 +14,7 @@ import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifactdatabase.db.SQL; +import org.dive4elements.artifactdatabase.db.SQLExecutor; import org.dive4elements.artifactdatabase.db.DBConnection; import java.sql.Connection; @@ -135,7 +136,7 @@ */ protected ArtifactReviver reviver; - protected DBConnection dbConnection; + protected SQLExecutor sqlExecutor; /** * Default constructor. @@ -149,12 +150,17 @@ * @param context The global context of the artifact database * @param reviver The reviver to awake artifact one last time. */ - public DatabaseCleaner(Object context, ArtifactReviver reviver, DBConfig config) { + public DatabaseCleaner( + Object context, + ArtifactReviver reviver, + SQLExecutor sqlExecutor, + DBConfig config + ) { setDaemon(true); sleepTime = getSleepTime(); this.context = context; this.reviver = reviver; - this.dbConnection = config.getDBConnection(); + this.sqlExecutor = sqlExecutor; setupSQL(config.getSQL()); } @@ -249,155 +255,154 @@ protected void cleanup() { logger.info("database cleanup"); - Connection connection = null; - PreparedStatement fetchIds = null; - PreparedStatement stmnt = null; - ResultSet result = null; - - DataSource dataSource = dbConnection.getDataSource(); - - Set lockedIds = lockedIdsProvider != null + final Set lockedIds = lockedIdsProvider != null ? lockedIdsProvider.getLockedIds() : EMPTY_IDS; - String questionMarks = lockedIds.isEmpty() + final String questionMarks = lockedIds.isEmpty() ? "-666" // XXX: A bit hackish. : StringUtils.repeat('?', lockedIds.size(), ','); - List deletedCollections = new ArrayList(); - List deletedArtifacts = new ArrayList(); - - try { - connection = dataSource.getConnection(); - connection.setAutoCommit(false); - - fetchIds = connection.prepareStatement( - SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks)); - - // some dbms like derby do not support LIMIT - // in SQL statements. - fetchIds.setMaxRows(MAX_ROWS); - - // Fetch ids of outdated collections - stmnt = connection.prepareStatement( - SQL_OUTDATED_COLLECTIONS.replace( - "$LOCKED_IDS$", questionMarks)); - - // fill in the locked ids - int idx = 1; - for (Integer id: lockedIds) { - fetchIds.setInt(idx, id); - stmnt .setInt(idx, id); - ++idx; - } - - ArrayList cs = new ArrayList(); - result = stmnt.executeQuery(); - while (result.next()) { - cs.add(new IdIdentifier( - result.getInt(1), - result.getString(2))); - } - - result.close(); result = null; - stmnt.close(); stmnt = null; - - // delete collection items - stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION_ITEMS); - - for (IdIdentifier id: cs) { - logger.debug("Mark collection for deletion: " + id.id); - stmnt.setInt(1, id.id); - stmnt.execute(); - } - - stmnt.close(); stmnt = null; - - // delete collections - stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION); + final List deletedCollections = new ArrayList(); + final List deletedArtifacts = new ArrayList(); - for (IdIdentifier id: cs) { - stmnt.setInt(1, id.id); - stmnt.execute(); - deletedCollections.add(id.identifier); - } - - stmnt.close(); stmnt = null; - connection.commit(); - - cs = null; - - // remove artifacts - stmnt = connection.prepareStatement(SQL_DELETE_ARTIFACT); - - 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.getString(4))); - } + SQLExecutor.Instance exec = sqlExecutor.new Instance() { - result.close(); result = null; - - if (ids.isEmpty()) { - break; - } - - for (int i = ids.size()-1; i >= 0; --i) { - IdData idData = ids.get(i); - Artifact artifact = reviver.reviveArtifact( - idData.factoryName, idData.data); - idData.data = null; + @Override + public boolean doIt() throws SQLException { - logger.debug("Prepare Artifact (id=" - + idData.id + ") for deletion."); - - stmnt.setInt(1, idData.id); - stmnt.execute(); - connection.commit(); + PreparedStatement fetchIds = null; + PreparedStatement stmnt = null; + ResultSet result = null; - try { - if (artifact != null) { - logger.debug("Call endOfLife for Artifact: " - + artifact.identifier()); + try { + fetchIds = conn.prepareStatement( + SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks)); - artifact.endOfLife(context); - } - } - catch (Exception e) { - logger.error(e.getMessage(), e); + // some dbms like derby do not support LIMIT + // in SQL statements. + fetchIds.setMaxRows(MAX_ROWS); + + // Fetch ids of outdated collections + stmnt = conn.prepareStatement( + SQL_OUTDATED_COLLECTIONS.replace( + "$LOCKED_IDS$", questionMarks)); + + // fill in the locked ids + int idx = 1; + for (Integer id: lockedIds) { + fetchIds.setInt(idx, id); + stmnt .setInt(idx, id); + ++idx; } - deletedArtifacts.add(idData.identifier); - } // for all fetched data - } - } - catch (SQLException sqle) { - logger.error(sqle.getLocalizedMessage(), sqle); - } - finally { - if (result != null) { - try { result.close(); } - catch (SQLException sqle) {} + ArrayList cs = new ArrayList(); + result = stmnt.executeQuery(); + while (result.next()) { + cs.add(new IdIdentifier( + result.getInt(1), + result.getString(2))); + } + + result.close(); result = null; + stmnt.close(); stmnt = null; + + // delete collection items + stmnt = conn.prepareStatement(SQL_DELETE_COLLECTION_ITEMS); + + for (IdIdentifier id: cs) { + logger.debug("Mark collection for deletion: " + id.id); + stmnt.setInt(1, id.id); + stmnt.execute(); + } + + stmnt.close(); stmnt = null; + + // delete collections + stmnt = conn.prepareStatement(SQL_DELETE_COLLECTION); + + for (IdIdentifier id: cs) { + stmnt.setInt(1, id.id); + stmnt.execute(); + deletedCollections.add(id.identifier); + } + + stmnt.close(); stmnt = null; + conn.commit(); + + cs = null; + + // remove artifacts + stmnt = conn.prepareStatement(SQL_DELETE_ARTIFACT); + + 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.getString(4))); + } + + result.close(); result = null; + + if (ids.isEmpty()) { + break; + } + + for (int i = ids.size()-1; i >= 0; --i) { + IdData idData = ids.get(i); + Artifact artifact = reviver.reviveArtifact( + idData.factoryName, idData.data); + idData.data = null; + + logger.debug("Prepare Artifact (id=" + + idData.id + ") for deletion."); + + stmnt.setInt(1, idData.id); + stmnt.execute(); + conn.commit(); + + try { + if (artifact != null) { + logger.debug("Call endOfLife for Artifact: " + + artifact.identifier()); + + artifact.endOfLife(context); + } + } + catch (Exception e) { + logger.error(e.getMessage(), e); + } + + deletedArtifacts.add(idData.identifier); + } // for all fetched data + } + } + finally { + if (result != null) { + try { result.close(); } + catch (SQLException sqle) {} + } + if (stmnt != null) { + try { stmnt.close(); } + catch (SQLException sqle) {} + } + if (fetchIds != null) { + try { fetchIds.close(); } + catch (SQLException sqle) {} + } + } + return true; } - if (stmnt != null) { - try { stmnt.close(); } - catch (SQLException sqle) {} - } - if (fetchIds != null) { - try { fetchIds.close(); } - catch (SQLException sqle) {} - } - if (connection != null) { - try { connection.close(); } - catch (SQLException sqle) {} - } + }; + + if (!exec.runWriteNoRollback()) { + logger.error("Deleting artifacts failed."); } if (!deletedCollections.isEmpty()) { diff -r 91b1435fb9ea -r 3b1e48d22ce0 artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java Thu Sep 03 11:46:24 2015 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java Thu Sep 03 15:34:07 2015 +0200 @@ -55,6 +55,33 @@ } } + public boolean runWriteNoRollback() { + rwLock.writeLock().lock(); + try { + DataSource dataSource = dbConnection.getDataSource(); + try { + conn = dataSource.getConnection(); + try { + conn.setAutoCommit(false); + return doIt(); + } + catch (SQLException sqle) { + throw sqle; + } + } + catch (SQLException sqle) { + logger.error(sqle.getLocalizedMessage(), sqle); + } + finally { + close(); + } + return false; + } + finally { + rwLock.writeLock().unlock(); + } + } + public boolean runWrite() { rwLock.writeLock().lock(); try {