KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > virtualdatabase > RequestResultFailoverCache


1 /**
2  * Sequoia: Database clustering technology.
3  * Copyright (C) 2006 Continuent, Inc.
4  * Contact: sequoia@continuent.org
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Initial developer(s): Damian Arregui.
19  * Contributor(s): ______________________.
20  */

21
22 package org.continuent.sequoia.controller.virtualdatabase;
23
24 import java.io.Serializable JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Map.Entry;
29
30 import org.continuent.sequoia.common.log.Trace;
31 import org.continuent.sequoia.controller.requests.AbstractRequest;
32
33 /**
34  * This class defines a RequestResultFailoverCache.<br>
35  * <br>
36  * It is used to implement the transparent failover feature. It temporarily
37  * stores requests results so that they can be retrieved by the driver. Results
38  * are stored/retrieved with a request ID.<br>
39  * <br>
40  * An associated clean-up thread is started at instantiation time. It takes care
41  * of removing cache entries which are too old.
42  *
43  * @author <a HREF="mailto:damian.arregui@continuent.com">Damian Arregui</a>
44  * @version 1.0
45  */

46 public class RequestResultFailoverCache implements Runnable JavaDoc
47 {
48
49   /**
50    * Time elapsed between two clean-up runs (in ms).
51    */

52   private static final long CACHE_CLEANUP_TIMEOUT = 10000;
53
54   /**
55    * Period of time after which a cache entry is considered to be too old (in
56    * ms).
57    */

58   private long entryTimeout;
59
60   /** Distribued virtual database logger */
61   private Trace logger;
62
63   // Request result cache
64
// request ID -> result
65
private Map JavaDoc requestIdResult = new HashMap JavaDoc();
66
67   // Transaction ID to request ID mapping
68
// transaction ID -> request ID
69
private Map JavaDoc transactionIdRequestId = new HashMap JavaDoc();
70
71   // Connection ID to request ID mapping
72
// connection ID -> request ID
73
private Map JavaDoc connectionIdRequestId = new HashMap JavaDoc();
74
75   private boolean isKilled = false;
76
77   // This class is used to store in cache a expirationDate together with each
78
// result
79
private class CachedResult
80   {
81     private Serializable JavaDoc result;
82     private long expirationDate;
83
84     /**
85      * Creates a new <code>CachedResult</code> object containing a result and
86      * automatically associating a expirationDate to it
87      *
88      * @param result result to store in this entry
89      */

90     public CachedResult(Serializable JavaDoc result, long entryTimeout)
91     {
92       this.result = result;
93       expirationDate = System.currentTimeMillis() + entryTimeout;
94     }
95
96     /**
97      * Return the result
98      *
99      * @return result stored in the entry
100      */

101     public Serializable JavaDoc getResult()
102     {
103       return result;
104     }
105
106     /**
107      * Timestamp (in ms) when the result expires
108      *
109      * @return creation expirationDate
110      */

111     public long getExpirationDate()
112     {
113       return expirationDate;
114     }
115   }
116
117   /**
118    * Creates a new <code>RequestResultFailoverCache</code> object and starts
119    * its associated clean-up thread.
120    *
121    * @param logger logger to use to display messages
122    * @param entryTimeout time in ms after which an entry is removed from the
123    * cache
124    */

125   public RequestResultFailoverCache(Trace logger, long entryTimeout)
126   {
127     this.logger = logger;
128     this.entryTimeout = entryTimeout;
129     (new Thread JavaDoc(this, "RequestResultFailoverCacheCleanupThread")).start();
130   }
131
132   /**
133    * Stores in cache a result associated with a given request.
134    *
135    * @param request request executed
136    * @param result result of the execution of the request
137    */

138   public synchronized void store(AbstractRequest request, Serializable JavaDoc result)
139   {
140     Long JavaDoc requestId = new Long JavaDoc(request.getId());
141
142     // Add to the cache first (else other lists would temporarily point to a
143
// non-existing entry).
144
synchronized (requestIdResult)
145     {
146       if (requestIdResult.isEmpty())
147       {
148         // Wake up thread to purge results as needed
149
requestIdResult.notify();
150       }
151       requestIdResult.put(requestId, new CachedResult(result, entryTimeout));
152     }
153
154     if (!request.isAutoCommit())
155     { // Replace last result for the transaction
156
Long JavaDoc transactionId = new Long JavaDoc(request.getTransactionId());
157       if (transactionIdRequestId.containsKey(transactionId))
158       {
159         requestIdResult.remove(transactionIdRequestId.get(transactionId));
160       }
161       transactionIdRequestId.put(transactionId, requestId);
162     }
163
164     if (request.isPersistentConnection())
165     { // Replace the last result for the persistent connection
166
Long JavaDoc connectionId = new Long JavaDoc(request.getPersistentConnectionId());
167       if (connectionIdRequestId.containsKey(connectionId))
168       {
169         requestIdResult.remove(connectionIdRequestId.get(connectionId));
170       }
171       connectionIdRequestId.put(connectionId, requestId);
172     }
173
174     if (logger.isDebugEnabled())
175       logger.debug("Stored result for request ID: " + request.getId() + " -> "
176           + result);
177   }
178
179   /**
180    * Retrieves from cache the result associated with a request ID.
181    *
182    * @param requestId id of the request to retrieve
183    * @return result or null if result not found
184    */

185   public synchronized Serializable JavaDoc retrieve(long requestId)
186   {
187     Serializable JavaDoc res = null;
188     Long JavaDoc requestIdLong = new Long JavaDoc(requestId);
189     if (requestIdResult.containsKey(requestIdLong))
190     {
191       res = ((CachedResult) requestIdResult.get(requestIdLong)).getResult();
192       if (logger.isDebugEnabled())
193         logger.debug("Retrieved result for request ID: " + requestId + " -> "
194             + res);
195     }
196     else
197     { // Not found
198
if (logger.isDebugEnabled())
199         logger.debug("No result found in failover cache for request "
200             + requestId);
201     }
202     return res;
203   }
204
205   /**
206    * Takes care of removing cache entries which are too old.
207    *
208    * @see java.lang.Runnable#run()
209    */

210   public void run()
211   {
212     // Thread runs forever
213
while (!isKilled)
214     {
215       try
216       {
217         synchronized (requestIdResult)
218         {
219           // Wait if there is no result else just sleep for the configured time
220
// interval
221
if (requestIdResult.isEmpty())
222             requestIdResult.wait();
223           else
224             requestIdResult.wait(CACHE_CLEANUP_TIMEOUT);
225         }
226       }
227       catch (InterruptedException JavaDoc e)
228       {
229         // Ignore
230
}
231       removeOldEntries();
232     }
233   }
234
235   /**
236    * Shutdown this thread so that it terminates asap. Note that if the thread
237    * was waiting it will still proceed to the cleanup operations before
238    * terminating.
239    */

240   public void shutdown()
241   {
242     isKilled = true;
243     synchronized (requestIdResult)
244     {
245       requestIdResult.notifyAll();
246     }
247   }
248
249   private void removeOldEntries()
250   {
251     if (logger.isDebugEnabled())
252       logger.debug("Cleaning-up request result failover cache...");
253     synchronized (this)
254     {
255       long currentTimeMillis = System.currentTimeMillis();
256
257       // Remove expired entries from the cache (iterate over request IDs)
258
for (Iterator JavaDoc iter = requestIdResult.entrySet().iterator(); iter
259           .hasNext();)
260       {
261         CachedResult cachedResult = (CachedResult) ((Entry) iter.next())
262             .getValue();
263         if ((currentTimeMillis > cachedResult.getExpirationDate()))
264         {
265           iter.remove();
266           if (logger.isDebugEnabled())
267             logger.debug("Removed result from failover cache: "
268                 + cachedResult.getResult());
269         }
270       }
271
272       // Iterate over transaction IDs
273
for (Iterator JavaDoc iter = transactionIdRequestId.entrySet().iterator(); iter
274           .hasNext();)
275       {
276         Entry entry = (Entry) iter.next();
277         if (requestIdResult.get(entry.getValue()) == null)
278         { // No more in the cache, the transaction has completed
279
iter.remove();
280           if (logger.isDebugEnabled())
281             logger.debug("Removed transaction " + entry.getKey()
282                 + " from failover cache");
283         }
284       }
285
286       // Iterate over connection IDs
287
for (Iterator JavaDoc iter = connectionIdRequestId.entrySet().iterator(); iter
288           .hasNext();)
289       {
290         Entry entry = (Entry) iter.next();
291         if (requestIdResult.get(entry.getValue()) == null)
292         { // No more in the cache, the connection is closed
293
iter.remove();
294           if (logger.isDebugEnabled())
295             logger.debug("Removed persistent connection " + entry.getKey()
296                 + " from failover cache");
297         }
298       }
299
300     }
301   }
302 }
303
Popular Tags