001package org.apache.commons.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 022import java.sql.SQLException; 023import java.text.ParseException; 024import java.util.Date; 025import java.util.concurrent.TimeUnit; 026 027import javax.sql.DataSource; 028 029import org.apache.commons.jcs.auxiliary.AuxiliaryCacheAttributes; 030import org.apache.commons.jcs.auxiliary.disk.jdbc.JDBCDiskCacheFactory; 031import org.apache.commons.jcs.auxiliary.disk.jdbc.TableState; 032import org.apache.commons.jcs.auxiliary.disk.jdbc.dsfactory.DataSourceFactory; 033import org.apache.commons.jcs.auxiliary.disk.jdbc.mysql.util.ScheduleParser; 034import org.apache.commons.jcs.engine.behavior.ICompositeCacheManager; 035import org.apache.commons.jcs.engine.behavior.IElementSerializer; 036import org.apache.commons.jcs.engine.logging.behavior.ICacheEventLogger; 037import org.apache.commons.logging.Log; 038import org.apache.commons.logging.LogFactory; 039 040/** 041 * This factory should create mysql disk caches. 042 * <p> 043 * @author Aaron Smuts 044 */ 045public class MySQLDiskCacheFactory 046 extends JDBCDiskCacheFactory 047{ 048 /** The logger */ 049 private static final Log log = LogFactory.getLog( MySQLDiskCacheFactory.class ); 050 051 /** 052 * This factory method should create an instance of the mysqlcache. 053 * <p> 054 * @param rawAttr specific cache configuration attributes 055 * @param compositeCacheManager the global cache manager 056 * @param cacheEventLogger a specific logger for cache events 057 * @param elementSerializer a serializer for cache elements 058 * @return MySQLDiskCache the cache instance 059 * @throws SQLException if the cache instance could not be created 060 */ 061 @Override 062 public <K, V> MySQLDiskCache<K, V> createCache( AuxiliaryCacheAttributes rawAttr, 063 ICompositeCacheManager compositeCacheManager, 064 ICacheEventLogger cacheEventLogger, IElementSerializer elementSerializer ) 065 throws SQLException 066 { 067 MySQLDiskCacheAttributes cattr = (MySQLDiskCacheAttributes) rawAttr; 068 TableState tableState = getTableState( cattr.getTableName() ); 069 DataSourceFactory dsFactory = getDataSourceFactory(cattr, compositeCacheManager.getConfigurationProperties()); 070 071 MySQLDiskCache<K, V> cache = new MySQLDiskCache<K, V>( cattr, dsFactory, tableState, compositeCacheManager ); 072 cache.setCacheEventLogger( cacheEventLogger ); 073 cache.setElementSerializer( elementSerializer ); 074 075 // create a shrinker if we need it. 076 createShrinkerWhenNeeded( cattr, cache ); 077 scheduleOptimizations( cattr, tableState, cache.getDataSource() ); 078 079 return cache; 080 081 } 082 083 /** 084 * For each time in the optimization schedule, this calls schedule Optimization. 085 * <p> 086 * @param attributes configuration properties. 087 * @param tableState for noting optimization in progress, etc. 088 * @param ds the DataSource 089 */ 090 protected void scheduleOptimizations( MySQLDiskCacheAttributes attributes, TableState tableState, DataSource ds ) 091 { 092 if ( attributes != null ) 093 { 094 if ( attributes.getOptimizationSchedule() != null ) 095 { 096 if ( log.isInfoEnabled() ) 097 { 098 log.info( "Will try to configure optimization for table [" + attributes.getTableName() 099 + "] 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}