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