001: /*
002: * Licensed under the X license (see http://www.x.org/terms.htm)
003: */
004: package org.ofbiz.minerva.pool;
005:
006: import java.util.HashSet;
007: import java.util.Iterator;
008:
009: import org.apache.log4j.Logger;
010:
011: /**
012: * Runs garbage collection on all available pools. Only one GC thread is
013: * created, no matter how many pools there are - it just tries to calculate
014: * the next time it should run based on the figues for all the pools. It will
015: * run on any pools which are "pretty close" to their requested time.
016: *
017: * @author Aaron Mulder (ammulder@alumni.princeton.edu)
018: * @version $Revision: 1.2 $
019: */
020: class PoolGCThread extends Thread {
021:
022: private HashSet pools = new HashSet();
023: private static Logger log = Logger.getLogger(ObjectPool.class);
024:
025: PoolGCThread() {
026: super ("Minerva ObjectPool GC Thread");
027: setDaemon(true);
028: }
029:
030: public void run() {
031: boolean trace = true;
032: while (true) {
033: // Don't do anything while there's nothing to do
034: waitForPools();
035: if (trace)
036: log.debug("gc thread waited for pools");
037:
038: // Figure out how long to sleep
039: long delay = getDelay();
040: if (trace)
041: log.debug("gc thread delay: " + delay);
042:
043: // Sleep
044: if (delay > 0l) {
045: try {
046: sleep(delay);
047: } catch (InterruptedException ignored) {
048: }
049: }
050:
051: // Run garbage collection on eligible pools
052: runGC();
053: }
054: }
055:
056: private synchronized void waitForPools() {
057: while (pools.size() == 0) {
058: try {
059: wait();
060: } catch (InterruptedException ignored) {
061: // Warning level seems appropriate; shouldn't really happen
062: log.warn("waitForPools interrupted");
063: }
064: }
065: }
066:
067: private synchronized long getDelay() {
068: long next = Long.MAX_VALUE;
069: long now = System.currentTimeMillis();
070: long current;
071:
072: for (Iterator it = pools.iterator(); it.hasNext();) {
073: ObjectPool pool = (ObjectPool) it.next();
074: current = pool.getNextGCMillis(now);
075: if (current < next)
076: next = current;
077: }
078: return next >= 0l ? next : 0l;
079: }
080:
081: private synchronized void runGC() {
082: boolean trace = true;
083:
084: if (trace)
085: log.debug("GC thread running GC");
086:
087: for (Iterator it = pools.iterator(); it.hasNext();) {
088: ObjectPool pool = (ObjectPool) it.next();
089:
090: if (trace)
091: log.debug("GC Thread pool: " + pool.getName()
092: + ", isTimeToGC(): " + pool.isTimeToGC());
093:
094: if (pool.isTimeToGC())
095: pool.runGCandShrink();
096: }
097: }
098:
099: synchronized void addPool(ObjectPool pool) {
100: if (log.isDebugEnabled())
101: log.debug("Adding pool: " + pool.getName()
102: + ", GC enabled: " + pool.isGCEnabled());
103:
104: if (pool.isGCEnabled())
105: pools.add(pool);
106:
107: notify();
108: }
109:
110: synchronized void removePool(ObjectPool pool) {
111: if (log.isDebugEnabled())
112: log.debug("Removing pool: " + pool.getName());
113:
114: pools.remove(pool);
115: }
116: }
117:
118: /*
119: vim:tabstop=3:et:shiftwidth=3
120: */
|