Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | Related Pages

MetadataCache.java

00001 /**
00002  * C-JDBC: Clustered JDBC.
00003  * Copyright (C) 2002-2004 French National Institute For Research In Computer
00004  * Science And Control (INRIA).
00005  * Contact: c-jdbc@objectweb.org
00006  * 
00007  * This library is free software; you can redistribute it and/or modify it
00008  * under the terms of the GNU Lesser General Public License as published by the
00009  * Free Software Foundation; either version 2.1 of the License, or any later
00010  * version.
00011  * 
00012  * This library is distributed in the hope that it will be useful, but WITHOUT
00013  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
00015  * for more details.
00016  * 
00017  * You should have received a copy of the GNU Lesser General Public License
00018  * along with this library; if not, write to the Free Software Foundation,
00019  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00020  *
00021  * Initial developer(s): Emmanuel Cecchet.
00022  * Contributor(s): ______________________________________.
00023  */
00024 
00025 package org.objectweb.cjdbc.controller.cache.metadata;
00026 
00027 import java.util.Hashtable;
00028 
00029 import org.objectweb.cjdbc.common.i18n.Translate;
00030 import org.objectweb.cjdbc.common.log.Trace;
00031 import org.objectweb.cjdbc.common.sql.AbstractRequest;
00032 import org.objectweb.cjdbc.common.xml.DatabasesXmlTags;
00033 import org.objectweb.cjdbc.driver.Field;
00034 
00035 /**
00036  * This class implements a ResultSet metadata cache.
00037  * <p>
00038  * ResultSet Fields are kept here to prevent recomputing them and allocating
00039  * them each time a query is executed.
00040  * 
00041  * @author <a href="mailto:Emmanuel.Cecchet@inria.fr">Emmanuel Cecchet </a>
00042  * @version 1.0
00043  */
00044 public class MetadataCache
00045 {
00046   private static Trace logger = Trace.getLogger(MetadataCache.class.getName());
00047   private Hashtable metadataCache;  // SQL -> Field[]
00048   private Hashtable fieldCache;     // Schema.Table.Column name -> Field
00049   private int       maxNbOfMetadata;
00050   private int       maxNbOfField;
00051 
00052   /**
00053    * Constructor for MetadataCache.
00054    * 
00055    * @param maxNbOfMetadata maximum nb of entries in metadata cache
00056    * @param maxNbOfField maximum nb of entries in field cache
00057    */
00058   public MetadataCache(int maxNbOfMetadata, int maxNbOfField)
00059   {
00060     metadataCache = new Hashtable(maxNbOfMetadata == 0
00061         ? 10000
00062         : maxNbOfMetadata);
00063     fieldCache = new Hashtable(maxNbOfField == 0 ? 100 : maxNbOfField);
00064     if (maxNbOfMetadata < 0)
00065       throw new RuntimeException(Translate.get("cache.metadata.invalid.size",
00066           maxNbOfMetadata));
00067     if (maxNbOfMetadata == 0)
00068       this.maxNbOfMetadata = Integer.MAX_VALUE;
00069     else
00070       this.maxNbOfMetadata = maxNbOfMetadata;
00071     if (maxNbOfField < 0)
00072       throw new RuntimeException(Translate.get("cache.metadata.invalid.size",
00073           maxNbOfField));
00074     if (maxNbOfField == 0)
00075       this.maxNbOfField = Integer.MAX_VALUE;
00076     else
00077       this.maxNbOfField = maxNbOfField;
00078   }
00079 
00080   /**
00081    * Get metadata associated to a request.
00082    * <p>
00083    * Returns null if the cache contains no metadata for the given request.
00084    * 
00085    * @param request the request we look for
00086    * @return the metadata or null if not in cache
00087    */
00088   public Field[] getMetadata(AbstractRequest request)
00089   {
00090     String sqlSkeleton = request.getSqlSkeleton();
00091     if (sqlSkeleton != null)
00092       return (Field[]) metadataCache.get(sqlSkeleton);
00093     else
00094       return (Field[]) metadataCache.get(request.getSQL());
00095   }
00096 
00097   /**
00098    * Add a metadata entry to the cache and associate it to the given request.
00099    * 
00100    * @param request request to which the metadata belong
00101    * @param metadata metadata to cache
00102    */
00103   public void addMetadata(AbstractRequest request, Field[] metadata)
00104   {
00105     // Note that the underlying cache Hashtable is synchronized and we usually
00106     // do not need to synchronize on it.
00107     // As we will have to add a cache entry, check if the cache size is ok
00108     // else remove the first entry of the hashtable.
00109     while (metadataCache.size() > maxNbOfMetadata)
00110     { // Remove first entry from Hashtable. We need to synchronize here to be
00111       // sure that we are not trying to concurrently remove the first cache
00112       // entry.
00113       synchronized (metadataCache)
00114       {
00115         try
00116         {
00117           metadataCache.remove(metadataCache.keys().nextElement());
00118         }
00119         catch (Exception ignore)
00120         {
00121           break;
00122         }
00123       }
00124     }
00125 
00126     // Add to cache
00127     try
00128     {
00129       String sqlSkeleton = request.getSqlSkeleton();
00130       if (sqlSkeleton != null)
00131         metadataCache.put(sqlSkeleton, metadata);
00132       else
00133         metadataCache.put(request.getSQL(), metadata);
00134     }
00135     catch (OutOfMemoryError oome)
00136     {
00137       synchronized (metadataCache)
00138       {
00139         metadataCache.clear();
00140       }
00141       System.gc();
00142       logger.warn(Translate.get("cache.memory.error.cache.flushed", this
00143           .getClass()));
00144     }
00145   }
00146 
00147   /**
00148    * Get the field corresponding to a column name.
00149    * <p>
00150    * Returns null if the cache contains no field for the given name.
00151    * 
00152    * @param fullyQualifiedFieldName the field name (table.column) to look for
00153    * @return the corresponding Field or null if not in cache
00154    */
00155   public Field getField(String fullyQualifiedFieldName)
00156   {
00157     return (Field) fieldCache.get(fullyQualifiedFieldName);
00158   }
00159 
00160   /**
00161    * Add a Field entry to the cache and associate it to the given name.
00162    * 
00163    * @param fullyQualifiedFieldName table.column name that uniquely identifies
00164    *          the field
00165    * @param field field to cache
00166    */
00167   public void addField(String fullyQualifiedFieldName, Field field)
00168   {
00169     // Note that the underlying cache Hashtable is synchronized and we usually
00170     // do not need to synchronize on it.
00171     // As we will have to add a cache entry, check if the cache size is ok
00172     // else remove the first entry of the hashtable.
00173     while (fieldCache.size() > maxNbOfField)
00174     { // Remove first entry from Hashtable. We need to synchronize here to be
00175       // sure that we are not trying to concurrently remove the first cache
00176       // entry.
00177       synchronized (fieldCache)
00178       {
00179         try
00180         {
00181           fieldCache.remove(fieldCache.keys().nextElement());
00182         }
00183         catch (Exception ignore)
00184         {
00185           break;
00186         }
00187       }
00188     }
00189     // Add to cache
00190     try
00191     {
00192       fieldCache.put(fullyQualifiedFieldName, field);
00193     }
00194     catch (OutOfMemoryError oome)
00195     {
00196       synchronized (fieldCache)
00197       {
00198         fieldCache.clear();
00199       }
00200       System.gc();
00201       logger.warn(Translate.get("cache.memory.error.cache.flushed", this
00202           .getClass()));
00203     }
00204   }
00205 
00206   /**
00207    * Get xml information about this ParsingCache
00208    * 
00209    * @return <code>String</code> in xml formatted text
00210    */
00211   public String getXml()
00212   {
00213     return "<" + DatabasesXmlTags.ELT_MetadataCache + " "
00214         + DatabasesXmlTags.ATT_maxNbOfMetadata + "=\"" + maxNbOfMetadata
00215         + "\" " + DatabasesXmlTags.ATT_maxNbOfField + "=\""
00216         + (maxNbOfField == Integer.MAX_VALUE ? 0 : maxNbOfField) + "\"/>";
00217   }
00218 
00219 }

Generated on Mon Apr 11 22:01:32 2005 for C-JDBC by  doxygen 1.3.9.1