changeset 541:3b1e48d22ce0

Experimentally let database cleaner and backend share the same sql executor.
author Sascha L. Teichmann <teichmann@intevation.de>
date Thu, 03 Sep 2015 15:34:07 +0200
parents 91b1435fb9ea
children 9497f58484a0
files artifact-database/src/main/java/org/dive4elements/artifactdatabase/App.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/Backend.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java artifact-database/src/main/java/org/dive4elements/artifactdatabase/db/SQLExecutor.java
diffstat 4 files changed, 179 insertions(+), 139 deletions(-) [+]
line wrap: on
line diff
--- 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();
 
--- 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();
--- 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<Integer> lockedIds = lockedIdsProvider != null
+        final Set<Integer> 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<String> deletedCollections = new ArrayList<String>();
-        List<String> deletedArtifacts   = new ArrayList<String>();
-
-        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<IdIdentifier> cs = new ArrayList<IdIdentifier>();
-            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<String> deletedCollections = new ArrayList<String>();
+        final List<String> deletedArtifacts   = new ArrayList<String>();
 
-            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<IdData> ids = new ArrayList<IdData>();
-
-                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<IdIdentifier> cs = new ArrayList<IdIdentifier>();
+                    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<IdData> ids = new ArrayList<IdData>();
+
+                        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()) {
--- 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 {

http://dive4elements.wald.intevation.org