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