KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > proxool > HouseKeeper


1 /*
2  * This software is released under a licence similar to the Apache Software Licence.
3  * See org.logicalcobwebs.proxool.package.html for details.
4  * The latest version is available at http://proxool.sourceforge.net
5  */

6 package org.logicalcobwebs.proxool;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10
11 import java.sql.Connection JavaDoc;
12 import java.sql.Statement JavaDoc;
13
14 /**
15  * Responisble for house keeping one pool
16  *
17  * @version $Revision: 1.5 $, $Date: 2006/01/18 14:40:01 $
18  * @author bill
19  * @author $Author: billhorsman $ (current maintainer)
20  * @since Proxool 0.8
21  */

22 class HouseKeeper {
23
24     private static final Log LOG = LogFactory.getLog(HouseKeeper.class);
25
26     private ConnectionPool connectionPool;
27
28     private long timeLastSwept;
29
30     public HouseKeeper(ConnectionPool connectionPool) {
31         this.connectionPool = connectionPool;
32     }
33
34    protected void sweep() throws ProxoolException {
35        ConnectionPoolDefinitionIF definition = connectionPool.getDefinition();
36        Log log = connectionPool.getLog();
37        Statement JavaDoc testStatement = null;
38        try {
39
40            connectionPool.acquirePrimaryReadLock();
41
42            // Right, now we know we're the right thread then we can carry on house keeping
43
Connection JavaDoc connection = null;
44            ProxyConnectionIF proxyConnection = null;
45
46            int recentlyStartedActiveConnectionCountTemp = 0;
47
48            // sanity check
49
int[] verifiedConnectionCountByState = new int[4];
50
51            ProxyConnectionIF[] proxyConnections = connectionPool.getProxyConnections();
52            for (int i = 0; i < proxyConnections.length; i++) {
53                proxyConnection = proxyConnections[i];
54                connection = proxyConnection.getConnection();
55
56                if (!connectionPool.isConnectionPoolUp()) {
57                    break;
58                }
59
60                // First lets check whether the connection still works. We should only validate
61
// connections that are not is use! SetOffline only succeeds if the connection
62
// is available.
63
if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_OFFLINE)) {
64                    try {
65                        testStatement = connection.createStatement();
66
67                        // Some DBs return an object even if DB is shut down
68
if (proxyConnection.isReallyClosed()) {
69                            proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL);
70                            connectionPool.removeProxyConnection(proxyConnection, "it appears to be closed", ConnectionPool.FORCE_EXPIRY, true);
71                        }
72
73                        String JavaDoc sql = definition.getHouseKeepingTestSql();
74                        if (sql != null && sql.length() > 0) {
75                            // A Test Statement has been provided. Execute it!
76
boolean testResult = false;
77                            try {
78                                testResult = testStatement.execute(sql);
79                            } finally {
80                                if (log.isDebugEnabled() && definition.isVerbose()) {
81                                    log.debug(connectionPool.displayStatistics() + " - Testing connection " + proxyConnection.getId() + (testResult ? ": True" : ": False"));
82                                }
83                            }
84                        }
85
86                        proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_AVAILABLE);
87                    } catch (Throwable JavaDoc e) {
88                        // There is a problem with this connection. Let's remove it!
89
proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL);
90                        connectionPool.removeProxyConnection(proxyConnection, "it has problems: " + e, ConnectionPool.REQUEST_EXPIRY, true);
91                    } finally {
92                        try {
93                            testStatement.close();
94                        } catch (Throwable JavaDoc t) {
95                            // Never mind.
96
}
97                    }
98                } // END if (poolableConnection.setOffline())
99
// Now to check whether the connection is due for expiry
100
if (proxyConnection.getAge() > definition.getMaximumConnectionLifetime()) {
101                    final String JavaDoc reason = "age is " + proxyConnection.getAge() + "ms";
102                    // Check whether we can make it offline
103
if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_AVAILABLE, ProxyConnectionIF.STATUS_OFFLINE)) {
104                        if (proxyConnection.setStatus(ProxyConnectionIF.STATUS_OFFLINE, ProxyConnectionIF.STATUS_NULL)) {
105                            // It is. Expire it now .
106
connectionPool.expireProxyConnection(proxyConnection, reason, ConnectionPool.REQUEST_EXPIRY);
107                        }
108                    } else {
109                        // Oh no, it's in use. Never mind, we'll mark it for expiry
110
// next time it is available. This will happen in the
111
// putConnection() method.
112
proxyConnection.markForExpiry(reason);
113                        if (log.isDebugEnabled()) {
114                            log.debug(connectionPool.displayStatistics() + " - #" + FormatHelper.formatMediumNumber(proxyConnection.getId())
115                                    + " marked for expiry.");
116                        }
117                    } // END if (poolableConnection.setOffline())
118
} // END if (poolableConnection.getAge() > maximumConnectionLifetime)
119

