jtaylor 02/05/16 06:10:20
Modified: src/java/org/apache/jcs/engine/memory/shrinking
ShrinkerThread.java
Log:
Cleaning up the ShrinkerThread. Shouldn't affect
functionality.
Revision Changes Path
1.9 +209 -135
jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/shrinking/ShrinkerThread.java
Index: ShrinkerThread.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/shrinking/ShrinkerThread.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- ShrinkerThread.java 13 May 2002 22:16:18 -0000 1.8
+++ ShrinkerThread.java 16 May 2002 13:10:20 -0000 1.9
@@ -53,53 +53,75 @@
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
-import java.util.Map;
+
+import java.io.IOException;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
-import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.jcs.engine.memory.MemoryCache;
-import org.apache.jcs.engine.memory.MemoryElementDescriptor;
-
+import org.apache.jcs.engine.behavior.ICacheElement;
+import org.apache.jcs.engine.behavior.IElementAttributes;
import org.apache.jcs.engine.control.event.ElementEvent;
-import org.apache.jcs.engine.control.event.behavior.IElementEventHandler;
import org.apache.jcs.engine.control.event.behavior.IElementEvent;
import org.apache.jcs.engine.control.event.behavior.IElementEventConstants;
-import org.apache.jcs.engine.behavior.ICacheElement;
+import org.apache.jcs.engine.control.event.behavior.IElementEventHandler;
+import org.apache.jcs.engine.memory.MemoryCache;
/**
- * A background memory shrinker. Memory problems and concurrent modification
- * exception caused by acting directly on an iterator of the underlying memory
- * cache should have been solved.
+ * A background memory shrinker. Memory problems and concurrent modification
+ * exception caused by acting directly on an iterator of the underlying memory
+ * cache should have been solved.
*
- *@author <a href="mailto:[EMAIL PROTECTED]">Aaron Smuts</a>
- *@created February 18, 2002
- *@version $Id:
+ * @author <a href="mailto:[EMAIL PROTECTED]">Aaron Smuts</a>
+ * @version $Id: ShrinkerThread.java,v 1.9 2002/05/16 13:10:20 jtaylor Exp $
*/
public class ShrinkerThread extends Thread
{
+ private final static Log log = LogFactory.getLog( ShrinkerThread.class );
- private MemoryCache cache;
- boolean alive = true;
+ /** The MemoryCache instance which this shrinker is watching */
+ private final MemoryCache cache;
+
+ /** The time to sleep between shrink runs */
+ private final long shrinkerInterval;
- private final static Log log =
- LogFactory.getLog( ShrinkerThread.class );
+ /** Maximum memory idle time for the whole cache */
+ private final long maxMemoryIdleTime;
+
+ /** Flag that indicates if the thread is still alive */
+ boolean alive = true;
/**
- * Constructor for the ShrinkerThread object. Should take an IMemoryCache
+ * Constructor for the ShrinkerThread object.
*
- *@param cache
+ * @param cache The MemoryCache which the new shrinker should watch.
*/
public ShrinkerThread( MemoryCache cache )
{
super();
+
this.cache = cache;
+
+ this.shrinkerInterval =
+ cache.getCacheAttributes().getShrinkerIntervalSeconds() * 1000;
+
+ long maxMemoryIdleTimeSeconds =
+ cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds();
+
+ if ( maxMemoryIdleTimeSeconds == -1 )
+ {
+ this.maxMemoryIdleTime = -1;
+ }
+ else
+ {
+ this.maxMemoryIdleTime = maxMemoryIdleTimeSeconds * 1000;
+ }
}
/**
- * Graceful shutdown after this round of processing.
+ * Graceful shutdown after this round of processing.
*/
public void kill()
{
@@ -107,11 +129,10 @@
}
/**
- * Main processing method for the ShrinkerThread object
+ * Main processing method for the ShrinkerThread object
*/
public void run()
{
-
while ( alive )
{
@@ -119,158 +140,124 @@
try
{
- this.sleep( cache.getCacheAttributes()
- .getShrinkerIntervalSeconds() * 1000 );
+ this.sleep( shrinkerInterval );
}
catch ( InterruptedException ie )
{
- return;
+ // Continue until killed ( alive == false )
}
}
+
return;
}
-
/**
- * This method is called when the thread wakes up. A. The method obtains an
- * array of keys for the cache region. B. It iterates through the keys and
- * tries to get the item from the cache without affecting the last access
- * or position of the item. C. Then the item is checked for expiration.
- * This expiration check has 3 parts: 1. Has the
- * cacheattributes.MaxMemoryIdleTimeSeconds defined for the region been
- * exceeded? If so, the item should be move to disk. 2. Has the item
- * exceeded MaxLifeSeconds defined in the element atributes? If so, remove
- * it. 3. Has the item exceeded IdleTime defined in the element atributes?
- * If so, remove it. If there are event listeners registered for the cache
- * element, they will be called.
+ * This method is called when the thread wakes up. Frist the method obtains
+ * an array of keys for the cache region. It iterates through the keys and
+ * tries to get the item from the cache without affecting the last access
+ * or position of the item. The item is checked for expiration, the
+ * expiration check has 3 parts:
+ * <ol>
+ * <li>
+ * Has the cacheattributes.MaxMemoryIdleTimeSeconds defined for the
+ * region been exceeded? If so, the item should be move to disk.
+ * </li>
+ * <li>
+ * Has the item exceeded MaxLifeSeconds defined in the element
+ * attributes? If so, remove it.
+ * </li>
+ * <li>
+ * Has the item exceeded IdleTime defined in the element atributes?
+ * If so, remove it. If there are event listeners registered for
+ * the cache element, they will be called.
+ * </li>
+ * </ol>
*
- *@TODO Change element event handling to use the queue, then move the
- * queue to the region and access via the Cache.
+ * @todo Change element event handling to use the queue, then move the
+ * queue to the region and access via the Cache.
*/
protected void shrink()
{
-
if ( log.isDebugEnabled() )
{
- log.debug( "Shrinking" );
+ log.debug( "Shrinking memory cache for: "
+ + this.cache.getCompositeCache().getCacheName() );
}
try
{
-
-
Object[] keys = cache.getKeyArray();
int size = keys.length;
+
+ Serializable key;
+ ICacheElement cacheElement;
+ IElementAttributes attributes;
+
for ( int i = 0; i < size; i++ )
{
+ key = ( Serializable ) keys[ i ];
+ cacheElement = cache.getQuiet( key );
- Serializable key = ( Serializable ) keys[i];
- ICacheElement ce = cache.getQuiet( key );
-
- if ( ce != null )
+ if ( cacheElement == null )
{
+ continue;
+ }
- boolean ok = true;
-
- long now = System.currentTimeMillis();
+ attributes = cacheElement.getElementAttributes();
- if ( log.isDebugEnabled() )
- {
- log.debug( "now = " + now );
- log.debug( "!ce.getElementAttributes().getIsEternal() = " +
!ce.getElementAttributes().getIsEternal() );
- log.debug( "ce.getElementAttributes().getMaxLifeSeconds() =
" + ce.getElementAttributes().getMaxLifeSeconds() );
- log.debug( "now - ce.getElementAttributes().getCreateTime()
= " + String.valueOf( now - ce.getElementAttributes().getCreateTime() ) );
- log.debug( "ce.getElementAttributes().getMaxLifeSeconds() *
1000 = " + ce.getElementAttributes().getMaxLifeSeconds() * 1000 );
- }
+ boolean remove = false;
- ////////////////////////////////////////////////
- if ( !ce.getElementAttributes().getIsEternal() )
- {
- // Exceeded maxLifeSeconds
- if ( ( ce.getElementAttributes().getMaxLifeSeconds() != -1
) && ( now - ce.getElementAttributes().getCreateTime() ) > (
ce.getElementAttributes().getMaxLifeSeconds() * 1000 ) )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded maxLifeSeconds -- " +
ce.getKey() );
- }
-
- // handle event, might move to a new method
- ArrayList eventHandlers =
ce.getElementAttributes().getElementEventHandlers();
- if ( eventHandlers != null )
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "Handlers are registered. Event --
ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND" );
- }
- IElementEvent event = new ElementEvent( ce,
IElementEventConstants.ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND );
- Iterator hIt = eventHandlers.iterator();
- while ( hIt.hasNext() )
- {
- IElementEventHandler hand = (
IElementEventHandler ) hIt.next();
- //hand.handleElementEvent( event );
- cache.getCompositeCache().addElementEvent(
hand, event );
- }
- }
+ long now = System.currentTimeMillis();
- ok = false;
- cache.remove( ce.getKey() );
- }
- else
- // Exceeded maxIdleTime, removal
- if ( ( ce.getElementAttributes().getIdleTime() != -1 )
&& ( now - ce.getElementAttributes().getLastAccessTime() ) > (
ce.getElementAttributes().getIdleTime() * 1000 ) )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded maxIdleTime [
ce.getElementAttributes().getIdleTime() = " + ce.getElementAttributes().getIdleTime()
+ " ]-- " + ce.getKey() );
- }
-
- // handle event, might move to a new method
- ArrayList eventHandlers =
ce.getElementAttributes().getElementEventHandlers();
- if ( eventHandlers != null )
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "Handlers are registered. Event --
ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND" );
- }
- IElementEvent event = new ElementEvent( ce,
IElementEventConstants.ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND );
- Iterator hIt = eventHandlers.iterator();
- while ( hIt.hasNext() )
- {
- IElementEventHandler hand = (
IElementEventHandler ) hIt.next();
- //hand.handleElementEvent( event );
- cache.getCompositeCache().addElementEvent(
hand, event );
- }
- }
+ // Useful, but overkill even for DEBUG since it is written for
+ // every element in memory
+ //
+ // if ( log.isDebugEnabled() )
+ // {
+ // log.debug( "IsEternal: " + attributes.getIsEternal() );
+ // log.debug( "MaxLifeSeconds: "
+ // + attributes.getMaxLifeSeconds() );
+ // log.debug( "CreateTime:" + attributes.getCreateTime() );
+ // }
- ok = false;
- cache.remove( ce.getKey() );
- }
+ // If the element is not eternal, check if it should be
+ // removed and remove it if so.
- }// end if not eternal
+ if ( !cacheElement.getElementAttributes().getIsEternal() )
+ {
+ remove = checkForRemoval( cacheElement, now );
- // This should be last, since we wouldn't want to wast time
- // spooling if the item is removed.
- // Memory idle, to disk shrinkage
- if ( ok && (
cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds() != -1 ) )
+ if ( remove )
{
- long deadAt = ce.getElementAttributes().getLastAccessTime()
+ ( cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds() * 1000 );
- if ( ( deadAt - now ) < 0 )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded memory idle time, Pushing item
to disk -- " + ce.getKey() + " over by = " + String.valueOf( deadAt - now ) + " ms." );
- }
+ cache.remove( cacheElement.getKey() );
+ }
+ }
- cache.remove( ce.getKey() );
+ // If the item is not removed, check is it has been idle
+ // long enough to be spooled.
- cache.waterfal( ce );
+ if ( !remove && ( maxMemoryIdleTime != -1 ) )
+ {
+ final long lastAccessTime = attributes.getLastAccessTime();
+
+ if ( lastAccessTime + maxMemoryIdleTime < now )
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "Exceeded memory idle time: "
+ + cacheElement.getKey() );
}
- }
- }// end if ce != null
+ // FIXME: Shouldn't we ensure that the element is
+ // spooled before removing it from memory?
+
+ cache.remove( cacheElement.getKey() );
- }// end for
+ cache.waterfal( cacheElement );
+ }
+ }
+ }
}
catch ( Throwable t )
{
@@ -285,4 +272,91 @@
}
+ /**
+ * Check if either lifetime or idletime has expired for the provided event,
+ * and remove it from the cache if so.
+ *
+ * @param cacheElement Element to check for expiration
+ * @param now Time to consider expirations relative to
+ * @return true if the element should be removed, or false.
+ * @throws IOException
+ */
+ private boolean checkForRemoval( ICacheElement cacheElement, long now )
+ throws IOException
+ {
+ IElementAttributes attributes = cacheElement.getElementAttributes();
+
+ final long maxLifeSeconds = attributes.getMaxLifeSeconds();
+ final long createTime = attributes.getCreateTime();
+
+ // Check if maxLifeSeconds has been exceeded
+ if ( maxLifeSeconds != -1 && now - createTime > maxLifeSeconds * 1000 )
+ {
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Exceeded maxLifeSeconds: " + cacheElement.getKey() );
+ }
+
+ handleElementEvents( cacheElement, IElementEventConstants
+ .ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND );
+
+ return true;
+ }
+
+ final long idleTime = attributes.getIdleTime();
+ final long lastAccessTime = attributes.getLastAccessTime();
+
+ // Check maxIdleTime has been exceeded
+ if ( idleTime != -1 && now - lastAccessTime > idleTime * 1000 )
+ {
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Exceeded maxIdleTime " + cacheElement.getKey() );
+ }
+
+ handleElementEvents( cacheElement, IElementEventConstants
+ .ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND );
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Handle any events registered for the given element of the given event
+ * type.
+ *
+ * @param cacheElement Element to handle events for
+ * @param eventType Type of event to handle
+ * @throws IOException If an error occurs
+ */
+ private void handleElementEvents( ICacheElement cacheElement,
+ int eventType )
+ throws IOException
+ {
+ IElementAttributes attributes = cacheElement.getElementAttributes();
+
+ ArrayList eventHandlers = attributes.getElementEventHandlers();
+
+ if ( eventHandlers != null )
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "Handlers are registered, type: " + eventType );
+ }
+
+ IElementEvent event = new ElementEvent( cacheElement, eventType );
+
+ Iterator handlerIter = eventHandlers.iterator();
+
+ while ( handlerIter.hasNext() )
+ {
+ IElementEventHandler hand =
+ ( IElementEventHandler ) handlerIter.next();
+
+ cache.getCompositeCache().addElementEvent( hand, event );
+ }
+ }
+ }
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>