asmuts 02/05/13 09:25:42
Modified: src/java/org/apache/jcs/engine/memory/behavior
IMemoryCache.java
src/java/org/apache/jcs/engine/memory/lru
LRUMemoryCache.java
src/java/org/apache/jcs/engine/memory MemoryCache.java
src/java/org/apache/jcs/engine/memory/mru
MRUMemoryCache.java
src/java/org/apache/jcs/engine/memory/shrinking
ShrinkerThread.java
Log:
Modified and tested shrinking.
The concurrent modification exceptions were eating memory.
The shrinker was also removing items via the iterator, but the linked list still
held references to them.
I reduced the chance of the exceptions, but there is still a race condition in the
creation of the Array of keys.
The removals and gets go through the memory cache now.
We need to get rid of the MemoryCache interface and use the IMemoryCache interface.
There is a small memory usage by the shrinker, but the garbage collector is
reclaiming it successfully.
I don't think there are any more memory leaks. I'll test some more and then clean
up.
Revision Changes Path
1.3 +16 -2
jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/behavior/IMemoryCache.java
Index: IMemoryCache.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/behavior/IMemoryCache.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- IMemoryCache.java 8 Apr 2002 14:27:37 -0000 1.2
+++ IMemoryCache.java 13 May 2002 16:25:41 -0000 1.3
@@ -53,6 +53,13 @@
public Iterator getIterator();
+ /**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return An Object[]
+ */
+ public Object[] getKeyArray();
+
/** Removes an item from the cache. */
public boolean remove( Serializable key )
throws IOException;
@@ -67,14 +74,21 @@
public Serializable get( Serializable key )
throws IOException;
+ /** Get an item from the cache without effecting its order or last access time
*/
+ public ICacheElement getQuiet( Serializable key )
+ throws IOException;
+
/** Description of the Method */
public Serializable get( Serializable key, boolean container )
throws IOException;
- /** Puts an item to the cache. */
- public void waterfal( MemoryElementDescriptor me )
+ /** Throws an item out of memory, if there is a disk cache it will be spooled.
*/
+// public void waterfal( MemoryElementDescriptor me )
+// throws IOException;
+
+ public void waterfal( ICacheElement ce )
throws IOException;
1.6 +68 -3
jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java
Index: LRUMemoryCache.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/lru/LRUMemoryCache.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- LRUMemoryCache.java 13 Apr 2002 04:01:33 -0000 1.5
+++ LRUMemoryCache.java 13 May 2002 16:25:42 -0000 1.6
@@ -32,7 +32,7 @@
*
* @author <a href="mailto:[EMAIL PROTECTED]">Aaron Smuts</a>
* @author <a href="mailto:[EMAIL PROTECTED]">James Taylor</a>
- * @version $Id: LRUMemoryCache.java,v 1.5 2002/04/13 04:01:33 jtaylor Exp $
+ * @version $Id: LRUMemoryCache.java,v 1.6 2002/05/13 16:25:42 asmuts Exp $
*/
public class LRUMemoryCache implements MemoryCache, Serializable
{
@@ -179,6 +179,51 @@
}
}
+
+ /**
+ * Get an item from the cache without affecting its last access
+ * time or position.
+ *
+ * @return Element mathinh key if found, or null
+ * @param key Identifies item to find
+ * @exception IOException
+ */
+ public ICacheElement getQuiet( Serializable key )
+ throws IOException
+ {
+ MemoryElementDescriptor me = null;
+ ICacheElement ce = null;
+
+ try
+ {
+
+ me = ( MemoryElementDescriptor ) map.get( key );
+ if ( me != null )
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( cacheName + ": LRUMemoryCache quiet hit for " + key );
+ }
+
+ ce = me.ce;
+
+ }
+ else
+ {
+ log.debug( cacheName + ": LRUMemoryCache quiet miss for " + key );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+
+ return ce;
+
+
+ }
+
/**
* Get an item from the cache
*
@@ -345,17 +390,37 @@
return map.entrySet().iterator();
}
+
+ /**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return An Object[]
+ */
+ public Object[] getKeyArray()
+ {
+ // may need to lock to map here?
+ return map.keySet().toArray();
+ }
+
+
/**
* Puts an item to the cache.
*
* @param me
* @exception IOException
*/
- public void waterfal( MemoryElementDescriptor me )
+// public void waterfal( MemoryElementDescriptor me )
+// throws IOException
+// {
+// this.cache.spoolToDisk( me.ce );
+// }
+ public void waterfal( ICacheElement ce )
throws IOException
{
- this.cache.spoolToDisk( me.ce );
+ this.cache.spoolToDisk( ce );
}
+
+
/**
* Returns the CacheAttributes.
1.3 +21 -2
jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/MemoryCache.java
Index: MemoryCache.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/MemoryCache.java,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- MemoryCache.java 9 Apr 2002 00:32:45 -0000 1.2
+++ MemoryCache.java 13 May 2002 16:25:42 -0000 1.3
@@ -11,9 +11,12 @@
/**
* For the framework. Insures methods a MemoryCache needs to access.
*
+ * Not sure why we use this. Should use teh IMemeoryCache interface.
+ * I'll change it later.
+ *
* @author <a href="mailto:[EMAIL PROTECTED]">Aaron Smuts</a>
* @author <a href="mailto:[EMAIL PROTECTED]">James Taylor</a>
- * @version $Id: MemoryCache.java,v 1.2 2002/04/09 00:32:45 jtaylor Exp $
+ * @version $Id: MemoryCache.java,v 1.3 2002/05/13 16:25:42 asmuts Exp $
*/
public interface MemoryCache
{
@@ -38,6 +41,14 @@
*/
public Iterator getIterator();
+
+ /**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return Object[]
+ */
+ public Object[] getKeyArray();
+
/**
* Removes an item from the cache
*
@@ -54,9 +65,17 @@
public ICacheElement get( Serializable key )
throws IOException;
+ /** Get an item from the cache without effecting its order or last access time
*/
+ public ICacheElement getQuiet( Serializable key )
+ throws IOException;
+
/** Spools the item contained in the provided element to disk */
- public void waterfal( MemoryElementDescriptor me )
+// public void waterfal( MemoryElementDescriptor me )
+// throws IOException;
+
+ public void waterfal( ICacheElement ce )
throws IOException;
+
/** Puts an item to the cache. */
public void update( ICacheElement ce ) throws IOException;
1.4 +64 -3
jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java
Index: MRUMemoryCache.java
===================================================================
RCS file:
/home/cvs/jakarta-turbine-jcs/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MRUMemoryCache.java 8 Apr 2002 22:58:15 -0000 1.3
+++ MRUMemoryCache.java 13 May 2002 16:25:42 -0000 1.4
@@ -26,7 +26,7 @@
*
* @author <a href="mailto:[EMAIL PROTECTED]">Aaron Smuts</a>
* @author <a href="mailto:[EMAIL PROTECTED]">James Taylor</a>
- * @version $Id: MRUMemoryCache.java,v 1.3 2002/04/08 22:58:15 jtaylor Exp $
+ * @version $Id: MRUMemoryCache.java,v 1.4 2002/05/13 16:25:42 asmuts Exp $
*/
public class MRUMemoryCache
implements MemoryCache, Serializable
@@ -197,6 +197,50 @@
}
+
+
+ /**
+ * Get an item from the cache without affecting its last access
+ * time or position.
+ *
+ * @return Element mathinh key if found, or null
+ * @param key Identifies item to find
+ * @exception IOException
+ */
+ public ICacheElement getQuiet( Serializable key )
+ throws IOException
+ {
+
+ ICacheElement ce = null;
+
+ try
+ {
+
+ ce = ( ICacheElement ) map.get( key );
+ if ( ce != null )
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( cacheName + ": MRUMemoryCache quiet hit for " + key );
+ }
+
+ }
+ else
+ {
+ log.debug( cacheName + ": MRUMemoryCache quiet miss for " + key );
+ }
+
+ }
+ catch ( Exception e )
+ {
+ log.error( e );
+ }
+
+ return ce;
+
+ }
+
+
/**
* Description of the Method
*
@@ -414,10 +458,15 @@
* @param me
* @exception IOException
*/
- public void waterfal( MemoryElementDescriptor me )
+// public void waterfal( MemoryElementDescriptor me )
+// throws IOException
+// {
+// this.cache.spoolToDisk( me.ce );
+// }
+ public void waterfal( ICacheElement ce )
throws IOException
{
- this.cache.spoolToDisk( me.ce );
+ this.cache.spoolToDisk( ce );
}
/**
@@ -429,6 +478,18 @@
{
//return Collections.enumeration(map.entrySet());
return map.entrySet().iterator();
+ }
+
+
+ /**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return Object[]
+ */
+ public Object[] getKeyArray()
+ {
+ // may need to lock to map here?
+ return map.keySet().toArray();
}
/**
1.5 +135 -94
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.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- ShrinkerThread.java 9 May 2002 21:47:11 -0000 1.4
+++ ShrinkerThread.java 13 May 2002 16:25:42 -0000 1.5
@@ -56,6 +56,7 @@
import java.util.Map;
import java.util.ArrayList;
import java.util.Iterator;
+import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -66,6 +67,7 @@
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;
/**
* A background memory shrinker. Just started. <u>DON'T USE</u>
@@ -142,108 +144,147 @@
try
{
- java.util.Iterator itr = cache.getIterator();
- while ( itr.hasNext() )
- {
- Map.Entry e = ( Map.Entry ) itr.next();
- MemoryElementDescriptor me = ( MemoryElementDescriptor )
e.getValue();
+/////////////////////////////////////
- long now = System.currentTimeMillis();
- if ( log.isDebugEnabled() )
- {
- log.debug( "now = " + now );
- log.debug( "!me.ce.getElementAttributes().getIsEternal() = " +
!me.ce.getElementAttributes().getIsEternal() );
- log.debug( "me.ce.getElementAttributes().getMaxLifeSeconds() =
" + me.ce.getElementAttributes().getMaxLifeSeconds() );
- log.debug( "now - me.ce.getElementAttributes().getCreateTime()
= " + String.valueOf( now - me.ce.getElementAttributes().getCreateTime() ) );
- log.debug( "me.ce.getElementAttributes().getMaxLifeSeconds() *
1000 = " + me.ce.getElementAttributes().getMaxLifeSeconds() * 1000 );
- }
+ // creation of the iterator without any change to
+ // the underlying collection does not result in
+ // increased memory uage
+// java.util.Iterator itr = cache.getIterator();
+//
+// while ( itr.hasNext() )
+// {
+// Map.Entry e = ( Map.Entry ) itr.next();
+// MemoryElementDescriptor me = ( MemoryElementDescriptor )
e.getValue();
+// ICacheElement ce = me.ce;
- // Memory idle, to disk shrinkage
- if ( cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds() != -1
)
- {
- long deadAt = me.ce.getElementAttributes().getLastAccessTime()
+ ( cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds() * 1000 );
- if ( ( deadAt - now ) < 0 )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded memory idle time, Pushing item to
disk -- " + me.ce.getKey() + " over by = " + String.valueOf( deadAt - now ) + " ms." );
- }
- itr.remove();
- cache.waterfal( me );
- }
- }
+///////////////////////////////////////
+
+
+ Object[] keys = cache.getKeyArray();
+ int size = keys.length;
+ for ( int i=0; i < size; i++ ) {
+
+ Serializable key = (Serializable)keys[i];
+ ICacheElement ce = cache.getQuiet(key);
- if ( !me.ce.getElementAttributes().getIsEternal() )
+
+///////////////////////////////////////
+
+
+ if ( ce != null )
{
- // Exceeded maxLifeSeconds
- if ( ( me.ce.getElementAttributes().getMaxLifeSeconds() != -1 )
&& ( now - me.ce.getElementAttributes().getCreateTime() ) > (
me.ce.getElementAttributes().getMaxLifeSeconds() * 1000 ) )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded maxLifeSeconds -- " +
me.ce.getKey() );
- }
-
- // handle event, might move to a new method
- ArrayList eventHandlers =
me.ce.getElementAttributes().getElementEventHandlers();
- if ( eventHandlers != null )
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "Handlers are registered. Event --
ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND" );
- }
- IElementEvent event = new ElementEvent( me.ce,
IElementEventConstants.ELEMENT_EVENT_EXCEEDED_MAXLIFE_BACKGROUND );
- Iterator hIt = eventHandlers.iterator();
- while ( hIt.hasNext() )
- {
- IElementEventHandler hand = ( IElementEventHandler
) hIt.next();
- hand.handleElementEvent( event );
- }
- }
-
- itr.remove();
- // TODO: this needs to go through the remove chanel
- // since an old copy could be on disk and we may want
- // to clean up the other caches.
- // probably need to call both
- //cache.remove( me.ce.getKey() );
- }
- else
- // Exceeded maxIdleTime, removal
- if ( ( me.ce.getElementAttributes().getIdleTime() != -1 )
&& ( now - me.ce.getElementAttributes().getLastAccessTime() ) > (
me.ce.getElementAttributes().getIdleTime() * 1000 ) )
- {
- if ( log.isInfoEnabled() )
- {
- log.info( "Exceeded maxIdleTime [
me.ce.getElementAttributes().getIdleTime() = " +
me.ce.getElementAttributes().getIdleTime() + " ]-- " + me.ce.getKey() );
- }
-
- // handle event, might move to a new method
- ArrayList eventHandlers =
me.ce.getElementAttributes().getElementEventHandlers();
- if ( eventHandlers != null )
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "Handlers are registered. Event --
ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND" );
- }
- IElementEvent event = new ElementEvent( me.ce,
IElementEventConstants.ELEMENT_EVENT_EXCEEDED_IDLETIME_BACKGROUND );
- Iterator hIt = eventHandlers.iterator();
- while ( hIt.hasNext() )
- {
- IElementEventHandler hand = ( IElementEventHandler
) hIt.next();
- hand.handleElementEvent( event );
- }
- }
-
- itr.remove();
-
- //cache.remove( me.ce.getKey() );
- }
- }
- }
+ long now = System.currentTimeMillis();
+
+ 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 );
+ }
+
+ // Memory idle, to disk shrinkage
+ if ( cache.getCacheAttributes().getMaxMemoryIdleTimeSeconds() !=
-1 )
+ {
+ 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." );
+ }
+ //itr.remove();
+ cache.remove( ce.getKey() );
+
+ cache.waterfal( ce );
+ }
+ }
+
+ 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 );
+ }
+ }
+
+ //itr.remove();
+ // TODO: this needs to go through the remove chanel
+ // since an old copy could be on disk and we may want
+ // to clean up the other caches.
+ // probably need to call both
+ 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 );
+ }
+ }
+
+ //itr.remove();
+
+ cache.remove( ce.getKey() );
+ }
+ }
+
+ } // end if ce != null
+
+/////////////////////////////////////
+
+
+ }
+
+
+////////////////////////////////////
+
+// }
+//
+// itr = null;
- itr = null;
+////////////////////////////////////
}
catch ( Throwable t )
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>