1 package org.apache.commons.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 org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.Set;
28
29 /**
30 * Calls delete expired on the disk caches. The shrinker is run by a clock daemon. The shrinker
31 * calls delete on each region. It pauses between calls.
32 * <p>
33 * @author Aaron Smuts
34 */
35 public class ShrinkerThread
36 implements Runnable
37 {
38 /** The logger. */
39 private static final Log log = LogFactory.getLog( ShrinkerThread.class );
40
41 /** A set of JDBCDiskCache objects to call deleteExpired on. */
42 private final Set<JDBCDiskCache<?, ?>> shrinkSet =
43 Collections.synchronizedSet( new HashSet<JDBCDiskCache<?, ?>>() );
44
45 /** Default time period to use. */
46 private static final long DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS = 5000;
47
48 /**
49 * How long should we wait between calls to deleteExpired when we are iterating through the list
50 * of regions. Delete can lock the table. We want to give clients a chance to get some work
51 * done.
52 */
53 private long pauseBetweenRegionCallsMillis = DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS;
54
55 /**
56 * Does nothing special.
57 */
58 protected ShrinkerThread()
59 {
60 super();
61 }
62
63 /**
64 * Adds a JDBC disk cache to the set of disk cache to shrink.
65 * <p>
66 * @param diskCache
67 */
68 public void addDiskCacheToShrinkList( JDBCDiskCache<?, ?> diskCache )
69 {
70 // the set will prevent dupes.
71 // we could also just add these to a hashmap by region name
72 // but that might cause a problem if you wanted to use two different
73 // jbdc disk caches for the same region.
74 shrinkSet.add( diskCache );
75 }
76
77 /**
78 * Calls deleteExpired on each item in the set. It pauses between each call.
79 */
80 @Override
81 public void run()
82 {
83 try
84 {
85 deleteExpiredFromAllRegisteredRegions();
86 }
87 catch ( Throwable e )
88 {
89 log.error( "Caught an expcetion while trying to delete expired items.", e );
90 }
91 }
92
93 /**
94 * Deletes the expired items from all the registered regions.
95 */
96 private void deleteExpiredFromAllRegisteredRegions()
97 {
98 if ( log.isInfoEnabled() )
99 {
100 log.info( "Running JDBC disk cache shrinker. Number of regions [" + shrinkSet.size() + "]" );
101 }
102
103 Object[] caches = null;
104
105 synchronized ( shrinkSet )
106 {
107 caches = this.shrinkSet.toArray();
108 }
109
110 if ( caches != null )
111 {
112 for ( int i = 0; i < caches.length; i++ )
113 {
114 JDBCDiskCache<?, ?> cache = (JDBCDiskCache<?, ?>) caches[i];
115
116 long start = System.currentTimeMillis();
117 int deleted = cache.deleteExpired();
118 long end = System.currentTimeMillis();
119
120 if ( log.isInfoEnabled() )
121 {
122 log.info( "Deleted [" + deleted + "] expired for region [" + cache.getCacheName() + "] for table ["
123 + cache.getTableName() + "] in " + ( end - start ) + " ms." );
124 }
125
126 // don't pause after the last call to delete expired.
127 if ( i < caches.length - 1 )
128 {
129 if ( log.isInfoEnabled() )
130 {
131 log.info( "Pausing for [" + this.getPauseBetweenRegionCallsMillis()
132 + "] ms. before shrinking the next region." );
133 }
134
135 try
136 {
137 Thread.sleep( this.getPauseBetweenRegionCallsMillis() );
138 }
139 catch ( InterruptedException e )
140 {
141 log.warn( "Interrupted while waiting to delete expired for the next region." );
142 }
143 }
144 }
145 }
146 }
147
148 /**
149 * How long should we wait between calls to deleteExpired when we are iterating through the list
150 * of regions.
151 * <p>
152 * @param pauseBetweenRegionCallsMillis The pauseBetweenRegionCallsMillis to set.
153 */
154 public void setPauseBetweenRegionCallsMillis( long pauseBetweenRegionCallsMillis )
155 {
156 this.pauseBetweenRegionCallsMillis = pauseBetweenRegionCallsMillis;
157 }
158
159 /**
160 * How long should we wait between calls to deleteExpired when we are iterating through the list
161 * of regions.
162 * <p>
163 * @return Returns the pauseBetweenRegionCallsMillis.
164 */
165 public long getPauseBetweenRegionCallsMillis()
166 {
167 return pauseBetweenRegionCallsMillis;
168 }
169 }