001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.tomcat.util.threads;
018:
019: import org.apache.tomcat.util.buf.TimeStamp;
020:
021: /**
022: * Expire unused objects.
023: *
024: */
025: public final class Expirer implements ThreadPoolRunnable {
026: // We can use Event/Listener, but this is probably simpler
027: // and more efficient
028: public static interface ExpireCallback {
029: public void expired(TimeStamp o);
030: }
031:
032: private int checkInterval = 60;
033: private Reaper reaper;
034: ExpireCallback expireCallback;
035:
036: public Expirer() {
037: }
038:
039: // ------------------------------------------------------------- Properties
040: public int getCheckInterval() {
041: return checkInterval;
042: }
043:
044: public void setCheckInterval(int checkInterval) {
045: this .checkInterval = checkInterval;
046: }
047:
048: public void setExpireCallback(ExpireCallback cb) {
049: expireCallback = cb;
050: }
051:
052: // -------------------- Managed objects --------------------
053: static final int INITIAL_SIZE = 8;
054: TimeStamp managedObjs[] = new TimeStamp[INITIAL_SIZE];
055: TimeStamp checkedObjs[] = new TimeStamp[INITIAL_SIZE];
056: int managedLen = managedObjs.length;
057: int managedCount = 0;
058:
059: public void addManagedObject(TimeStamp ts) {
060: synchronized (managedObjs) {
061: if (managedCount >= managedLen) {
062: // What happens if expire is on the way ? Nothing,
063: // expire will do it's job on the old array ( GC magic )
064: // and the expired object will be marked as such
065: // Same thing would happen ( and did ) with Hashtable
066: TimeStamp newA[] = new TimeStamp[2 * managedLen];
067: System.arraycopy(managedObjs, 0, newA, 0, managedLen);
068: managedObjs = newA;
069: managedLen = 2 * managedLen;
070: }
071: managedObjs[managedCount] = ts;
072: managedCount++;
073: }
074: }
075:
076: public void removeManagedObject(TimeStamp ts) {
077: for (int i = 0; i < managedCount; i++) {
078: if (ts == managedObjs[i]) {
079: synchronized (managedObjs) {
080: managedObjs[i] = managedObjs[managedCount - 1];
081: managedCount--;
082: }
083: return;
084: }
085: }
086: }
087:
088: // --------------------------------------------------------- Public Methods
089:
090: public void start() {
091: // Start the background reaper thread
092: if (reaper == null) {
093: reaper = new Reaper("Expirer");
094: reaper.addCallback(this , checkInterval * 1000);
095: }
096:
097: reaper.startReaper();
098: }
099:
100: public void stop() {
101: reaper.stopReaper();
102: }
103:
104: // -------------------------------------------------------- Private Methods
105:
106: // ThreadPoolRunnable impl
107:
108: public Object[] getInitData() {
109: return null;
110: }
111:
112: public void runIt(Object td[]) {
113: long timeNow = System.currentTimeMillis();
114: if (dL > 2)
115: debug("Checking " + timeNow);
116: int checkedCount;
117: synchronized (managedObjs) {
118: checkedCount = managedCount;
119: if (checkedObjs.length < checkedCount)
120: checkedObjs = new TimeStamp[managedLen];
121: System.arraycopy(managedObjs, 0, checkedObjs, 0,
122: checkedCount);
123: }
124: for (int i = 0; i < checkedCount; i++) {
125: TimeStamp ts = checkedObjs[i];
126: checkedObjs[i] = null;
127:
128: if (ts == null || !ts.isValid())
129: continue;
130:
131: long maxInactiveInterval = ts.getMaxInactiveInterval();
132: if (dL > 3)
133: debug("TS: " + maxInactiveInterval + " "
134: + ts.getLastAccessedTime());
135: if (maxInactiveInterval < 0)
136: continue;
137:
138: long timeIdle = timeNow - ts.getThisAccessedTime();
139:
140: if (timeIdle >= maxInactiveInterval) {
141: if (expireCallback != null) {
142: if (dL > 0)
143: debug(ts + " " + timeIdle + " "
144: + maxInactiveInterval);
145: expireCallback.expired(ts);
146: }
147: }
148: }
149: }
150:
151: private static final int dL = 0;
152:
153: private void debug(String s) {
154: System.out.println("Expirer: " + s);
155: }
156: }
|