View Javadoc

1   package org.apache.jcs.auxiliary.disk.jdbc;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.Enumeration;
23  import java.util.Hashtable;
24  import java.util.Map;
25  
26  import org.apache.commons.logging.Log;
27  import org.apache.commons.logging.LogFactory;
28  import org.apache.jcs.auxiliary.AuxiliaryCache;
29  import org.apache.jcs.auxiliary.AuxiliaryCacheManager;
30  
31  import EDU.oswego.cs.dl.util.concurrent.ClockDaemon;
32  import EDU.oswego.cs.dl.util.concurrent.ThreadFactory;
33  
34  /***
35   * This class serves as an abstract template for JDBCDiskCache Manager. The MySQL JDBC Disk Cache
36   * needs many of the same features as the generic maanger.
37   * <p>
38   * @author Aaron Smuts
39   */
40  public abstract class JDBCDiskCacheManagerAbstractTemplate
41      implements AuxiliaryCacheManager
42  {
43      /*** The logger. */
44      private static final Log log = LogFactory.getLog( JDBCDiskCacheManagerAbstractTemplate.class );
45  
46      /***
47       * Incremented on getIntance, decremented on release.
48       */
49      protected static int clients;
50  
51      /***
52       * A map of JDBCDiskCache objects to region names.
53       */
54      protected static Hashtable caches = new Hashtable();
55  
56      /***
57       * A map of TableState objects to table names. Each cache has a table state object, which is
58       * used to determin if any long processes such as deletes or optimizations are running.
59       */
60      protected static Hashtable tableStates = new Hashtable();
61  
62      /***
63       * The background disk shrinker, one for all regions.
64       */
65      private ClockDaemon shrinkerDaemon;
66  
67      /***
68       * A map of table name to shrinker threads. This allows each table to have a different setting.
69       * It assumes that there is only one jdbc disk cache auxiliary defined per table.
70       */
71      private Map shrinkerThreadMap = new Hashtable();
72  
73      /***
74       * Children must implement this method.
75       * <p>
76       * @param cattr
77       * @param tableState An object used by multiple processes to indicate state.
78       * @return AuxiliaryCache -- a JDBCDiskCache
79       */
80      protected abstract AuxiliaryCache createJDBCDiskCache( JDBCDiskCacheAttributes cattr, TableState tableState );
81  
82      /***
83       * Creates a JDBCDiskCache for the region if one doesn't exist, else it returns the precreated
84       * instance. It also adds the region to the shrinker thread if needed.
85       * <p>
86       * @param cattr
87       * @return The cache value
88       */
89      public AuxiliaryCache getCache( JDBCDiskCacheAttributes cattr )
90      {
91          AuxiliaryCache diskCache = null;
92  
93          log.debug( "cacheName = " + cattr.getCacheName() );
94  
95          synchronized ( caches )
96          {
97              diskCache = (AuxiliaryCache) caches.get( cattr.getCacheName() );
98  
99              if ( diskCache == null )
100             {
101                 TableState tableState = (TableState) tableStates.get( cattr.getTableName() );
102 
103                 if ( tableState == null )
104                 {
105                     tableState = new TableState( cattr.getTableName() );
106                 }
107 
108                 diskCache = createJDBCDiskCache( cattr, tableState );
109 
110                 caches.put( cattr.getCacheName(), diskCache );
111             }
112         }
113 
114         if ( log.isDebugEnabled() )
115         {
116             log.debug( "JDBC cache = " + diskCache );
117         }
118 
119         // create a shrinker if we need it.
120         createShrinkerWhenNeeded( cattr, diskCache );
121 
122         return diskCache;
123     }
124 
125     /***
126      * If UseDiskShrinker is true then we will create a shrinker daemon if necessary.
127      * <p>
128      * @param cattr
129      * @param raf
130      */
131     protected void createShrinkerWhenNeeded( JDBCDiskCacheAttributes cattr, AuxiliaryCache raf )
132     {
133         // add cache to shrinker.
134         if ( cattr.isUseDiskShrinker() )
135         {
136             if ( shrinkerDaemon == null )
137             {
138                 shrinkerDaemon = new ClockDaemon();
139                 shrinkerDaemon.setThreadFactory( new MyThreadFactory() );
140             }
141 
142             ShrinkerThread shrinkerThread = (ShrinkerThread) shrinkerThreadMap.get( cattr.getTableName() );
143             if ( shrinkerThread == null )
144             {
145                 shrinkerThread = new ShrinkerThread();
146                 shrinkerThreadMap.put( cattr.getTableName(), shrinkerThread );
147 
148                 long intervalMillis = Math.max( 999, cattr.getShrinkerIntervalSeconds() * 1000 );
149                 if ( log.isInfoEnabled() )
150                 {
151                     log.info( "Setting the shrinker to run every [" + intervalMillis + "] ms. for table ["
152                         + cattr.getTableName() + "]" );
153                 }
154                 shrinkerDaemon.executePeriodically( intervalMillis, shrinkerThread, false );
155             }
156             shrinkerThread.addDiskCacheToShrinkList( (JDBCDiskCache) raf );
157         }
158     }
159 
160     /***
161      * @param name
162      */
163     public void freeCache( String name )
164     {
165         JDBCDiskCache raf = (JDBCDiskCache) caches.get( name );
166         if ( raf != null )
167         {
168             raf.dispose();
169         }
170     }
171 
172     /***
173      * Gets the cacheType attribute of the HSQLCacheManager object
174      * <p>
175      * @return The cacheType value
176      */
177     public int getCacheType()
178     {
179         return DISK_CACHE;
180     }
181 
182     /*** Disposes of all regions. */
183     public void release()
184     {
185         // Wait until called by the last client
186         if ( --clients != 0 )
187         {
188             return;
189         }
190         synchronized ( caches )
191         {
192             Enumeration allCaches = caches.elements();
193 
194             while ( allCaches.hasMoreElements() )
195             {
196                 JDBCDiskCache raf = (JDBCDiskCache) allCaches.nextElement();
197                 if ( raf != null )
198                 {
199                     raf.dispose();
200                 }
201             }
202         }
203     }
204 
205     /***
206      * Allows us to set the daemon status on the clockdaemon
207      * <p>
208      * @author aaronsm
209      */
210     class MyThreadFactory
211         implements ThreadFactory
212     {
213         /***
214          * Set the priority to min and daemon to true.
215          * <p>
216          * @param runner
217          * @return the daemon thread.
218          */
219         public Thread newThread( Runnable runner )
220         {
221             Thread t = new Thread( runner );
222             t.setDaemon( true );
223             t.setPriority( Thread.MIN_PRIORITY );
224             return t;
225         }
226     }
227 }