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]>

Reply via email to