src/org/objectweb/cjdbc/controller/cache/parsing/ParsingCache.java

説明を見る。
00001 00025 package org.objectweb.cjdbc.controller.cache.parsing; 00026 00027 import java.sql.SQLException; 00028 import java.util.Hashtable; 00029 00030 import org.objectweb.cjdbc.common.i18n.Translate; 00031 import org.objectweb.cjdbc.common.sql.AbstractRequest; 00032 import org.objectweb.cjdbc.common.sql.ParsingGranularities; 00033 import org.objectweb.cjdbc.common.sql.RequestType; 00034 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags; 00035 import org.objectweb.cjdbc.controller.requestmanager.ParserThread; 00036 import org.objectweb.cjdbc.controller.requestmanager.RequestManager; 00037 00044 public class ParsingCache 00045 { 00046 private Hashtable cache; // SQL -> parsed request 00047 private Hashtable currentlyParsing; // SQL -> CurrentlyParsingEntry 00048 private RequestManager requestManager; 00049 private int granularity; 00050 private int maxNbOfEntries; 00051 private boolean backgroundParsing; // Default is parse when needed 00052 private boolean caseSensitiveParsing; // Default is case insensitive 00053 00061 private class CurrentlyParsingEntry 00062 { 00063 private ParserThread parserThread; 00064 private AbstractRequest request; 00065 00072 public CurrentlyParsingEntry(ParserThread parserThread, 00073 AbstractRequest request) 00074 { 00075 this.parserThread = parserThread; 00076 this.request = request; 00077 } 00078 00084 public ParserThread getParserThread() 00085 { 00086 return parserThread; 00087 } 00088 00094 public AbstractRequest getRequest() 00095 { 00096 return request; 00097 } 00098 00099 } 00100 00108 public ParsingCache(int size, boolean backgroundParsing) 00109 { 00110 cache = new Hashtable(size == 0 ? 10000 : size); 00111 currentlyParsing = new Hashtable(); 00112 if (size < 0) 00113 throw new RuntimeException(Translate.get("cache.parsing.invalid.size", 00114 size)); 00115 if (size == 0) 00116 this.maxNbOfEntries = Integer.MAX_VALUE; 00117 else 00118 this.maxNbOfEntries = size; 00119 this.backgroundParsing = backgroundParsing; 00120 caseSensitiveParsing = false; 00121 } 00122 00128 public int getGranularity() 00129 { 00130 return granularity; 00131 } 00132 00138 public void setGranularity(int granularity) 00139 { 00140 this.granularity = granularity; 00141 } 00142 00148 public RequestManager getRequestManager() 00149 { 00150 return requestManager; 00151 } 00152 00158 public void setRequestManager(RequestManager requestManager) 00159 { 00160 this.requestManager = requestManager; 00161 } 00162 00171 public void getParsingFromCache(AbstractRequest request) 00172 { 00173 if (request.isParsed()) 00174 return; 00175 00176 String sql = request.getSqlSkeleton(); 00177 if (sql == null) 00178 sql = request.getSQL(); 00179 AbstractRequest parsedRequest = (AbstractRequest) cache.get(sql); 00180 00181 if (parsedRequest != null) 00182 { // Cache hit, clone the parsing 00183 request.cloneParsing(parsedRequest); 00184 return; 00185 } 00186 else if (backgroundParsing) 00187 { // Cache miss, start parsing the request in background 00188 synchronized (currentlyParsing) 00189 { 00190 if (!currentlyParsing.contains(sql)) 00191 { // Nobody else is trying to parse the same SQL query 00192 ParserThread pt = new ParserThread(request, requestManager 00193 .getDatabaseSchema(), granularity, caseSensitiveParsing); 00194 currentlyParsing.put(sql, new CurrentlyParsingEntry(pt, request)); 00195 } 00196 } 00197 } 00198 } 00199 00206 public void getParsingFromCacheAndParseIfMissing(AbstractRequest request) 00207 throws SQLException 00208 { 00209 if (request.isParsed()) 00210 return; 00211 00212 // Check cache 00213 String instanciatedSQL = request.getSQL(); 00214 AbstractRequest parsedRequest = (AbstractRequest) cache 00215 .get(instanciatedSQL); 00216 00217 if (parsedRequest == null) 00218 { // Cache miss 00219 String sqlSkeleton = request.getSqlSkeleton(); 00220 String sql; 00221 if (sqlSkeleton != null) 00222 { // Missed with instanciated query, try with skeleton 00223 sql = sqlSkeleton; 00224 parsedRequest = (AbstractRequest) cache.get(sql); 00225 if (parsedRequest != null) 00226 { // Cache hit with skeleton 00227 request.cloneParsing(parsedRequest); 00228 return; 00229 } 00230 } 00231 else 00232 sql = instanciatedSQL; 00233 00234 // Full cache miss. Note that the underlying cache Hashtable is 00235 // synchronized and we usually do not need to synchronize on it. 00236 // As we will have to add a cache entry, check if the cache size is ok 00237 // else remove the first entry of the hashtable. 00238 while (cache.size() > maxNbOfEntries) 00239 { // Remove first entry from Hashtable. We need to synchronize here to be 00240 // sure that we are not trying to concurrently remove the first cache 00241 // entry. 00242 synchronized (cache) 00243 { 00244 try 00245 { 00246 cache.remove(cache.keys().nextElement()); 00247 } 00248 catch (Exception ignore) 00249 { 00250 break; 00251 } 00252 } 00253 } 00254 00255 // Both skeleton and instanciated missed 00256 if (backgroundParsing) 00257 { 00258 // Find the parsing thread and request (note that Hasthtable is 00259 // synchronized) 00260 CurrentlyParsingEntry cpe = (CurrentlyParsingEntry) currentlyParsing 00261 .get(sql); 00262 if (cpe != null) 00263 { 00264 ParserThread pt = cpe.getParserThread(); 00265 try 00266 { 00267 if (pt != null) 00268 { 00269 // Wait for completion 00270 pt.join(); 00271 synchronized (currentlyParsing) 00272 { 00273 currentlyParsing.remove(sql); 00274 } 00275 00276 // Update cache 00277 if ((granularity != ParsingGranularities.COLUMN_UNIQUE) 00278 || (sqlSkeleton == null)) 00279 // No skeleton or no uniqueness criteria, add the query 00280 cache.put(instanciatedSQL, cpe.getRequest()); 00281 else 00282 { // We have a skeleton and COLUMN_UNIQUE parsing 00283 if (request.getCacheAbility() != RequestType.UNIQUE_CACHEABLE) 00284 // It is NOT UNIQUE, add the skeleton 00285 cache.put(sqlSkeleton, cpe.getRequest()); 00286 else 00287 // It is UNIQUE, add the instanciated query 00288 cache.put(instanciatedSQL, cpe.getRequest()); 00289 } 00290 } 00291 } 00292 catch (InterruptedException failed) 00293 { 00294 throw new SQLException(Translate.get( 00295 "cache.parsing.failed.join.parser.thread", new String[]{ 00296 "" + request.getId(), failed.getMessage()})); 00297 } 00298 } 00299 } 00300 // Parse it now because we didn't parse in background or 00301 // backgroundParsing has failed for any obscure reason. 00302 request.parse(requestManager.getDatabaseSchema(), granularity, 00303 caseSensitiveParsing); 00304 00305 // Update cache 00306 if ((sqlSkeleton != null) 00307 && (granularity == ParsingGranularities.COLUMN_UNIQUE) 00308 && (request.getCacheAbility() == RequestType.UNIQUE_CACHEABLE)) 00309 // If this is a unique request, we must put the instanciated query in 00310 // the cache to retrieve the exact pk value. 00311 cache.put(instanciatedSQL, request); 00312 else 00313 cache.put(sql, request); 00314 } 00315 else 00316 // Cache hit 00317 request.cloneParsing(parsedRequest); 00318 } 00319 00325 public boolean isBackgroundParsing() 00326 { 00327 return backgroundParsing; 00328 } 00329 00336 public void setBackgroundParsing(boolean backgroundParsing) 00337 { 00338 this.backgroundParsing = backgroundParsing; 00339 } 00340 00346 public void setCaseSensitiveParsing(boolean isCaseSensitiveParsing) 00347 { 00348 this.caseSensitiveParsing = isCaseSensitiveParsing; 00349 } 00350 00356 public boolean isCaseSensitiveParsing() 00357 { 00358 return caseSensitiveParsing; 00359 } 00360 00366 public String getXml() 00367 { 00368 return "<" + DatabasesXmlTags.ELT_ParsingCache + " " 00369 + DatabasesXmlTags.ATT_backgroundParsing + "=\"" + backgroundParsing 00370 + "\" " + DatabasesXmlTags.ATT_maxNbOfEntries + "=\"" + maxNbOfEntries 00371 + "\"/>"; 00372 } 00373 00374 }

CJDBCversion1.0.4に対してTue Oct 12 15:16:00 2004に生成されました。 doxygen 1.3.8