00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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.log.Trace;
00032 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00033 import org.objectweb.cjdbc.common.sql.ParsingGranularities;
00034 import org.objectweb.cjdbc.common.sql.RequestType;
00035 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00036 import org.objectweb.cjdbc.controller.requestmanager.ParserThread;
00037 import org.objectweb.cjdbc.controller.requestmanager.RequestManager;
00038
00039
00040
00041
00042
00043
00044
00045 public class ParsingCache
00046 {
00047 private static Trace logger = Trace.getLogger(ParsingCache.class.getName());
00048 private Hashtable cache;
00049 private Hashtable currentlyParsing;
00050 private RequestManager requestManager;
00051 private int granularity;
00052 private int maxNbOfEntries;
00053 private boolean backgroundParsing;
00054 private boolean caseSensitiveParsing;
00055
00056
00057
00058
00059
00060
00061
00062
00063 private class CurrentlyParsingEntry
00064 {
00065 private ParserThread parserThread;
00066 private AbstractRequest request;
00067
00068
00069
00070
00071
00072
00073
00074 public CurrentlyParsingEntry(ParserThread parserThread,
00075 AbstractRequest request)
00076 {
00077 this.parserThread = parserThread;
00078 this.request = request;
00079 }
00080
00081
00082
00083
00084
00085
00086 public ParserThread getParserThread()
00087 {
00088 return parserThread;
00089 }
00090
00091
00092
00093
00094
00095
00096 public AbstractRequest getRequest()
00097 {
00098 return request;
00099 }
00100
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110 public ParsingCache(int size, boolean backgroundParsing)
00111 {
00112 cache = new Hashtable(size == 0 ? 10000 : size);
00113 currentlyParsing = new Hashtable();
00114 if (size < 0)
00115 throw new RuntimeException(Translate.get("cache.parsing.invalid.size",
00116 size));
00117 if (size == 0)
00118 this.maxNbOfEntries = Integer.MAX_VALUE;
00119 else
00120 this.maxNbOfEntries = size;
00121 this.backgroundParsing = backgroundParsing;
00122 caseSensitiveParsing = false;
00123 }
00124
00125
00126
00127
00128
00129
00130 public int getGranularity()
00131 {
00132 return granularity;
00133 }
00134
00135
00136
00137
00138
00139
00140 public void setGranularity(int granularity)
00141 {
00142 this.granularity = granularity;
00143 }
00144
00145
00146
00147
00148
00149
00150 public RequestManager getRequestManager()
00151 {
00152 return requestManager;
00153 }
00154
00155
00156
00157
00158
00159
00160 public void setRequestManager(RequestManager requestManager)
00161 {
00162 this.requestManager = requestManager;
00163 }
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 public void getParsingFromCache(AbstractRequest request)
00174 {
00175 if (request.isParsed())
00176 return;
00177
00178 String sql = request.getSqlSkeleton();
00179 if (sql == null)
00180 sql = request.getSQL();
00181 AbstractRequest parsedRequest = (AbstractRequest) cache.get(sql);
00182
00183 if (parsedRequest != null)
00184 {
00185 request.cloneParsing(parsedRequest);
00186 return;
00187 }
00188 else if (backgroundParsing)
00189 {
00190 synchronized (currentlyParsing)
00191 {
00192 if (!currentlyParsing.contains(sql))
00193 {
00194 ParserThread pt = new ParserThread(request, requestManager
00195 .getDatabaseSchema(), granularity, caseSensitiveParsing);
00196 currentlyParsing.put(sql, new CurrentlyParsingEntry(pt, request));
00197 }
00198 }
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208 public void getParsingFromCacheAndParseIfMissing(AbstractRequest request)
00209 throws SQLException
00210 {
00211 if (request.isParsed())
00212 return;
00213
00214
00215 String instanciatedSQL = request.getSQL();
00216 AbstractRequest parsedRequest = (AbstractRequest) cache
00217 .get(instanciatedSQL);
00218
00219
00220 try
00221 {
00222
00223 if (parsedRequest == null)
00224 {
00225 String sqlSkeleton = request.getSqlSkeleton();
00226 String sql;
00227 if (sqlSkeleton != null)
00228 {
00229 sql = sqlSkeleton;
00230 parsedRequest = (AbstractRequest) cache.get(sql);
00231 if (parsedRequest != null)
00232 {
00233 request.cloneParsing(parsedRequest);
00234 return;
00235 }
00236 }
00237 else
00238 sql = instanciatedSQL;
00239
00240
00241
00242
00243
00244 while (cache.size() > maxNbOfEntries)
00245 {
00246
00247
00248 synchronized (cache)
00249 {
00250 try
00251 {
00252 cache.remove(cache.keys().nextElement());
00253 }
00254 catch (Exception ignore)
00255 {
00256 break;
00257 }
00258 }
00259 }
00260
00261
00262
00263 if (backgroundParsing)
00264 {
00265
00266
00267 CurrentlyParsingEntry cpe = (CurrentlyParsingEntry) currentlyParsing
00268 .get(sql);
00269 if (cpe != null)
00270 {
00271 ParserThread pt = cpe.getParserThread();
00272 try
00273 {
00274 if (pt != null)
00275 {
00276
00277 pt.join();
00278 synchronized (currentlyParsing)
00279 {
00280 currentlyParsing.remove(sql);
00281 }
00282
00283
00284 if ((granularity != ParsingGranularities.COLUMN_UNIQUE)
00285 || (sqlSkeleton == null))
00286
00287 cache.put(instanciatedSQL, cpe.getRequest());
00288 else
00289 {
00290 if (request.getCacheAbility() != RequestType.UNIQUE_CACHEABLE)
00291
00292 cache.put(sqlSkeleton, cpe.getRequest());
00293 else
00294
00295 cache.put(instanciatedSQL, cpe.getRequest());
00296 }
00297 }
00298 }
00299 catch (InterruptedException failed)
00300 {
00301 throw new SQLException(Translate.get(
00302 "cache.parsing.failed.join.parser.thread", new String[]{
00303 "" + request.getId(), failed.getMessage()}));
00304 }
00305 }
00306 }
00307
00308
00309 request.parse(requestManager.getDatabaseSchema(), granularity,
00310 caseSensitiveParsing);
00311
00312
00313 if ((sqlSkeleton != null)
00314 && (granularity == ParsingGranularities.COLUMN_UNIQUE)
00315 && (request.getCacheAbility() == RequestType.UNIQUE_CACHEABLE))
00316
00317
00318 cache.put(instanciatedSQL, request);
00319 else
00320 cache.put(sql, request);
00321 }
00322 else
00323
00324 request.cloneParsing(parsedRequest);
00325
00326 }
00327 catch (OutOfMemoryError oome)
00328 {
00329 synchronized (cache)
00330 {
00331 cache.clear();
00332 }
00333 System.gc();
00334 logger.warn(Translate.get("cache.memory.error.cache.flushed", this
00335 .getClass()));
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344 public boolean isBackgroundParsing()
00345 {
00346 return backgroundParsing;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355 public void setBackgroundParsing(boolean backgroundParsing)
00356 {
00357 this.backgroundParsing = backgroundParsing;
00358 }
00359
00360
00361
00362
00363
00364
00365 public void setCaseSensitiveParsing(boolean isCaseSensitiveParsing)
00366 {
00367 this.caseSensitiveParsing = isCaseSensitiveParsing;
00368 }
00369
00370
00371
00372
00373
00374
00375 public boolean isCaseSensitiveParsing()
00376 {
00377 return caseSensitiveParsing;
00378 }
00379
00380
00381
00382
00383
00384
00385 public String getXml()
00386 {
00387 return "<" + DatabasesXmlTags.ELT_ParsingCache + " "
00388 + DatabasesXmlTags.ATT_backgroundParsing + "=\"" + backgroundParsing
00389 + "\" " + DatabasesXmlTags.ATT_maxNbOfEntries + "=\"" + maxNbOfEntries
00390 + "\"/>";
00391 }
00392
00393 }