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.ResultCacheEntryRelaxed;
031:
032: /**
033: * This thread manages relaxed cache entries and remove them from the cache if
034: * their deadline has expired or they are dirty.
035: *
036: * @author <a href="mailto:Nicolas.Modrzyk@inrialpes.fr">Nicolas Modrzyk </a>
037: * @version 1.0
038: */
039: public final class RelaxedCacheThread extends Thread {
040: private long threadWakeUpTime = 0;
041: private final ResultCache cache;
042: int refreshCacheRate = 60;
043: int refreshCacheTime = 60 / refreshCacheRate;
044: private Trace logger = Trace.getLogger(RelaxedCacheThread.class
045: .getName());
046:
047: private boolean isKilled = false;
048:
049: /**
050: * Creates a new <code>RelaxedCacheThread</code> object
051: *
052: * @param cache ResultCache creating this thread
053: */
054: public RelaxedCacheThread(ResultCache cache) {
055: super ("RelaxedCacheThread");
056: this .cache = cache;
057: }
058:
059: /**
060: * Creates a new <code>RelaxedCacheThread</code> object
061: *
062: * @param cache ResultCache creating this thread
063: * @param refreshCacheRate cache refresh rate in seconds
064: */
065: public RelaxedCacheThread(ResultCache cache, int refreshCacheRate) {
066: this (cache);
067: this .refreshCacheRate = refreshCacheRate;
068: }
069:
070: /**
071: * Returns the threadWakeUpTime value.
072: *
073: * @return Returns the threadWakeUpTime.
074: */
075: public long getThreadWakeUpTime() {
076: return threadWakeUpTime;
077: }
078:
079: /**
080: * @see java.lang.Runnable#run()
081: */
082: public void run() {
083: ResultCacheEntryRelaxed entry;
084: long now;
085: long sleep;
086: // Keep trace of relaxed cache entries to delete
087: ArrayList toRemoveFromRelaxedCache = new ArrayList();
088: while (!isKilled) {
089: synchronized (this ) {
090: try {
091: threadWakeUpTime = 0;
092: if (cache.getRelaxedCache().isEmpty()) { // Nothing in the cache, just sleep!
093: if (logger.isDebugEnabled())
094: logger
095: .debug(Translate
096: .get("cachethread.cache.empty.sleeping"));
097: wait();
098: } else { // Look for first deadline
099: now = System.currentTimeMillis();
100: for (Iterator iter = cache.getRelaxedCache()
101: .iterator(); iter.hasNext();) {
102: entry = (ResultCacheEntryRelaxed) iter
103: .next();
104: if (entry.getDeadline() < now) { // Deadline has expired
105: if (entry.isDirty()
106: || !entry.getKeepIfNotDirty()) { // Remove this entry
107: toRemoveFromRelaxedCache.add(entry);
108: continue;
109: } else
110: // Entry is still valid, reset deadline
111: entry.setDeadline(now
112: + entry.getTimeout());
113: }
114:
115: // Recompute next wakeup time if needed
116: if (threadWakeUpTime == 0
117: || (entry.getDeadline() < threadWakeUpTime))
118: threadWakeUpTime = entry.getDeadline();
119: }
120:
121: // Clean up all dirty entries from the relaxed cache
122: int size = toRemoveFromRelaxedCache.size();
123: for (int i = 0; i < size; i++) {
124: entry = (ResultCacheEntryRelaxed) toRemoveFromRelaxedCache
125: .get(i);
126: if (logger.isDebugEnabled())
127: logger
128: .debug(Translate
129: .get(
130: "cachethread.remove.entry.from.cache",
131: entry
132: .getRequest()
133: .getUniqueKey()));
134: this .cache.removeFromCache(entry
135: .getRequest());
136: cache.getRelaxedCache().remove(entry);
137: }
138: toRemoveFromRelaxedCache.clear();
139: if (threadWakeUpTime == 0) { // All entries were dirty and not kept in the cache, therefore
140: // there is no next deadline. (and no cache entry to wait for)
141: continue;
142: } else { // Sleep until the next deadline
143: sleep = (threadWakeUpTime - now) / 1000
144: + refreshCacheTime;
145: if (logger.isDebugEnabled()) {
146: logger.debug(Translate.get(
147: "cachethread.sleeping", sleep));
148: }
149: sleep = (sleep) * 1000;
150: wait(sleep);
151: }
152: }
153: } catch (Exception e) {
154: logger.warn(e.getMessage(), e);
155: }
156: }
157: }
158: }
159:
160: /**
161: * Shutdown the current thread.
162: */
163: public synchronized void shutdown() {
164: isKilled = true;
165: notify();
166: }
167:
168: }
|