Mercurial > dive4elements > framework
comparison artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java @ 30:88972c6daa4f
Added a cleanup thread which periodically removes
outdated artifacts from database and calls there
endOfLife() method.
artifacts/trunk@70 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author | Sascha L. Teichmann <sascha.teichmann@intevation.de> |
---|---|
date | Thu, 10 Sep 2009 23:16:18 +0000 |
parents | |
children | c2d53bd30ab8 |
comparison
equal
deleted
inserted
replaced
29:22b03d5c84c5 | 30:88972c6daa4f |
---|---|
1 package de.intevation.artifactdatabase; | |
2 | |
3 import de.intevation.artifacts.Artifact; | |
4 | |
5 import java.sql.Connection; | |
6 import java.sql.SQLException; | |
7 import java.sql.PreparedStatement; | |
8 import java.sql.ResultSet; | |
9 | |
10 import javax.sql.DataSource; | |
11 | |
12 import org.apache.log4j.Logger; | |
13 | |
14 import java.util.ArrayList; | |
15 | |
16 /** | |
17 * @author Sascha L. Teichmann | |
18 */ | |
19 public class DatabaseCleaner | |
20 extends Thread | |
21 { | |
22 private static Logger logger = Logger.getLogger(DatabaseCleaner.class); | |
23 | |
24 public static final int MAX_ROWS = 50; | |
25 | |
26 public static final String SQL_OUTDATED = | |
27 SQL.get("artifacts.outdated"); | |
28 | |
29 public static final String SQL_DELETE = | |
30 SQL.get("artifacts.delete"); | |
31 | |
32 public static final String SLEEP_XPATH = | |
33 "/artifact-database/cleaner/sleep-time/text()"; | |
34 | |
35 public static final long SLEEP_DEFAULT = | |
36 5 * 60 * 1000L; // 5 minutes | |
37 | |
38 protected long sleepTime; | |
39 | |
40 protected Object sleepLock = new Object(); | |
41 | |
42 protected Object context; | |
43 | |
44 public DatabaseCleaner() { | |
45 } | |
46 | |
47 public DatabaseCleaner(Object context) { | |
48 setDaemon(true); | |
49 sleepTime = getSleepTime(); | |
50 this.context = context; | |
51 } | |
52 | |
53 public void wakeup() { | |
54 synchronized (sleepLock) { | |
55 sleepLock.notify(); | |
56 } | |
57 } | |
58 | |
59 protected static long getSleepTime() { | |
60 String sleepTimeString = Config.getStringXPath(SLEEP_XPATH); | |
61 | |
62 if (sleepTimeString == null) { | |
63 return SLEEP_DEFAULT; | |
64 } | |
65 try { | |
66 // sleep at least one second | |
67 return Math.max(Long.parseLong(sleepTimeString), 1000L); | |
68 } | |
69 catch (NumberFormatException nfe) { | |
70 logger.warn("Cleaner sleep time defaults to " + SLEEP_DEFAULT); | |
71 } | |
72 return SLEEP_DEFAULT; | |
73 } | |
74 | |
75 private static final class IdData { | |
76 | |
77 int id; | |
78 byte [] data; | |
79 | |
80 public IdData(int id, byte [] data) { | |
81 this.id = id; | |
82 this.data = data; | |
83 } | |
84 } // class IdData | |
85 | |
86 /** | |
87 * Cleaning is done in two phases. First we fetch a list of ids | |
88 * of artifacts. If there are artifacts the cleaning is done. | |
89 * Second we load the artifacts one by one one and call there | |
90 * endOfLife() method. In this loop we remove them from database, too. | |
91 * Each deletion is commited to ensure that a sudden failure | |
92 * of the artifact database server does delete artifacts twice | |
93 * or does not delete them at all. After this the first step | |
94 * is repeated. | |
95 */ | |
96 protected void cleanup() { | |
97 logger.info("database cleanup"); | |
98 | |
99 Connection connection = null; | |
100 PreparedStatement fetchIds = null; | |
101 PreparedStatement deleteId = null; | |
102 ResultSet result = null; | |
103 | |
104 int removedArtifacts = 0; | |
105 | |
106 DataSource dataSource = DBConnection.getDataSource(); | |
107 try { | |
108 connection = dataSource.getConnection(); | |
109 connection.setAutoCommit(false); | |
110 fetchIds = connection.prepareStatement(SQL_OUTDATED); | |
111 deleteId = connection.prepareStatement(SQL_DELETE); | |
112 | |
113 // some dbms like derby do not support LIMIT | |
114 // in SQL statements. | |
115 fetchIds.setMaxRows(MAX_ROWS); | |
116 | |
117 for (;;) { | |
118 ArrayList ids = new ArrayList(); | |
119 | |
120 result = fetchIds.executeQuery(); | |
121 | |
122 while (result.next()) { | |
123 ids.add(new IdData( | |
124 result.getInt(1), result.getBytes(2))); | |
125 } | |
126 | |
127 result.close(); result = null; | |
128 | |
129 if (ids.isEmpty()) { | |
130 break; | |
131 } | |
132 | |
133 for (int i = ids.size()-1; i >= 0; --i) { | |
134 IdData idData = (IdData)ids.get(i); | |
135 Artifact artifact = Backend.restoreArtifact( | |
136 idData.data); | |
137 idData.data = null; | |
138 | |
139 deleteId.setInt(1, idData.id); | |
140 deleteId.execute(); | |
141 connection.commit(); | |
142 | |
143 try { | |
144 if (artifact != null) { | |
145 artifact.endOfLife(context); | |
146 } | |
147 } | |
148 catch (Exception e) { | |
149 logger.error(e.getLocalizedMessage(), e); | |
150 } | |
151 } // for all fetched data | |
152 | |
153 removedArtifacts += ids.size(); | |
154 } | |
155 } | |
156 catch (SQLException sqle) { | |
157 logger.error(sqle.getLocalizedMessage(), sqle); | |
158 } | |
159 finally { | |
160 if (result != null) { | |
161 try { result.close(); } | |
162 catch (SQLException sqle) {} | |
163 } | |
164 if (fetchIds != null) { | |
165 try { fetchIds.close(); } | |
166 catch (SQLException sqle) {} | |
167 } | |
168 if (deleteId != null) { | |
169 try { deleteId.close(); } | |
170 catch (SQLException sqle) {} | |
171 } | |
172 if (connection != null) { | |
173 try { connection.close(); } | |
174 catch (SQLException sqle) {} | |
175 } | |
176 } | |
177 | |
178 logger.info("artifacts removed: " + removedArtifacts); | |
179 } | |
180 | |
181 public void run() { | |
182 logger.info("sleep time: " + sleepTime + "ms"); | |
183 for (;;) { | |
184 cleanup(); | |
185 try { | |
186 synchronized (sleepLock) { | |
187 sleepLock.wait(sleepTime); | |
188 } | |
189 } | |
190 catch (InterruptedException ie) { | |
191 } | |
192 } // for (;;) | |
193 } | |
194 } | |
195 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8: |