KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > continuent > sequoia > controller > cache > parsing > ParsingCache


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

22
23 package org.continuent.sequoia.controller.cache.parsing;
24
25 import java.sql.SQLException JavaDoc;
26 import java.util.Hashtable JavaDoc;
27
28 import org.continuent.sequoia.common.i18n.Translate;
29 import org.continuent.sequoia.common.log.Trace;
30 import org.continuent.sequoia.common.xml.DatabasesXmlTags;
31 import org.continuent.sequoia.controller.requestmanager.ParserThread;
32 import org.continuent.sequoia.controller.requestmanager.RequestManager;
33 import org.continuent.sequoia.controller.requests.AbstractRequest;
34 import org.continuent.sequoia.controller.requests.ParsingGranularities;
35 import org.continuent.sequoia.controller.requests.RequestType;
36 import org.continuent.sequoia.controller.semantic.SemanticBehavior;
37 import org.continuent.sequoia.controller.semantic.SemanticManager;
38
39 /**
40  * This class implements a request parsing cache.
41  *
42  * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
43  * @version 1.0
44  */

45 public class ParsingCache
46 {
47   private static Trace logger = Trace
48                                      .getLogger(ParsingCache.class.getName());
49   // SQL -> parsed request
50
private Hashtable JavaDoc cache;
51   // SQL -> CurrentlyParsingEntry
52
private Hashtable JavaDoc currentlyParsing;
53   private RequestManager requestManager;
54   private int granularity;
55   private int maxNbOfEntries;
56   // Default is parse when needed
57
private boolean backgroundParsing;
58   // Default is case insensitive
59
private boolean caseSensitiveParsing;
60   private SemanticManager semanticManager;
61
62   /**
63    * CurrentlyParsingEntry contains a (Request,ParserThread) which is an element
64    * of the currentlyParsing Hashtable.
65    *
66    * @author <a HREF="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
67    * @version 1.0
68    */

69   private class CurrentlyParsingEntry
70   {
71     private ParserThread parserThread;
72     private AbstractRequest request;
73
74     /**
75      * Constructor for CurrentlyParsingEntry.
76      *
77      * @param parserThread creating parser thread
78      * @param request request to parse
79      */

80     public CurrentlyParsingEntry(ParserThread parserThread,
81         AbstractRequest request)
82     {
83       this.parserThread = parserThread;
84       this.request = request;
85     }
86
87     /**
88      * Returns the parserThread.
89      *
90      * @return ParserThread
91      */

92     public ParserThread getParserThread()
93     {
94       return parserThread;
95     }
96
97     /**
98      * Returns the request.
99      *
100      * @return AbstractRequest
101      */

102     public AbstractRequest getRequest()
103     {
104       return request;
105     }
106
107   }
108
109   /**
110    * Constructor for ParsingCache.
111    *
112    * @param semanticManager semantic manager to fetch the semantic from if it
113    * overrides request parsing
114    * @param size maximum cache size in nb of entries
115    * @param backgroundParsing true if the parsing should be done in background
116    * by a ParserThread
117    */

118   public ParsingCache(SemanticManager semanticManager, int size,
119       boolean backgroundParsing)
120   {
121     this.semanticManager = semanticManager;
122     cache = new Hashtable JavaDoc(size == 0 ? 10000 : size);
123     currentlyParsing = new Hashtable JavaDoc();
124     if (size < 0)
125       throw new RuntimeException JavaDoc(Translate.get("cache.parsing.invalid.size",
126           size));
127     if (size == 0)
128       this.maxNbOfEntries = Integer.MAX_VALUE;
129     else
130       this.maxNbOfEntries = size;
131     this.backgroundParsing = backgroundParsing;
132     caseSensitiveParsing = false;
133   }
134
135   /**
136    * Returns the granularity value.
137    *
138    * @return Returns the granularity.
139    */

140   public int getGranularity()
141   {
142     return granularity;
143   }
144
145   /**
146    * Sets the granularity value.
147    *
148    * @param granularity The granularity to set.
149    */

150   public void setGranularity(int granularity)
151   {
152     this.granularity = granularity;
153   }
154
155   /**
156    * Returns the requestManager value.
157    *
158    * @return Returns the requestManager.
159    */

160   public RequestManager getRequestManager()
161   {
162     return requestManager;
163   }
164
165   /**
166    * Sets the requestManager value.
167    *
168    * @param requestManager The requestManager to set.
169    */

170   public void setRequestManager(RequestManager requestManager)
171   {
172     this.requestManager = requestManager;
173   }
174
175   /**
176    * Get the parsing from the parsing cache and parse the query if this is a
177    * cache miss.
178    *
179    * @param request the request we look for
180    * @exception SQLException if an error occurs
181    */

182   public void getParsingFromCacheAndParseIfMissing(AbstractRequest request)
183       throws SQLException JavaDoc
184   {
185     if (request.isParsed())
186       return;
187
188     // Check cache
189
String JavaDoc instanciatedSQL = request.getUniqueKey();
190     AbstractRequest parsedRequest = (AbstractRequest) cache
191         .get(instanciatedSQL);
192
193     try
194     {
195       if (parsedRequest != null)
196       {
197         // Cache hit
198
request.cloneParsing(parsedRequest);
199         return;
200       }
201
202       // At this point, we have a cache miss
203

204       // Check if there is a semantic information for this request
205
request.setSemanticManager(semanticManager);
206       SemanticBehavior semantic = semanticManager.getRequestSemantic(request);
207       if (semantic != null)
208       {
209         request.setSemantic(semantic);
210         return;
211       }
212
213       // No semantic information, parse manually
214
String JavaDoc sqlSkeleton = request.getSqlOrTemplate();
215       String JavaDoc sql;
216       if (sqlSkeleton != null)
217       { // Missed with instanciated query, try with skeleton
218
sql = sqlSkeleton;
219         parsedRequest = (AbstractRequest) cache.get(sql);
220         if (parsedRequest != null)
221         { // Cache hit with skeleton
222
request.cloneParsing(parsedRequest);
223           return;
224         }
225       }
226       else
227         sql = instanciatedSQL;
228
229       // Full cache miss. Note that the underlying cache Hashtable is
230
// synchronized and we usually do not need to synchronize on it.
231
// As we will have to add a cache entry, check if the cache size is ok
232
// else remove the first entry of the hashtable.
233
while (cache.size() > maxNbOfEntries)
234       { // Remove first entry from Hashtable. We need to synchronize here to
235
// be
236
// sure that we are not trying to concurrently remove the first cache
237
// entry.
238
synchronized (cache)
239         {
240           try
241           {
242             cache.remove(cache.keys().nextElement());
243           }
244           catch (Exception JavaDoc ignore)
245           {
246             break;
247           }
248         }
249       }
250
251       // Both skeleton and instanciated missed
252
if (backgroundParsing)
253       {
254         // Find the parsing thread and request (note that Hasthtable is
255
// synchronized)
256
CurrentlyParsingEntry cpe = (CurrentlyParsingEntry) currentlyParsing
257             .get(sql);
258         if (cpe != null)
259         {
260           ParserThread pt = cpe.getParserThread();
261           try
262           {
263             if (pt != null)
264             {
265               // Wait for completion
266
pt.join();
267               synchronized (currentlyParsing)
268               {
269                 currentlyParsing.remove(sql);
270               }
271
272               // Update cache
273
if ((granularity != ParsingGranularities.COLUMN_UNIQUE)
274                   || (sqlSkeleton == null))
275                 // No skeleton or no uniqueness criteria, add the query
276
cache.put(instanciatedSQL, cpe.getRequest());
277               else
278               { // We have a skeleton and COLUMN_UNIQUE parsing
279
if (request.getCacheAbility() != RequestType.UNIQUE_CACHEABLE)
280                   // It is NOT UNIQUE, add the skeleton
281
cache.put(sqlSkeleton, cpe.getRequest());
282                 else
283                   // It is UNIQUE, add the instanciated query
284
cache.put(instanciatedSQL, cpe.getRequest());
285               }
286             }
287           }
288           catch (InterruptedException JavaDoc failed)
289           {
290             throw new SQLException JavaDoc(Translate.get(
291                 "cache.parsing.failed.join.parser.thread", new String JavaDoc[]{
292                     "" + request.getId(), failed.getMessage()}));
293           }
294         }
295       }
296       // Parse it now because we didn't parse in background or
297
// backgroundParsing has failed for any obscure reason.
298
request.parse(requestManager.getDatabaseSchema(), granularity,
299           caseSensitiveParsing);
300
301       // Update cache
302
if ((sqlSkeleton != null)
303           && (granularity == ParsingGranularities.COLUMN_UNIQUE)
304           && (request.getCacheAbility() == RequestType.UNIQUE_CACHEABLE))
305         // If this is a unique request, we must put the instanciated query in
306
// the cache to retrieve the exact pk value.
307
cache.put(instanciatedSQL, request);
308       else
309         cache.put(sql, request);
310     }
311     catch (OutOfMemoryError JavaDoc oome)
312     {
313       synchronized (cache)
314       {
315         cache.clear();
316       }
317       System.gc();
318       logger.warn(Translate.get("cache.memory.error.cache.flushed", this
319           .getClass()));
320     }
321   }
322
323   /**
324    * Returns the backgroundParsing.
325    *
326    * @return boolean
327    */

328   public boolean isBackgroundParsing()
329   {
330     return backgroundParsing;
331   }
332
333   /**
334    * Sets the background parsing. If true the request are parsed in background
335    * by a separate thread that is created for this purpose.
336    *
337    * @param backgroundParsing The backgroundParsing to set
338    */

339   public void setBackgroundParsing(boolean backgroundParsing)
340   {
341     this.backgroundParsing = backgroundParsing;
342   }
343
344   /**
345    * Sets the parsing case sensitivity
346    *
347    * @param isCaseSensitiveParsing true if parsing is case sensitive
348    */

349   public void setCaseSensitiveParsing(boolean isCaseSensitiveParsing)
350   {
351     this.caseSensitiveParsing = isCaseSensitiveParsing;
352   }
353
354   /**
355    * Returns the caseSensitiveParsin.
356    *
357    * @return boolean
358    */

359   public boolean isCaseSensitiveParsing()
360   {
361     return caseSensitiveParsing;
362   }
363
364   /**
365    * Get xml information about this ParsingCache
366    *
367    * @return <code>String</code> in xml formatted text
368    */

369   public String JavaDoc getXml()
370   {
371     return "<" + DatabasesXmlTags.ELT_ParsingCache + " "
372         + DatabasesXmlTags.ATT_backgroundParsing + "=\"" + backgroundParsing
373         + "\" " + DatabasesXmlTags.ATT_maxNbOfEntries + "=\"" + maxNbOfEntries
374         + "\"/>";
375   }
376
377   /**
378    * Retrieves the current request parsing cache configuration. The returned
379    * string contains:
380    * <ul>
381    * <li>granularity
382    * <li>maximum number of entries
383    * <li>background parsing flag
384    * <li>case sensitivity
385    * </ul>
386    *
387    * @return a String containing the configuration of the cache
388    */

389   public String JavaDoc dumpCacheConfig()
390   {
391     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
392     sb.append(Translate.get("cache.dump")); //$NON-NLS-1$
393
sb.append(Translate.get(
394         "cache.granularity", ParsingGranularities.getInformation(granularity))); //$NON-NLS-1$
395
sb.append(Translate.get("cache.max.entries", maxNbOfEntries)); //$NON-NLS-1$
396
sb.append(Translate.get("cache.background.parsing", backgroundParsing)); //$NON-NLS-1$
397
sb.append(Translate.get("cache.case.sensitive", caseSensitiveParsing)); //$NON-NLS-1$
398
return sb.toString();
399   }
400
401   /**
402    * Retrieves the number of entries currently contained in the cache
403    *
404    * @return number of cache entries
405    */

406   public int getNumberOfCacheEntries()
407   {
408     return cache.size();
409   }
410
411   /**
412    * Prints entries of the cache, from beginIndex to (beginIndex + max) or to
413    * the last entry if beginIndex+max is out of bounds
414    *
415    * @param beginIndex entry from which to start dump
416    * @param max maximum number of entries to dump
417    * @return a string containing the cache entries (request unique key + short
418    * description string) from beginIndex to the last entry or to
419    * beginIndex+max.
420    */

421   public String JavaDoc dumpCacheEntries(int beginIndex, int max)
422   {
423     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
424     int i = beginIndex;
425     Object JavaDoc[] keys = cache.keySet().toArray();
426     while (i < keys.length && i < (beginIndex + max))
427     {
428       sb.append(Translate.get("cache.entry", new String JavaDoc[]{ //$NON-NLS-1$
429
keys[i].toString(),
430               ((AbstractRequest) cache.get(keys[i])).toShortDebugString()}));
431       i++;
432     }
433     return sb.toString();
434   }
435
436   /**
437    * Dumps requests that are currently beeing parsed
438    *
439    * @return a String containing the entries (request unique key + short
440    * description string) currently beeing parsed
441    */

442   public String JavaDoc dumpCurrentlyParsedEntries()
443   {
444     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
445     if (currentlyParsing != null && currentlyParsing.size() > 0)
446     {
447       sb.append(Translate.get("cache.currently.parsing.entries")); //$NON-NLS-1$
448
for (int i = 0; i < currentlyParsing.size(); i++)
449       {
450         sb.append(Translate.get("cache.currently.parsing.entry", new String JavaDoc[]{ //$NON-NLS-1$
451
currentlyParsing.keySet().toArray()[i].toString(),
452                 ((CurrentlyParsingEntry) currentlyParsing.get(currentlyParsing
453                     .keySet().toArray()[i])).request.toShortDebugString()}));
454       }
455     }
456     return sb.toString();
457   }
458 }
459
Popular Tags