View Javadoc
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 }