001: /**
002: * Sequoia: Database clustering technology.
003: * Copyright (C) 2002-2004 French National Institute For Research In Computer
004: * Science And Control (INRIA).
005: * Copyright (C) 2005 AmicoSoft, Inc. dba Emic Networks
006: * Contact: sequoia@continuent.org
007: *
008: * Licensed under the Apache License, Version 2.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: * Initial developer(s): Nicolas Modrzyk.
021: * Contributor(s): ______________________.
022: */package org.continuent.sequoia.controller.cache.result.threads;
023:
024: import java.util.ArrayList;
025: import java.util.Iterator;
026:
027: import org.continuent.sequoia.common.i18n.Translate;
028: import org.continuent.sequoia.common.log.Trace;
029: import org.continuent.sequoia.controller.cache.result.ResultCache;
030: import org.continuent.sequoia.controller.cache.result.entries.ResultCacheEntryEager;
031:
032: /**
033: * This thread manages eager cache entries and remove them from the cache if
034: * they have expired.
035: *
036: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
037: * @version 1.0
038: */
039: public final class EagerCacheThread extends Thread {
040: private final ResultCache cache;
041: private long threadWakeUpTime = 0;
042: int refreshCacheRate = 60;
043: int refreshCacheTime = 60 / refreshCacheRate;
044: private Trace logger = Trace.getLogger(EagerCacheThread.class
045: .getName());
046: private boolean isKilled = false;
047:
048: /**
049: * Creates a new <code>EagerCacheThread</code> object
050: *
051: * @param cache ResultCache creating this thread
052: */
053: public EagerCacheThread(ResultCache cache) {
054: super ("EagerCacheThread");
055: this .cache = cache;
056: }
057:
058: /**
059: * Returns the threadWakeUpTime value.
060: *
061: * @return Returns the threadWakeUpTime.
062: */
063: public long getThreadWakeUpTime() {
064: return threadWakeUpTime;
065: }
066:
067: /**
068: * @see java.lang.Runnable#run()
069: */
070: public void run() {
071: ResultCacheEntryEager entry;
072: long now;
073: long sleep;
074: // Keep trace of relaxed cache entries to delete
075: ArrayList toRemoveFromEagerCache = new ArrayList();
076: while (!isKilled) {
077: synchronized (this ) {
078: try {
079: threadWakeUpTime = 0;
080: if (cache.getEagerCache().isEmpty()) { // Nothing in the cache, just sleep!
081: if (logger.isDebugEnabled())
082: logger
083: .debug(Translate
084: .get("cachethread.cache.empty.sleeping"));
085: wait();
086: } else { // Look for first deadline
087: now = System.currentTimeMillis();
088: for (Iterator iter = cache.getEagerCache()
089: .iterator(); iter.hasNext();) {
090: entry = (ResultCacheEntryEager) iter.next();
091: if (entry.getDeadline() < now) { // Deadline has expired, remove entry
092: toRemoveFromEagerCache.add(entry);
093: continue;
094: }
095:
096: // Recompute next wakeup time
097: if ((threadWakeUpTime == 0)
098: || (entry.getDeadline() < threadWakeUpTime))
099: threadWakeUpTime = entry.getDeadline();
100: }
101:
102: // Clean up all the entries from the eager cache
103: int size = toRemoveFromEagerCache.size();
104: for (int i = 0; i < size; i++) {
105: entry = (ResultCacheEntryEager) toRemoveFromEagerCache
106: .get(i);
107: if (logger.isDebugEnabled())
108: logger
109: .debug(Translate
110: .get(
111: "cachethread.remove.entry.from.cache",
112: entry
113: .getRequest()
114: .getUniqueKey()));
115: try {
116: cache.removeFromCache(entry
117: .getRequest());
118: } catch (Exception e) {
119: logger
120: .warn(
121: "cachethread.remove.entry.error",
122: e);
123: }
124: try {
125: cache.getEagerCache().remove(entry);
126: } catch (Exception e) {
127: logger
128: .warn(
129: "cachethread.remove.entry.error",
130: e);
131: }
132: }
133: toRemoveFromEagerCache.clear();
134: if (threadWakeUpTime == 0) { // All entries were not kept in the cache, therefore
135: // there is no next deadline. (and no cache entry to wait for)
136: continue;
137: } else { // Sleep until the next deadline
138: sleep = (threadWakeUpTime - now) / 1000
139: + refreshCacheTime;
140: if (logger.isDebugEnabled()) {
141: logger.debug(Translate.get(
142: "cachethread.sleeping", sleep));
143: }
144: sleep = (sleep) * 1000;
145: wait(sleep);
146: }
147: }
148: } catch (Exception e) {
149: logger.warn(e.getMessage(), e);
150: }
151: }
152: }
153: }
154:
155: /**
156: * Shutdown the current thread.
157: */
158: public synchronized void shutdown() {
159: isKilled = true;
160: notify();
161: }
162:
163: }
|