001package org.apache.commons.jcs3.auxiliary.disk.jdbc; 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.util.Iterator; 023import java.util.concurrent.CopyOnWriteArraySet; 024 025import org.apache.commons.jcs3.log.Log; 026import org.apache.commons.jcs3.log.LogManager; 027import org.apache.commons.jcs3.utils.timing.ElapsedTimer; 028 029/** 030 * Calls delete expired on the disk caches. The shrinker is run by a clock daemon. The shrinker 031 * calls delete on each region. It pauses between calls. 032 */ 033public class ShrinkerThread 034 implements Runnable 035{ 036 /** The logger. */ 037 private static final Log log = LogManager.getLog( ShrinkerThread.class ); 038 039 /** A set of JDBCDiskCache objects to call deleteExpired on. */ 040 private final CopyOnWriteArraySet<JDBCDiskCache<?, ?>> shrinkSet = 041 new CopyOnWriteArraySet<>(); 042 043 /** Default time period to use. */ 044 private static final long DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS = 5000; 045 046 /** 047 * How long should we wait between calls to deleteExpired when we are iterating through the list 048 * of regions. Delete can lock the table. We want to give clients a chance to get some work 049 * done. 050 */ 051 private long pauseBetweenRegionCallsMillis = DEFAULT_PAUSE_BETWEEN_REGION_CALLS_MILLIS; 052 053 /** 054 * Does nothing special. 055 */ 056 protected ShrinkerThread() 057 { 058 } 059 060 /** 061 * Adds a JDBC disk cache to the set of disk cache to shrink. 062 * <p> 063 * @param diskCache 064 */ 065 public void addDiskCacheToShrinkList( final JDBCDiskCache<?, ?> diskCache ) 066 { 067 // the set will prevent dupes. 068 // we could also just add these to a hashmap by region name 069 // but that might cause a problem if you wanted to use two different 070 // jbdc disk caches for the same region. 071 shrinkSet.add( diskCache ); 072 } 073 074 /** 075 * Calls deleteExpired on each item in the set. It pauses between each call. 076 */ 077 @Override 078 public void run() 079 { 080 try 081 { 082 deleteExpiredFromAllRegisteredRegions(); 083 } 084 catch ( final Throwable e ) 085 { 086 log.error( "Caught an exception while trying to delete expired items.", e ); 087 } 088 } 089 090 /** 091 * Deletes the expired items from all the registered regions. 092 */ 093 private void deleteExpiredFromAllRegisteredRegions() 094 { 095 log.info( "Running JDBC disk cache shrinker. Number of regions [{0}]", 096 shrinkSet::size); 097 098 for (final Iterator<JDBCDiskCache<?, ?>> i = shrinkSet.iterator(); i.hasNext();) 099 { 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}