View Javadoc
1   package org.apache.commons.jcs.auxiliary.disk.jdbc.mysql;
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.sql.SQLException;
23  import java.text.ParseException;
24  import java.util.Date;
25  import java.util.concurrent.TimeUnit;
26  
27  import javax.sql.DataSource;
28  
29  import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes;
30  import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
31  import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState;
32  import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
33  import org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
34  import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager;
35  import org.apache.commons.jcs.engine.behavior.IElementSerializer;
36  import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /**
41   * This factory should create mysql disk caches.
42   * <p>
43   * @author Aaron Smuts
44   */
45  public class MySQLDiskCacheFactory
46      extends JDBCDiskCacheFactory
47  {
48      /** The logger */
49      private static final Log log = LogFactory.getLog( MySQLDiskCacheFactory.class );
50  
51      /**
52       * This factory method should create an instance of the mysqlcache.
53       * <p>
54       * @param rawAttr specific cache configuration attributes
55       * @param compositeCacheManager the global cache manager
56       * @param cacheEventLogger a specific logger for cache events
57       * @param elementSerializer a serializer for cache elements
58       * @return MySQLDiskCache the cache instance
59       * @throws SQLException if the cache instance could not be created
60       */
61      @Override
62      public <K, V> MySQLDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr,
63              ICompositeCacheManager compositeCacheManager,
64              ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer )
65              throws SQLException
66      {
67          MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr;
68          TableState tableState = getTableState( cattr.getTableName() );
69          DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
70  
71          MySQLDiskCache<K, V> cache = new MySQLDiskCache<K, V>( cattr, dsFactory, tableState, compositeCacheManager );
72          cache.setCacheEventLogger( cacheEventLogger );
73          cache.setElementSerializer( elementSerializer );
74  
75          // create a shrinker if we need it.
76          createShrinkerWhenNeeded( cattr, cache );
77          scheduleOptimizations( cattr, tableState, cache.getDataSource() );
78  
79          return cache;
80  
81      }
82  
83      /**
84       * For each time in the optimization schedule, this calls schedule Optimization.
85       * <p>
86       * @param attributes configuration properties.
87       * @param tableState for noting optimization in progress, etc.
88       * @param ds the DataSource
89       */
90      protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource ds  )
91      {
92          if ( attributes != null )
93          {
94              if ( attributes.getOptimizationSchedule() != null )
95              {
96                  if ( log.isInfoEnabled() )
97                  {
98                      log.info( "Will try to configure optimization for table [" + attributes.getTableName()
99                          + "] on schedule [" + attributes.getOptimizationSchedule() + "]" );
100                 }
101 
102                 MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, ds );
103 
104                 // loop through the dates.
105                 try
106                 {
107                     Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() );
108                     if ( dates != null )
109                     {
110                         for ( int i = 0; i < dates.length; i++ )
111                         {
112                             this.scheduleOptimization( dates[i], optimizer );
113                         }
114                     }
115                 }
116                 catch ( ParseException e )
117                 {
118                     log.warn( "Problem creating optimization schedule for table [" + attributes.getTableName() + "]", e );
119                 }
120             }
121             else
122             {
123                 if ( log.isInfoEnabled() )
124                 {
125                     log.info( "Optimization is not configured for table [" + attributes.getTableName() + "]" );
126                 }
127             }
128         }
129     }
130 
131     /**
132      * This takes in a single time and schedules the optimizer to be called at that time every day.
133      * <p>
134      * @param startTime -- HH:MM:SS format
135      * @param optimizer
136      */
137     protected void scheduleOptimization( Date startTime, MySQLTableOptimizer optimizer )
138     {
139         if ( log.isInfoEnabled() )
140         {
141             log.info( "startTime [" + startTime + "] for optimizer " + optimizer );
142         }
143 
144         // get the runnable from the factory
145         OptimizerTask runnable = new OptimizerTask( optimizer );
146         Date now = new Date();
147         long initialDelay = startTime.getTime() - now.getTime();
148 
149         // have the daemon execute our runnable
150         getScheduledExecutorService().scheduleAtFixedRate(runnable, initialDelay, 86400000L, TimeUnit.MILLISECONDS );
151     }
152 
153     /**
154      * This calls the optimizers' optimize table method. This is used by the timer.
155      * <p>
156      * @author Aaron Smuts
157      */
158     private static class OptimizerTask
159         implements Runnable
160     {
161         /** Handles optimization */
162         private MySQLTableOptimizer optimizer = null;
163 
164         /**
165          * Get a handle on the optimizer.
166          * <p>
167          * @param optimizer
168          */
169         public OptimizerTask( MySQLTableOptimizer optimizer )
170         {
171             this.optimizer = optimizer;
172         }
173 
174         /**
175          * This calls optimize on the optimizer.
176          * <p>
177          * @see java.lang.Runnable#run()
178          */
179         @Override
180         public void run()
181         {
182             if ( optimizer != null )
183             {
184                 boolean success = optimizer.optimizeTable();
185                 if ( log.isInfoEnabled() )
186                 {
187                     log.info( "Optimization success status [" + success + "]" );
188                 }
189             }
190             else
191             {
192                 log.warn( "OptimizerRunner: The optimizer is null.  Could not optimize table." );
193             }
194         }
195     }
196 }