001 package org.apache.jcs.auxiliary.disk.jdbc.mysql;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.Serializable;
023 import java.util.Date;
024 import java.util.Timer;
025 import java.util.TimerTask;
026
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029 import org.apache.jcs.auxiliary.disk.jdbc.JDBCDiskCacheAttributes;
030 import org.apache.jcs.auxiliary.disk.jdbc.JDBCDiskCacheManagerAbstractTemplate;
031 import org.apache.jcs.auxiliary.disk.jdbc.JDBCDiskCachePoolAccess;
032 import org.apache.jcs.auxiliary.disk.jdbc.TableState;
033 import org.apache.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleFormatException;
034 import org.apache.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
035 import org.apache.jcs.engine.behavior.ICompositeCacheManager;
036 import org.apache.jcs.engine.behavior.IElementSerializer;
037 import org.apache.jcs.engine.logging.behavior.ICacheEventLogger;
038
039 /**
040 * This manages instances of the MySQL jdbc disk cache. It maintains one for each region. One for
041 * all regions would work, but this gives us more detailed stats by region.
042 * <p>
043 * Although the generic JDBC Disk Cache Manager can be used for MySQL, the MySQL JDBC Disk Cache has
044 * additional features, such as table optimization that are particular to MySQL.
045 */
046 public class MySQLDiskCacheManager
047 extends JDBCDiskCacheManagerAbstractTemplate
048 {
049 /** Don't change. */
050 private static final long serialVersionUID = -8258856770927857896L;
051
052 /** The logger */
053 protected static final Log log = LogFactory.getLog( MySQLDiskCacheManager.class );
054
055 /** The singleton instance. */
056 private static MySQLDiskCacheManager instance;
057
058 /** User configurable attributes. */
059 private final MySQLDiskCacheAttributes defaultJDBCDiskCacheAttributes;
060
061 /** ms in a day */
062 private static final int DAILY_INTERVAL = 60 * 60 * 24 * 1000;
063
064 /** for schedule optimizations */
065 private Timer daemon = null;
066
067 /** The cache manager instance */
068 private ICompositeCacheManager compositeCacheManager;
069
070 /**
071 * Constructor for the HSQLCacheManager object
072 * <p>
073 * @param cattr
074 * @param compositeCacheManager
075 * @param cacheEventLogger
076 * @param elementSerializer
077 */
078 private MySQLDiskCacheManager( MySQLDiskCacheAttributes cattr, ICompositeCacheManager compositeCacheManager,
079 ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
080 {
081 if ( log.isInfoEnabled() )
082 {
083 log.info( "Creating MySQLDiskCacheManager with " + cattr );
084 }
085 defaultJDBCDiskCacheAttributes = cattr;
086 setElementSerializer( elementSerializer );
087 setCacheEventLogger( cacheEventLogger );
088 setCompositeCacheManager( compositeCacheManager );
089 }
090
091 /**
092 * Gets the defaultCattr attribute of the HSQLCacheManager object
093 * <p>
094 * @return The defaultCattr value
095 */
096 public MySQLDiskCacheAttributes getDefaultJDBCDiskCacheAttributes()
097 {
098 return defaultJDBCDiskCacheAttributes;
099 }
100
101 /**
102 * Gets the instance attribute of the HSQLCacheManager class
103 * <p>
104 * @param cattr
105 * @param compositeCacheManager
106 * @param cacheEventLogger
107 * @param elementSerializer
108 * @return The instance value
109 */
110 public static MySQLDiskCacheManager getInstance( MySQLDiskCacheAttributes cattr, ICompositeCacheManager compositeCacheManager,
111 ICacheEventLogger cacheEventLogger,
112 IElementSerializer elementSerializer )
113 {
114 synchronized ( MySQLDiskCacheManager.class )
115 {
116 if ( instance == null )
117 {
118 instance = new MySQLDiskCacheManager( cattr, compositeCacheManager, cacheEventLogger, elementSerializer );
119 }
120 }
121 clients++;
122 return instance;
123 }
124
125 /**
126 * Gets the cache attribute of the HSQLCacheManager object
127 * <p>
128 * @param cacheName
129 * @return The cache value
130 */
131 @SuppressWarnings("unchecked")
132 public <K extends Serializable, V extends Serializable> MySQLDiskCache<K, V> getCache( String cacheName )
133 {
134 MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) defaultJDBCDiskCacheAttributes.copy();
135 cattr.setCacheName( cacheName );
136 return (MySQLDiskCache<K, V>) getCache( cattr );
137 }
138
139 /**
140 * Creates a JDBCDiskCache using the supplied attributes.
141 * <p>
142 * @param cattr
143 * @param tableState
144 * @return AuxiliaryCache
145 */
146 @Override
147 protected <K extends Serializable, V extends Serializable> MySQLDiskCache<K, V> createJDBCDiskCache( JDBCDiskCacheAttributes cattr, TableState tableState )
148 {
149 MySQLDiskCache<K, V> diskCache = new MySQLDiskCache<K, V>( (MySQLDiskCacheAttributes) cattr, tableState, getCompositeCacheManager() );
150
151 scheduleOptimizations( (MySQLDiskCacheAttributes) cattr, tableState, diskCache.getPoolAccess() );
152
153 return diskCache;
154 }
155
156 /**
157 * @param compositeCacheManager the compositeCacheManager to set
158 */
159 protected void setCompositeCacheManager( ICompositeCacheManager compositeCacheManager )
160 {
161 this.compositeCacheManager = compositeCacheManager;
162 }
163
164 /**
165 * @return the compositeCacheManager
166 */
167 protected ICompositeCacheManager getCompositeCacheManager()
168 {
169 return compositeCacheManager;
170 }
171 /**
172 * For each time in the optimization schedule, this calls schedule Optimizaiton.
173 * <p>
174 * @param attributes configuration propeties.
175 * @param tableState for noting optimization in progress, etc.
176 * @param poolAccess access to the pool
177 */
178 protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, JDBCDiskCachePoolAccess poolAccess )
179 {
180 if ( attributes != null )
181 {
182 if ( attributes.getOptimizationSchedule() != null )
183 {
184 if ( log.isInfoEnabled() )
185 {
186 log.info( "Will try to configure optimization for table [" + attributes.getTableName()
187 + "] on schdule [" + attributes.getOptimizationSchedule() + "]" );
188 }
189
190 MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, poolAccess );
191
192 // loop through the dates.
193 try
194 {
195 Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() );
196 if ( dates != null )
197 {
198 for ( int i = 0; i < dates.length; i++ )
199 {
200 this.scheduleOptimization( dates[i], optimizer );
201 }
202 }
203 }
204 catch ( ScheduleFormatException e )
205 {
206 log.warn( "Problem creating optimization schedule for table [" + attributes.getTableName() + "]" );
207 }
208 }
209 else
210 {
211 if ( log.isInfoEnabled() )
212 {
213 log.info( "Optimization is not configured for table [" + attributes.getTableName() + "]" );
214 }
215 }
216 }
217 }
218
219 /**
220 * This takes in a single time and schedules the optimizer to be called at that time every day.
221 * <p>
222 * @param startTime -- HH:MM:SS format
223 * @param optimizer
224 */
225 protected void scheduleOptimization( Date startTime, MySQLTableOptimizer optimizer )
226 {
227 if ( log.isInfoEnabled() )
228 {
229 log.info( "startTime [" + startTime + "] for optimizer " + optimizer );
230 }
231
232 // create clock daemon if necessary
233 if ( daemon == null )
234 {
235 // true for daemon status
236 daemon = new Timer( true );
237 }
238
239 // get the runnable from the factory
240 TimerTask runnable = new OptimizerTask( optimizer );
241
242 // have the daemon execute our runnable
243 // false to not execute immediately.
244 daemon.scheduleAtFixedRate( runnable, startTime, DAILY_INTERVAL );
245
246 if ( log.isInfoEnabled() )
247 {
248 log.info( "Scheduled optimization to begin at [" + startTime + "]" );
249 }
250 }
251
252 /**
253 * This calls the optimizers' optimize table method. This is used by the timer.
254 * <p>
255 * @author Aaron Smuts
256 */
257 private static class OptimizerTask
258 extends TimerTask
259 {
260 /** Handles optimization */
261 private MySQLTableOptimizer optimizer = null;
262
263 /**
264 * Get a handle on the optimizer.
265 * <p>
266 * @param optimizer
267 */
268 public OptimizerTask( MySQLTableOptimizer optimizer )
269 {
270 this.optimizer = optimizer;
271 }
272
273 /**
274 * This calls optimize on the optimizer.
275 * <p>
276 * @see java.lang.Runnable#run()
277 */
278 @Override
279 public void run()
280 {
281 if ( optimizer != null )
282 {
283 boolean success = optimizer.optimizeTable();
284 if ( log.isInfoEnabled() )
285 {
286 log.info( "Optimization success status [" + success + "]" );
287 }
288 }
289 else
290 {
291 log.warn( "OptimizerRunner: The optimizer is null. Could not optimize table." );
292 }
293 }
294 }
295 }