View Javadoc
1   package org.apache.commons.jcs3.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.jcs3.auxiliary.AuxiliaryCacheAttributes;
30  import org.apache.commons.jcs3.auxiliary.disk.jdbc.JDBCDiskCacheFactory;
31  import org.apache.commons.jcs3.auxiliary.disk.jdbc.TableState;
32  import org.apache.commons.jcs3.auxiliary.disk.jdbc.dsfactory.DataSourceFactory;
33  import org.apache.commons.jcs3.auxiliary.disk.jdbc.mysql.util.ScheduleParser;
34  import org.apache.commons.jcs3.engine.behavior.ICompositeCacheManager;
35  import org.apache.commons.jcs3.engine.behavior.IElementSerializer;
36  import org.apache.commons.jcs3.engine.logging.behavior.ICacheEventLogger;
37  import org.apache.commons.jcs3.log.Log;
38  import org.apache.commons.jcs3.log.LogManager;
39  
40  /**
41   * This factory should create mysql disk caches.
42   */
43  public class MySQLDiskCacheFactory
44      extends JDBCDiskCacheFactory
45  {
46      /** The logger */
47      private static final Log log = LogManager.getLog( MySQLDiskCacheFactory.class );
48  
49      /**
50       * This factory method should create an instance of the mysqlcache.
51       * <p>
52       * @param rawAttr specific cache configuration attributes
53       * @param compositeCacheManager the global cache manager
54       * @param cacheEventLogger a specific logger for cache events
55       * @param elementSerializer a serializer for cache elements
56       * @return MySQLDiskCache the cache instance
57       * @throws SQLException if the cache instance could not be created
58       */
59      @Override
60      public <K, V> MySQLDiskCache<K, V> createCache( final AuxiliaryCacheAttributes rawAttr,
61              final ICompositeCacheManager compositeCacheManager,
62              final ICacheEventLogger cacheEventLogger, final IElementSerializer elementSerializer )
63              throws SQLException
64      {
65          final MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr;
66          final TableState tableState = getTableState( cattr.getTableName() );
67          final DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties());
68  
69          final MySQLDiskCache<K, V> cache = new MySQLDiskCache<>( cattr, dsFactory, tableState);
70          cache.setCacheEventLogger( cacheEventLogger );
71          cache.setElementSerializer( elementSerializer );
72  
73          // create a shrinker if we need it.
74          createShrinkerWhenNeeded( cattr, cache );
75          scheduleOptimizations( cattr, tableState, cache.getDataSource() );
76  
77          return cache;
78  
79      }
80  
81      /**
82       * For each time in the optimization schedule, this calls schedule Optimization.
83       * <p>
84       * @param attributes configuration properties.
85       * @param tableState for noting optimization in progress, etc.
86       * @param ds the DataSource
87       */
88      protected void scheduleOptimizations( final MySQLDiskCacheAttributes attributes, final TableState tableState, final DataSource ds  )
89      {
90          if ( attributes != null )
91          {
92              if ( attributes.getOptimizationSchedule() != null )
93              {
94                  log.info( "Will try to configure optimization for table [{0}] on schedule [{1}]",
95                          attributes::getTableName, attributes::getOptimizationSchedule);
96  
97                  final MySQLTableOptimizer optimizer = new MySQLTableOptimizer( attributes, tableState, ds );
98  
99                  // loop through the dates.
100                 try
101                 {
102                     // canĀ“t be null, otherwise ScheduleParser.createDatesForSchedule will throw ParseException
103                     final Date[] dates = ScheduleParser.createDatesForSchedule( attributes.getOptimizationSchedule() );
104                     for (final Date date : dates) {
105                         this.scheduleOptimization( date, optimizer );
106                     }
107                 }
108                 catch ( final ParseException e )
109                 {
110                     log.warn( "Problem creating optimization schedule for table [{0}]",
111                             attributes.getTableName(), e );
112                 }
113             }
114             else
115             {
116                 log.info( "Optimization is not configured for table [{0}]",
117                         attributes.getTableName());
118             }
119         }
120     }
121 
122     /**
123      * This takes in a single time and schedules the optimizer to be called at that time every day.
124      * <p>
125      * @param startTime -- HH:MM:SS format
126      * @param optimizer
127      */
128     protected void scheduleOptimization( final Date startTime, final MySQLTableOptimizer optimizer )
129     {
130         log.info( "startTime [{0}] for optimizer {1}", startTime, optimizer );
131 
132         final Date now = new Date();
133         final long initialDelay = startTime.getTime() - now.getTime();
134 
135         // have the daemon execute the optimization
136         getScheduledExecutorService().scheduleAtFixedRate(() -> optimizeTable(optimizer),
137                 initialDelay, 86400L, TimeUnit.SECONDS );
138     }
139 
140     /**
141      * This calls the optimizers' optimize table method. This is used by the timer.
142      */
143     private static void optimizeTable(final MySQLTableOptimizer optimizer)
144     {
145         if ( optimizer != null )
146         {
147             final boolean success = optimizer.optimizeTable();
148             log.info( "Optimization success status [{0}]", success );
149         }
150         else
151         {
152             log.warn( "OptimizerRunner: The optimizer is null. Could not optimize table." );
153         }
154     }
155 }