comparison artifact-database/src/main/java/org/dive4elements/artifactdatabase/DatabaseCleaner.java @ 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 415df0fc4fa1
children 9497f58484a0
comparison
equal deleted inserted replaced
540:91b1435fb9ea 541:3b1e48d22ce0
12 import org.dive4elements.artifacts.common.utils.StringUtils; 12 import org.dive4elements.artifacts.common.utils.StringUtils;
13 13
14 import org.dive4elements.artifacts.Artifact; 14 import org.dive4elements.artifacts.Artifact;
15 15
16 import org.dive4elements.artifactdatabase.db.SQL; 16 import org.dive4elements.artifactdatabase.db.SQL;
17 import org.dive4elements.artifactdatabase.db.SQLExecutor;
17 import org.dive4elements.artifactdatabase.db.DBConnection; 18 import org.dive4elements.artifactdatabase.db.DBConnection;
18 19
19 import java.sql.Connection; 20 import java.sql.Connection;
20 import java.sql.PreparedStatement; 21 import java.sql.PreparedStatement;
21 import java.sql.ResultSet; 22 import java.sql.ResultSet;
133 * The reviver used to bring the dead artifact on last 134 * The reviver used to bring the dead artifact on last
134 * time back to live to call endOfLife() on them. 135 * time back to live to call endOfLife() on them.
135 */ 136 */
136 protected ArtifactReviver reviver; 137 protected ArtifactReviver reviver;
137 138
138 protected DBConnection dbConnection; 139 protected SQLExecutor sqlExecutor;
139 140
140 /** 141 /**
141 * Default constructor. 142 * Default constructor.
142 */ 143 */
143 public DatabaseCleaner() { 144 public DatabaseCleaner() {
147 * Constructor to create a cleaner with a given global context 148 * Constructor to create a cleaner with a given global context
148 * and a given reviver. 149 * and a given reviver.
149 * @param context The global context of the artifact database 150 * @param context The global context of the artifact database
150 * @param reviver The reviver to awake artifact one last time. 151 * @param reviver The reviver to awake artifact one last time.
151 */ 152 */
152 public DatabaseCleaner(Object context, ArtifactReviver reviver, DBConfig config) { 153 public DatabaseCleaner(
154 Object context,
155 ArtifactReviver reviver,
156 SQLExecutor sqlExecutor,
157 DBConfig config
158 ) {
153 setDaemon(true); 159 setDaemon(true);
154 sleepTime = getSleepTime(); 160 sleepTime = getSleepTime();
155 this.context = context; 161 this.context = context;
156 this.reviver = reviver; 162 this.reviver = reviver;
157 this.dbConnection = config.getDBConnection(); 163 this.sqlExecutor = sqlExecutor;
158 setupSQL(config.getSQL()); 164 setupSQL(config.getSQL());
159 } 165 }
160 166
161 protected void setupSQL(SQL sql) { 167 protected void setupSQL(SQL sql) {
162 SQL_OUTDATED = sql.get("artifacts.outdated"); 168 SQL_OUTDATED = sql.get("artifacts.outdated");
247 * is repeated. 253 * is repeated.
248 */ 254 */
249 protected void cleanup() { 255 protected void cleanup() {
250 logger.info("database cleanup"); 256 logger.info("database cleanup");
251 257
252 Connection connection = null; 258 final Set<Integer> lockedIds = lockedIdsProvider != null
253 PreparedStatement fetchIds = null;
254 PreparedStatement stmnt = null;
255 ResultSet result = null;
256
257 DataSource dataSource = dbConnection.getDataSource();
258
259 Set<Integer> lockedIds = lockedIdsProvider != null
260 ? lockedIdsProvider.getLockedIds() 259 ? lockedIdsProvider.getLockedIds()
261 : EMPTY_IDS; 260 : EMPTY_IDS;
262 261
263 String questionMarks = lockedIds.isEmpty() 262 final String questionMarks = lockedIds.isEmpty()
264 ? "-666" // XXX: A bit hackish. 263 ? "-666" // XXX: A bit hackish.
265 : StringUtils.repeat('?', lockedIds.size(), ','); 264 : StringUtils.repeat('?', lockedIds.size(), ',');
266 265
267 List<String> deletedCollections = new ArrayList<String>(); 266 final List<String> deletedCollections = new ArrayList<String>();
268 List<String> deletedArtifacts = new ArrayList<String>(); 267 final List<String> deletedArtifacts = new ArrayList<String>();
269 268
270 try { 269 SQLExecutor.Instance exec = sqlExecutor.new Instance() {
271 connection = dataSource.getConnection(); 270
272 connection.setAutoCommit(false); 271 @Override
273 272 public boolean doIt() throws SQLException {
274 fetchIds = connection.prepareStatement( 273
275 SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks)); 274 PreparedStatement fetchIds = null;
276 275 PreparedStatement stmnt = null;
277 // some dbms like derby do not support LIMIT 276 ResultSet result = null;
278 // in SQL statements. 277
279 fetchIds.setMaxRows(MAX_ROWS); 278 try {
280 279 fetchIds = conn.prepareStatement(
281 // Fetch ids of outdated collections 280 SQL_OUTDATED.replace("$LOCKED_IDS$", questionMarks));
282 stmnt = connection.prepareStatement( 281
283 SQL_OUTDATED_COLLECTIONS.replace( 282 // some dbms like derby do not support LIMIT
284 "$LOCKED_IDS$", questionMarks)); 283 // in SQL statements.
285 284 fetchIds.setMaxRows(MAX_ROWS);
286 // fill in the locked ids 285
287 int idx = 1; 286 // Fetch ids of outdated collections
288 for (Integer id: lockedIds) { 287 stmnt = conn.prepareStatement(
289 fetchIds.setInt(idx, id); 288 SQL_OUTDATED_COLLECTIONS.replace(
290 stmnt .setInt(idx, id); 289 "$LOCKED_IDS$", questionMarks));
291 ++idx; 290
291 // fill in the locked ids
292 int idx = 1;
293 for (Integer id: lockedIds) {
294 fetchIds.setInt(idx, id);
295 stmnt .setInt(idx, id);
296 ++idx;
297 }
298
299 ArrayList<IdIdentifier> cs = new ArrayList<IdIdentifier>();
300 result = stmnt.executeQuery();
301 while (result.next()) {
302 cs.add(new IdIdentifier(
303 result.getInt(1),
304 result.getString(2)));
305 }
306
307 result.close(); result = null;
308 stmnt.close(); stmnt = null;
309
310 // delete collection items
311 stmnt = conn.prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
312
313 for (IdIdentifier id: cs) {
314 logger.debug("Mark collection for deletion: " + id.id);
315 stmnt.setInt(1, id.id);
316 stmnt.execute();
317 }
318
319 stmnt.close(); stmnt = null;
320
321 // delete collections
322 stmnt = conn.prepareStatement(SQL_DELETE_COLLECTION);
323
324 for (IdIdentifier id: cs) {
325 stmnt.setInt(1, id.id);
326 stmnt.execute();
327 deletedCollections.add(id.identifier);
328 }
329
330 stmnt.close(); stmnt = null;
331 conn.commit();
332
333 cs = null;
334
335 // remove artifacts
336 stmnt = conn.prepareStatement(SQL_DELETE_ARTIFACT);
337
338 for (;;) {
339 List<IdData> ids = new ArrayList<IdData>();
340
341 result = fetchIds.executeQuery();
342
343 while (result.next()) {
344 ids.add(new IdData(
345 result.getInt(1),
346 result.getString(2),
347 result.getBytes(3),
348 result.getString(4)));
349 }
350
351 result.close(); result = null;
352
353 if (ids.isEmpty()) {
354 break;
355 }
356
357 for (int i = ids.size()-1; i >= 0; --i) {
358 IdData idData = ids.get(i);
359 Artifact artifact = reviver.reviveArtifact(
360 idData.factoryName, idData.data);
361 idData.data = null;
362
363 logger.debug("Prepare Artifact (id="
364 + idData.id + ") for deletion.");
365
366 stmnt.setInt(1, idData.id);
367 stmnt.execute();
368 conn.commit();
369
370 try {
371 if (artifact != null) {
372 logger.debug("Call endOfLife for Artifact: "
373 + artifact.identifier());
374
375 artifact.endOfLife(context);
376 }
377 }
378 catch (Exception e) {
379 logger.error(e.getMessage(), e);
380 }
381
382 deletedArtifacts.add(idData.identifier);
383 } // for all fetched data
384 }
385 }
386 finally {
387 if (result != null) {
388 try { result.close(); }
389 catch (SQLException sqle) {}
390 }
391 if (stmnt != null) {
392 try { stmnt.close(); }
393 catch (SQLException sqle) {}
394 }
395 if (fetchIds != null) {
396 try { fetchIds.close(); }
397 catch (SQLException sqle) {}
398 }
399 }
400 return true;
292 } 401 }
293 402 };
294 ArrayList<IdIdentifier> cs = new ArrayList<IdIdentifier>(); 403
295 result = stmnt.executeQuery(); 404 if (!exec.runWriteNoRollback()) {
296 while (result.next()) { 405 logger.error("Deleting artifacts failed.");
297 cs.add(new IdIdentifier(
298 result.getInt(1),
299 result.getString(2)));
300 }
301
302 result.close(); result = null;
303 stmnt.close(); stmnt = null;
304
305 // delete collection items
306 stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION_ITEMS);
307
308 for (IdIdentifier id: cs) {
309 logger.debug("Mark collection for deletion: " + id.id);
310 stmnt.setInt(1, id.id);
311 stmnt.execute();
312 }
313
314 stmnt.close(); stmnt = null;
315
316 // delete collections
317 stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION);
318
319 for (IdIdentifier id: cs) {
320 stmnt.setInt(1, id.id);
321 stmnt.execute();
322 deletedCollections.add(id.identifier);
323 }
324
325 stmnt.close(); stmnt = null;
326 connection.commit();
327
328 cs = null;
329
330 // remove artifacts
331 stmnt = connection.prepareStatement(SQL_DELETE_ARTIFACT);
332
333 for (;;) {
334 List<IdData> ids = new ArrayList<IdData>();
335
336 result = fetchIds.executeQuery();
337
338 while (result.next()) {
339 ids.add(new IdData(
340 result.getInt(1),
341 result.getString(2),
342 result.getBytes(3),
343 result.getString(4)));
344 }
345
346 result.close(); result = null;
347
348 if (ids.isEmpty()) {
349 break;
350 }
351
352 for (int i = ids.size()-1; i >= 0; --i) {
353 IdData idData = ids.get(i);
354 Artifact artifact = reviver.reviveArtifact(
355 idData.factoryName, idData.data);
356 idData.data = null;
357
358 logger.debug("Prepare Artifact (id="
359 + idData.id + ") for deletion.");
360
361 stmnt.setInt(1, idData.id);
362 stmnt.execute();
363 connection.commit();
364
365 try {
366 if (artifact != null) {
367 logger.debug("Call endOfLife for Artifact: "
368 + artifact.identifier());
369
370 artifact.endOfLife(context);
371 }
372 }
373 catch (Exception e) {
374 logger.error(e.getMessage(), e);
375 }
376
377 deletedArtifacts.add(idData.identifier);
378 } // for all fetched data
379 }
380 }
381 catch (SQLException sqle) {
382 logger.error(sqle.getLocalizedMessage(), sqle);
383 }
384 finally {
385 if (result != null) {
386 try { result.close(); }
387 catch (SQLException sqle) {}
388 }
389 if (stmnt != null) {
390 try { stmnt.close(); }
391 catch (SQLException sqle) {}
392 }
393 if (fetchIds != null) {
394 try { fetchIds.close(); }
395 catch (SQLException sqle) {}
396 }
397 if (connection != null) {
398 try { connection.close(); }
399 catch (SQLException sqle) {}
400 }
401 } 406 }
402 407
403 if (!deletedCollections.isEmpty()) { 408 if (!deletedCollections.isEmpty()) {
404 reviver.killedCollections(deletedCollections); 409 reviver.killedCollections(deletedCollections);
405 } 410 }

http://dive4elements.wald.intevation.org