120                // Now let's see if this connection has been active for a
121
// suspiciously long time.
122
if (proxyConnection.isActive()) {
123
124                    long activeTime = System.currentTimeMillis() - proxyConnection.getTimeLastStartActive();
125
126                    if (activeTime < definition.getRecentlyStartedThreshold()) {
127
128                        // This connection hasn't been active for all that long
129
// after all. And as long as we have at least one
130
// connection that is "actively active" then we don't
131
// consider the pool to be down.
132
recentlyStartedActiveConnectionCountTemp++;
133                    }
134
135                    if (activeTime > definition.getMaximumActiveTime()) {
136
137                        // This connection has been active for way too long. We're
138
// going to kill it :)
139
connectionPool.removeProxyConnection(proxyConnection,
140                                "it has been active for too long", ConnectionPool.FORCE_EXPIRY, true);
141                        String JavaDoc lastSqlCallMsg;
142                        if (proxyConnection.getLastSqlCall() != null) {
143                            lastSqlCallMsg = ", and the last SQL it performed is '" + proxyConnection.getLastSqlCall() + "'.";
144                        } else if (!proxyConnection.getDefinition().isTrace()) {
145                            lastSqlCallMsg = ", but the last SQL it performed is unknown because the trace property is not enabled.";
146                        } else {
147                            lastSqlCallMsg = ", but the last SQL it performed is unknown.";
148                        }
149                        log.warn("#" + FormatHelper.formatMediumNumber(proxyConnection.getId()) + " was active for " + activeTime
150                                + " milliseconds and has been removed automaticaly. The Thread responsible was named '"
151                                + proxyConnection.getRequester() + "'" + lastSqlCallMsg);
152
153                    }
154
155                }
156
157                // What have we got?
158
verifiedConnectionCountByState[proxyConnection.getStatus()]++;
159
160            }
161
162            calculateUpState(recentlyStartedActiveConnectionCountTemp);
163        } catch (Throwable JavaDoc e) {
164            // We don't want the housekeeping thread to fall over!
165
log.error("Housekeeping log.error( :", e);
166        } finally {
167            connectionPool.releasePrimaryReadLock();
168            timeLastSwept = System.currentTimeMillis();
169            if (definition.isVerbose()) {
170                if (log.isDebugEnabled()) {
171                    log.debug(connectionPool.displayStatistics() + " - House keeping triggerSweep done");
172                }
173            }
174        }
175
176        PrototyperController.triggerSweep(definition.getAlias());
177
178    }
179
180     /**
181      * Get the time since the last sweep was completed
182      * @return timeSinceLastSweep (milliseconds)
183      */

184     private long getTimeSinceLastSweep() {
185         return System.currentTimeMillis() - timeLastSwept;
186     }
187
188     /**
189      * Should we sleep
190      * @return true if the time since the last sweep was completed is greater
191      * than the {@link ConnectionPoolDefinitionIF#getHouseKeepingSleepTime houseKeepingSleepTime}
192      * property.
193      */

194     protected boolean isSweepDue() {
195         if (connectionPool.isConnectionPoolUp()) {
196             return (getTimeSinceLastSweep() > connectionPool.getDefinition().getHouseKeepingSleepTime());
197         } else {
198             LOG.warn("House keeper is still being asked to sweep despite the connection pool being down");
199             return false;
200         }
201     }
202
203     private void calculateUpState(int recentlyStartedActiveConnectionCount) {
204
205         try {
206
207             int calculatedUpState = StateListenerIF.STATE_QUIET;
208
209 /* We're up if the last time we tried to make a connection it
210              * was successful
211              */

212
213 /* I've changed the way we do this. Just because we failed to create
214              * a connection doesn't mean we're down. As long as we have some
215              * available connections, or the active ones we have aren't locked
216              * up then we should be able to struggle on. The last thing we want
217              * to do is say we're down when we're not!
218              */

219
220             // if (this.lastCreateWasSuccessful) {
221
final int availableConnectionCount = connectionPool.getAvailableConnectionCount();
222             if (availableConnectionCount > 0 || recentlyStartedActiveConnectionCount > 0) {
223
224 /* Defintion of overloaded is that we refused a connection
225                  * (because we were too busy) within the last minute.
226                  */

227
228                 if (connectionPool.getTimeOfLastRefusal() > (System.currentTimeMillis()
229                         - connectionPool.getDefinition().getOverloadWithoutRefusalLifetime())) {
230                     calculatedUpState = StateListenerIF.STATE_OVERLOADED;
231                 } else if (connectionPool.getActiveConnectionCount() > 0) {
232                     /* Are we doing anything at all?
233                  */

234                     calculatedUpState = StateListenerIF.STATE_BUSY;
235                 }
236
237             } else {
238                 calculatedUpState = StateListenerIF.STATE_DOWN;
239             }
240
241             connectionPool.setUpState(calculatedUpState);
242
243         } catch (Exception JavaDoc e) {
244             LOG.error(e);
245         }
246     }
247
248     /**
249      * Identifies the pool we are sweeping
250      * @return alias
251      */

252     protected String JavaDoc getAlias() {
253         return connectionPool.getDefinition().getAlias();
254     }
255
256 }
257
258
259 /*
260  Revision history:
261  $Log: HouseKeeper.java,v $
262  Revision 1.5 2006/01/18 14:40:01 billhorsman
263  Unbundled Jakarta's Commons Logging.
264
265  Revision 1.4 2005/10/02 12:35:06 billhorsman
266  Improve message when closing a connection that has been active for too long
267
268  Revision 1.3 2003/09/11 23:57:48 billhorsman
269  Test SQL now traps Throwable, not just SQLException.
270
271  Revision 1.2 2003/03/10 15:26:46 billhorsman
272  refactoringn of concurrency stuff (and some import
273  optimisation)
274
275  Revision 1.1 2003/03/05 18:42:33 billhorsman
276  big refactor of prototyping and house keeping to
277  drastically reduce the number of threads when using
278  many pools
279
280  */
Popular Tags