Author: asmuts
Date: Fri Feb 17 14:33:31 2006
New Revision: 378644
URL: http://svn.apache.org/viewcvs?rev=378644&view=rev
Log:
added additional tests for the test mru impl and removed unused classes
Removed:
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/Attributes.java
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/behavior/IAttributes.java
Modified:
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/CacheEventQueue.java
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java
jakarta/jcs/trunk/xdocs/IndexedDiskAuxCache.xml
jakarta/jcs/trunk/xdocs/JCSvsEHCache.xml
Modified: jakarta/jcs/trunk/src/java/org/apache/jcs/engine/CacheEventQueue.java
URL:
http://svn.apache.org/viewcvs/jakarta/jcs/trunk/src/java/org/apache/jcs/engine/CacheEventQueue.java?rev=378644&r1=378643&r2=378644&view=diff
==============================================================================
--- jakarta/jcs/trunk/src/java/org/apache/jcs/engine/CacheEventQueue.java
(original)
+++ jakarta/jcs/trunk/src/java/org/apache/jcs/engine/CacheEventQueue.java Fri
Feb 17 14:33:31 2006
@@ -39,8 +39,6 @@
* for a specified period, now set to 1 minute. If something comes in after
that
* a new processor thread should be created.
*
- * I didn't get all of Hanson's changes in yet, but I did add the
- * syncronization.
*/
public class CacheEventQueue
implements ICacheEventQueue
@@ -50,12 +48,14 @@
private static final int queueType = SINGLE_QUEUE_TYPE;
private static final int DEFAULT_WAIT_TO_DIE_MILLIS = 10000;
-
+
// time to wait for an event before snuffing the background thread
// if the queue is empty.
// make configurable later
private int waitToDieMillis = DEFAULT_WAIT_TO_DIE_MILLIS;
+ // When the events are pulled off the queue, the tell the listener to
handle
+ // the specific event type. The work is done by the listener.
private ICacheListener listener;
private long listenerId;
@@ -67,16 +67,23 @@
// in milliseconds
private int waitBeforeRetry;
+ // this is true if there is no worker thread.
private boolean destroyed = true;
+ // This means that the queue is functional.
+ // If we reached the max number of failures, the queue is marked as
+ // non functional and will never work again.
private boolean working = true;
+ // the thread that works the queue.
private Thread processorThread;
private Object queueLock = new Object();
+ // the head of the queue
private Node head = new Node();
+ // the end of the queue
private Node tail = head;
/**
@@ -136,10 +143,8 @@
*/
public synchronized void stopProcessing()
{
-
destroyed = true;
processorThread = null;
-
}
/**
@@ -172,6 +177,8 @@
}
/**
+ * If they queue has an active thread it is considered alive.
+ *
* @return The alive value
*/
public boolean isAlive()
@@ -191,7 +198,7 @@
}
/**
- * @return The {3} value
+ * @return The listenerId value
*/
public long getListenerId()
{
@@ -200,6 +207,8 @@
/**
* Event Q is emtpy.
+ *
+ * Calling destroy interupts the processor thread.
*/
public synchronized void destroy()
{
@@ -281,6 +290,9 @@
}
/**
+ * This adds a remove all event to the queue. When it is processed, all
+ * elements will be removed from the cache.
+ *
* @exception IOException
*/
public synchronized void addRemoveAllEvent()
@@ -357,9 +369,15 @@
/**
* Returns the next cache event from the queue or null if there are no
* events in the queue.
+ * <p>
+ * We have an empty node at the head and the tail. When we take an item
from
+ * the queue we move the next node to the head and then clear the value
from
+ * that node. This value is returned.
+ * <p>
+ * When the queue is empty the head node is the same as the tail node.
*
* @return An event to process.
- *
+ *
*/
private AbstractCacheEvent take()
{
@@ -450,7 +468,7 @@
return stats;
}
- ///////////////////////////// Inner classes /////////////////////////////
+ // /////////////////////////// Inner classes /////////////////////////////
private static class Node
{
@@ -460,6 +478,8 @@
}
/**
+ * This is the thread that works the queue.
+ *
* @author asmuts
* @created January 15, 2002
*/
@@ -491,18 +511,18 @@
*/
public void run()
{
- AbstractCacheEvent r = null;
+ AbstractCacheEvent event = null;
while ( queue.isAlive() )
{
- r = queue.take();
+ event = queue.take();
if ( log.isDebugEnabled() )
{
- log.debug( "Event from queue = " + r );
+ log.debug( "Event from queue = " + event );
}
- if ( r == null )
+ if ( event == null )
{
synchronized ( queueLock )
{
@@ -515,21 +535,21 @@
log.warn( "Interrupted while waiting for another
event to come in before we die." );
return;
}
- r = queue.take();
+ event = queue.take();
if ( log.isDebugEnabled() )
{
- log.debug( "Event from queue after sleep = " + r );
+ log.debug( "Event from queue after sleep = " +
event );
}
}
- if ( r == null )
+ if ( event == null )
{
queue.stopProcessing();
}
}
- if ( queue.isWorking() && queue.isAlive() && r != null )
+ if ( queue.isWorking() && queue.isAlive() && event != null )
{
- r.run();
+ event.run();
}
}
if ( log.isInfoEnabled() )
@@ -593,6 +613,8 @@
{
log.warn( "Interrupted while sleeping for retry on
event " + this + "." );
}
+ // TODO consider if this is best. maybe we shoudl just
+ // destroy
setWorking( false );
setAlive( false );
}
@@ -607,6 +629,8 @@
}
/**
+ * An element should be put in the cache.
+ *
* @author asmuts
* @created January 15, 2002
*/
@@ -626,10 +650,6 @@
throws IOException
{
this.ice = ice;
- /*
- * this.key = key; this.obj = CacheUtils.dup(obj); this.attr =
attr;
- * this.groupName = groupName;
- */
}
/**
@@ -640,13 +660,12 @@
protected void doRun()
throws IOException
{
- /*
- * CacheElement ce = new CacheElement(cacheName, key, obj);
- * ce.setElementAttributes( attr ); ce.setGroupName( groupName );
- */
listener.handlePut( ice );
}
+ /**
+ * For debugging.
+ */
public String toString()
{
return new StringBuffer( "PutEvent for key: " ).append(
ice.getKey() ).append( " value: " )
@@ -656,7 +675,7 @@
}
/**
- * Description of the Class
+ * An element should be removed from the cache.
*
* @author asmuts
* @created January 15, 2002
@@ -702,7 +721,8 @@
}
/**
- * Description of the Class
+ * All elements should be removed from the cache when this event is
+ * processed.
*
* @author asmuts
* @created January 15, 2002
@@ -735,7 +755,7 @@
}
/**
- * Description of the Class
+ * The cache should be disposed when this event is processed.
*
* @author asmuts
* @created January 15, 2002
@@ -770,6 +790,10 @@
}
/**
+ * This means that the queue is functional. If we reached the max number of
+ * failures, the queue is marked as non functional and will never work
+ * again.
+ *
* @param b
*/
public void setWorking( boolean b )
Modified:
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java
URL:
http://svn.apache.org/viewcvs/jakarta/jcs/trunk/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java?rev=378644&r1=378643&r2=378644&view=diff
==============================================================================
---
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java
(original)
+++
jakarta/jcs/trunk/src/java/org/apache/jcs/engine/memory/mru/MRUMemoryCache.java
Fri Feb 17 14:33:31 2006
@@ -38,11 +38,13 @@
import org.apache.jcs.engine.stats.behavior.IStats;
/**
- * A SLOW AS HELL reference management system. The most recently used items
move
+ * A SLOW reference management system. The most recently used items move
* to the front of the list and get spooled to disk if the cache hub is
* configured to use a disk cache.
+ * <p>
+ * This class is mainly for testing the hub. It also shows that use the
+ * Collection LinkedList is far slower than JCS' own double linked list.
*
- * @version $Id$
*/
public class MRUMemoryCache
extends AbstractMemoryCache
@@ -75,7 +77,7 @@
public synchronized void initialize( CompositeCache hub )
{
super.initialize( hub );
- log.info( "initialized MRUMemoryCache for " + cacheName );
+ log.info( "Initialized MRUMemoryCache for " + cacheName );
}
/**
@@ -118,13 +120,16 @@
}
// SPOOL LAST -- need to make this a grouping in a queue
- log.debug( "In RAM overflow" );
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "In RAM overflow" );
+ }
// write the last item to disk.
try
{
-
- // PUSH 5 TO DISK TO MINIMIZE THE TYPICAL
+ // PUSH more than 1 TO DISK TO MINIMIZE THE TYPICAL spool at each
+ // put.
int chunkSizeCorrected = Math.min( size, chunkSize );
if ( log.isDebugEnabled() )
@@ -139,18 +144,19 @@
// and wouldn't save much time in this synchronous call.
for ( int i = 0; i < chunkSizeCorrected; i++ )
{
- // Might want to rename this "overflow" incase the hub
- // wants to do something else.
- Serializable last = (Serializable) mrulist.getLast();
- ICacheElement ceL = (ICacheElement) map.get( last );
- cache.spoolToDisk( ceL );
+ ICacheElement toSpool = null;
+
// need a more fine grained locking here
- synchronized ( map )
+ synchronized ( lockMe )
{
+ Serializable last = (Serializable) mrulist.removeLast();
+ toSpool = (ICacheElement) map.get( last );
map.remove( last );
- mrulist.remove( last );
}
+ // Might want to rename this "overflow" incase the hub
+ // wants to do something else.
+ cache.spoolToDisk( toSpool );
}
if ( log.isDebugEnabled() )
@@ -163,7 +169,7 @@
catch ( Exception ex )
{
// impossible case.
- ex.printStackTrace();
+ log.error( "Problem updating MRU.", ex );
throw new IllegalStateException( ex.getMessage() );
}
}
@@ -184,7 +190,6 @@
try
{
-
ce = (ICacheElement) map.get( key );
if ( ce != null )
{
@@ -192,24 +197,24 @@
{
log.debug( cacheName + ": MRUMemoryCache quiet hit for " +
key );
}
-
}
else
{
log.debug( cacheName + ": MRUMemoryCache quiet miss for " +
key );
}
-
}
catch ( Exception e )
{
- log.error( e );
+ log.error( "Problem getting quietly from MRU.", e );
}
return ce;
}
+
/**
- * Description of the Method
+ * Gets an item out of the map. If it finds an item, it is removed from the
+ * list and then added to the first position in the linked list.
*
* @return
* @param key
@@ -223,7 +228,6 @@
try
{
-
if ( log.isDebugEnabled() )
{
log.debug( "get> key=" + key );
@@ -246,11 +250,10 @@
log.debug( cacheName + " -- RAM-HIT for " + key );
}
}
-
}
catch ( Exception e )
{
- log.error( e );
+ log.error( "Problem getting element.", e );
}
try
@@ -289,8 +292,6 @@
return ce;
}
- // end get
-
/**
* Removes an item from the cache.
*
@@ -304,17 +305,15 @@
if ( log.isDebugEnabled() )
{
log.debug( "remove> key=" + key );
- //+, nonLocal="+nonLocal);
}
- //p("remove> key="+key+", nonLocal="+nonLocal);
boolean removed = false;
// handle partial removal
if ( key instanceof String && key.toString().endsWith(
CacheConstants.NAME_COMPONENT_DELIMITER ) )
{
// remove all keys of the same name hierarchy.
- synchronized ( map )
+ synchronized ( lockMe )
{
for ( Iterator itr = map.entrySet().iterator(); itr.hasNext();
)
{
@@ -323,8 +322,8 @@
if ( k instanceof String && k.toString().startsWith(
key.toString() ) )
{
itr.remove();
- Serializable keyR = (ICacheElement) entry.getKey();
- map.remove( keyR );
+ Serializable keyR = (Serializable) entry.getKey();
+ //map.remove( keyR );
mrulist.remove( keyR );
removed = true;
}
@@ -334,7 +333,7 @@
else if ( key instanceof GroupId )
{
// remove all keys of the same name hierarchy.
- synchronized ( map )
+ synchronized ( lockMe )
{
for ( Iterator itr = map.entrySet().iterator(); itr.hasNext();
)
{
@@ -357,7 +356,6 @@
{
synchronized ( lockMe )
{
-
map.remove( key );
mrulist.remove( key );
}
@@ -375,9 +373,9 @@
*/
public Object[] getKeyArray()
{
+ // need to lock to map here?
synchronized ( lockMe )
{
- // may need to lock to map here?
return map.keySet().toArray();
}
}
@@ -390,7 +388,7 @@
log.debug( "dumpingMap" );
for ( Iterator itr = map.entrySet().iterator(); itr.hasNext(); )
{
- //for ( Iterator itr = memCache.getIterator(); itr.hasNext();) {
+ // for ( Iterator itr = memCache.getIterator(); itr.hasNext();) {
Map.Entry e = (Map.Entry) itr.next();
ICacheElement ce = (ICacheElement) e.getValue();
log.debug( "dumpMap> key=" + e.getKey() + ", val=" + ce.getVal() );
Modified: jakarta/jcs/trunk/xdocs/IndexedDiskAuxCache.xml
URL:
http://svn.apache.org/viewcvs/jakarta/jcs/trunk/xdocs/IndexedDiskAuxCache.xml?rev=378644&r1=378643&r2=378644&view=diff
==============================================================================
--- jakarta/jcs/trunk/xdocs/IndexedDiskAuxCache.xml (original)
+++ jakarta/jcs/trunk/xdocs/IndexedDiskAuxCache.xml Fri Feb 17 14:33:31 2006
@@ -1,141 +1,174 @@
<?xml version="1.0"?>
<document>
- <properties>
- <title>Indexed Disk Auxiliary Cache</title>
- <author email="[EMAIL PROTECTED]">Aaron Smuts</author>
- </properties>
-
- <body>
- <section name="Indexed Disk Auxiliary Cache">
- <p>
- The Indexed Disk Auxiliary Cache is an optional plugin for the
- JCS. It is primarily intended to provide a secondary store to
- ease the memory burden of the cache. When the memory cache
- exceeds its maximum size it tells the cache hub that the item
- to be removed from memory should be spooled to disk. The cache
- checks to see if any auxiliaries of type "disk" have been
- configured for the region. If the "Indexed Disk Auxiliary Cache"
- is used, the item will be spooled to disk.
- </p>
-
- <subsection name="Disk Indexing">
- <p>
- The Indexed Disk Auxiliary Cache follows the fastest
- pattern of disk caching. Items are stored at the end of a file
- dedicated to the cache region. The first byte of each disk entry
- specifies the length of the entry. The start position in the file
- is saved in memory, referenced by the item's key. Though this
still
- requires memory, it is insignificant given the performance trade
- off. Depending on the key size, 500,000 disk entries will
probably
- only require about 1 MB of memory. Locating the position of an
item is
- as fast as a map lookup and the retrieval of the item only
requires 2
- disk accesses.
- </p>
- <p>
- When items are removed from the disk cache, the location of the
available
- block on the storage file is recorded in a sorted preferential array
of a
- size not to exceed the maximum number of keys allowed in memory.
This allows
- the disk cache to reuse empty spots, thereby keeping the file size to
a
- minimum.
- </p>
- </subsection>
-
- <subsection name="Purgatory">
- <p>
- Writing to the disk cache is asynchronous and made efficient by
using a
- memory staging area called purgatory. Retrievals check purgatory then
- disk for an item. When items are sent to purgatory they are
simultaneously
- queued to be put to disk. If an item is retrieved from purgatory it
will no
- longer be written to disk, since the cache hub will move it back to
memory.
- Using purgatory insures that there is no wait for disk writes,
unecessary
- disk writes are avoided for borderline items, and the items are always
- available.
- </p>
- </subsection>
-
- <subsection name="Persistence">
- <p>
- When the disk cache is properly shutdown, the memory index is
written
- to disk and the value file is defragmented. When the cache starts
- up, the disk cache can be configured to read or delete the index file.
This
- provides an unreliable persistence mechanism.
- </p>
- </subsection>
-
- <subsection name="Configuration">
- <p>
- The simple configuration and is done in the auxiliary
- cache section of the <code>cache.ccf</code> configuration file.
- In the example below, I created an Indexed Disk Auxiliary Cache
- referenced by <code>DC</code>. It uses files located in the
- "DiskPath" directory.
- </p>
- <p>
- The Disk indexes are equipped with an LRU storage limit. The
maximum
- number of keys is configured by the maxKeySize parameter. If the
- maximum key size is less than 0, no limit will be placed on the
- number of keys. By default, the max key size is 5000.
- </p>
- <source><![CDATA[
+ <properties>
+ <title>Indexed Disk Auxiliary Cache</title>
+ <author email="[EMAIL PROTECTED]">Aaron Smuts</author>
+ </properties>
+
+ <body>
+ <section name="Indexed Disk Auxiliary Cache">
+ <p>
+ The Indexed Disk Auxiliary Cache is an optional
plugin
+ for the JCS. It is primarily intended to
provide a
+ secondary store to ease the memory burden of
the cache.
+ When the memory cache exceeds its maximum size
it tells
+ the cache hub that the item to be removed from
memory
+ should be spooled to disk. The cache checks to
see if
+ any auxiliaries of type "disk" have been
configured for
+ the region. If the "Indexed Disk Auxiliary
Cache" is
+ used, the item will be spooled to disk.
+ </p>
+
+ <subsection name="Disk Indexing">
+ <p>
+ The Indexed Disk Auxiliary Cache
follows the fastest
+ pattern of disk caching. Items are
stored at the end
+ of a file dedicated to the cache
region. The first
+ byte of each disk entry specifies the
length of the
+ entry. The start position in the file
is saved in
+ memory, referenced by the item's key.
Though this
+ still requires memory, it is
insignificant given the
+ performance trade off. Depending on the
key size,
+ 500,000 disk entries will probably only
require
+ about 1 MB of memory. Locating the
position of an
+ item is as fast as a map lookup and the
retrieval of
+ the item only requires 2 disk accesses.
+ </p>
+ <p>
+ When items are removed from the disk
cache, the
+ location of the available block on the
storage file
+ is recorded in a sorted preferential
array of a size
+ not to exceed the maximum number of
keys allowed in
+ memory. This allows the disk cache to
reuse empty
+ spots, thereby keeping the file size to
a minimum.
+ </p>
+ </subsection>
+
+ <subsection name="Purgatory">
+ <p>
+ Writing to the disk cache is
asynchronous and made
+ efficient by using a memory staging
area called
+ purgatory. Retrievals check purgatory
then disk for
+ an item. When items are sent to
purgatory they are
+ simultaneously queued to be put to
disk. If an item
+ is retrieved from purgatory it will no
longer be
+ written to disk, since the cache hub
will move it
+ back to memory. Using purgatory insures
that there
+ is no wait for disk writes, unecessary
disk writes
+ are avoided for borderline items, and
the items are
+ always available.
+ </p>
+ </subsection>
+
+ <subsection name="Persistence">
+ <p>
+ When the disk cache is properly
shutdown, the memory
+ index is written to disk and the value
file is
+ defragmented. When the cache starts up,
the disk
+ cache can be configured to read or
delete the index
+ file. This provides an unreliable
persistence
+ mechanism.
+ </p>
+ </subsection>
+
+ <subsection name="Configuration">
+ <p>
+ The simple configuration and is done in
the
+ auxiliary cache section of the
+ <code>cache.ccf</code>
+ configuration file. In the example
below, I created
+ an Indexed Disk Auxiliary Cache
referenced by
+ <code>DC</code>
+ . It uses files located in the
"DiskPath" directory.
+ </p>
+ <p>
+ The Disk indexes are equipped with an
LRU storage
+ limit. The maximum number of keys is
configured by
+ the maxKeySize parameter. If the
maximum key size is
+ less than 0, no limit will be placed on
the number
+ of keys. By default, the max key size
is 5000.
+ </p>
+ <source>
+ <![CDATA[
jcs.auxiliary.DC=
org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
jcs.auxiliary.DC.attributes=
org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=g:\dev\jakarta-turbine-stratum\raf
jcs.auxiliary.DC.attributes.MaxKeySize=100000
- ]]></source>
- </subsection>
+ ]]>
+ </source>
+ </subsection>
- <subsection name="Additional Configuration Options">
- <p>
- The indexed disk cache provides some additional configuration
options.
- </p>
- <p>
- The purgatory size of the Disk cache is equipped with an LRU
storage limit.
- The maximum number of elements allowed in purgatory is configured
by the
- MaxPurgatorySize parameter. By default, the max purgatory size is
5000.
- </p>
- <p>
- Initial testing indicates that the disk cache performs better when
the
- key and purgatory sizes are limited.
- </p>
- <source><![CDATA[
+ <subsection name="Additional Configuration Options">
+ <p>
+ The indexed disk cache provides some
additional
+ configuration options.
+ </p>
+ <p>
+ The purgatory size of the Disk cache is
equipped
+ with an LRU storage limit. The maximum
number of
+ elements allowed in purgatory is
configured by the
+ MaxPurgatorySize parameter. By default,
the max
+ purgatory size is 5000.
+ </p>
+ <p>
+ Initial testing indicates that the disk
cache
+ performs better when the key and
purgatory sizes are
+ limited.
+ </p>
+ <source>
+ <![CDATA[
jcs.auxiliary.DC.attributes.MaxPurgatorySize=10000
- ]]></source>
- <p>
- Slots in the data file become empty when items are removed from the
disk cache.
- The indexed disk cache keeps track of empty slots in the data file,
so they can
- be reused. The slot locations are stored in a sorted preferential
array --
- the recycle bin. The smallest items are removed from the recycle
bin when it
- reaches the specified limit. The MaxRecycleBinSize cannot be
larger than
- the MaxKeySize. If the MaxKeySize is less than 0, the recycle bin
will default
- to 5000.
- </p>
- <source><![CDATA[
+ ]]>
+ </source>
+ <p>
+ Slots in the data file become empty
when items are
+ removed from the disk cache. The
indexed disk cache
+ keeps track of empty slots in the data
file, so they
+ can be reused. The slot locations are
stored in a
+ sorted preferential array -- the
recycle bin. The
+ smallest items are removed from the
recycle bin when
+ it reaches the specified limit. The
+ MaxRecycleBinSize cannot be larger than
the
+ MaxKeySize. If the MaxKeySize is less
than 0, the
+ recycle bin will default to 5000.
+ </p>
+ <source>
+ <![CDATA[
jcs.auxiliary.DC.attributes.MaxRecycleBinSize=10000
- ]]></source>
- <p>
- The Disk cache can be configured to defragment the data file at
runtime. Since
- defragmentation is only necessary if items have been removed, the
deframentation
- interval is determined by the number of removes. Currently there
is no way
- to schedule defragmentation to run at a set time. If you set the
OptimizeAtRemoveCount
- to -1, no optimizations of the data file will occur until shutdown.
By default
- the value is -1.
- </p>
- <source><![CDATA[
+ ]]>
+ </source>
+ <p>
+ The Disk cache can be configured to
defragment the
+ data file at runtime. Since
defragmentation is only
+ necessary if items have been removed,
the
+ deframentation interval is determined
by the number
+ of removes. Currently there is no way
to schedule
+ defragmentation to run at a set time.
If you set the
+ OptimizeAtRemoveCount to -1, no
optimizations of the
+ data file will occur until shutdown. By
default the
+ value is -1.
+ </p>
+ <source>
+ <![CDATA[
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=30000
- ]]></source>
- </subsection>
+ ]]>
+ </source>
+ </subsection>
- <subsection name="A Complete Configuration Example">
- <p>
- In this sample cache.ccf file, I configured the cache to use a disk
cache,
- called DC, by default. Also, I explicitly set a cache region called
myRegion1
- to use DC. I specified custom settings for all of the Indexed Disk
Cache
- configuration parameters.
- </p>
- <source><![CDATA[
+ <subsection name="A Complete Configuration Example">
+ <p>
+ In this sample cache.ccf file, I
configured the
+ cache to use a disk cache, called DC,
by default.
+ Also, I explicitly set a cache region
called
+ myRegion1 to use DC. I specified custom
settings for
+ all of the Indexed Disk Cache
configuration
+ parameters.
+ </p>
+ <source>
+ <![CDATA[
##############################################################
##### Default Region Configuration
jcs.default=DC
@@ -160,15 +193,80 @@
jcs.auxiliary.DC.attributes.MaxKeySize=10000
jcs.auxiliary.DC.attributes.OptimizeAtRemoveCount=300000
jcs.auxiliary.DC.attributes.MaxRecycleBinSize=7500
- ]]></source>
- </subsection>
+ ]]>
+ </source>
+ </subsection>
+
+ <subsection name="Using Thread Pools to Reduce Threads">
+ <p>
+ The Indexed Disk Cache allows you to
use fewer
+ threads than active regions. By default
the disk
+ cache will use the standard cache event
queue which
+ has a dedicated thread. Although the
standard queue
+ kills its worker thread after a minute
of
+ inactivity, you may want to restrict
the total
+ number of threads. You can accomplish
this by using
+ a pooled event queue.
+ </p>
+ <p>
+ The configuration file below defines a
disk cache
+ called DC2. It uses an event queue of
type POOLED.
+ The queue is named
disk_cache_event_queue. The
+ disk_cache_event_queue is defined in
the bottom of
+ the file.
+ </p>
+ <source>
+ <![CDATA[
+##############################################################
+################## DEFAULT CACHE REGION #####################
+# sets the default aux value for any non configured caches
+jcs.default=DC2
+jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
+jcs.default.cacheattributes.MaxObjects=200001
+jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
+jcs.default.cacheattributes.UseMemoryShrinker=false
+jcs.default.cacheattributes.MaxMemoryIdleTimeSeconds=3600
+jcs.default.cacheattributes.ShrinkerIntervalSeconds=60
+jcs.default.elementattributes=org.apache.jcs.engine.ElementAttributes
+jcs.default.elementattributes.IsEternal=false
+jcs.default.elementattributes.MaxLifeSeconds=700
+jcs.default.elementattributes.IdleTime=1800
+jcs.default.elementattributes.IsSpool=true
+jcs.default.elementattributes.IsRemote=true
+jcs.default.elementattributes.IsLateral=true
+
+##############################################################
+################## AUXILIARY CACHES AVAILABLE ################
+
+# Disk Cache Using a Pooled Event Queue -- this allows you
+# to control the maximum number of threads it will use.
+# Each region uses 1 thread by default in the SINGLE model.
+# adding more threads than regions does not help performance.
+# If you want to use a separate pool for each disk cache, either use
+# the single model or define a different auxiliary for each region and use the
Pooled type.
+# SINGLE is generally best unless you ahve a huge # of regions.
+jcs.auxiliary.DC2=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheFactory
+jcs.auxiliary.DC2.attributes=org.apache.jcs.auxiliary.disk.indexed.IndexedDiskCacheAttributes
+jcs.auxiliary.DC2.attributes.DiskPath=target/test-sandbox/raf
+jcs.auxiliary.DC2.attributes.MaxPurgatorySize=10000
+jcs.auxiliary.DC2.attributes.MaxKeySize=10000
+jcs.auxiliary.DC2.attributes.MaxRecycleBinSize=5000
+jcs.auxiliary.DC2.attributes.OptimizeAtRemoveCount=300000
+jcs.auxiliary.DC2.attributes.EventQueueType=POOLED
+jcs.auxiliary.DC2.attributes.EventQueuePoolName=disk_cache_event_queue
+
+##############################################################
+################## OPTIONAL THREAD POOL CONFIGURATION ########
- <subsection name="TODO">
- <p>
- The Indexed Disk Auxiliary Cache will eventually be equiped
- with periodic index storage.
- </p>
- </subsection>
- </section>
- </body>
+# Disk Cache Event Queue Pool
+thread_pool.disk_cache_event_queue.useBoundary=false
+thread_pool.remote_cache_client.maximumPoolSize=15
+thread_pool.disk_cache_event_queue.minimumPoolSize=1
+thread_pool.disk_cache_event_queue.keepAliveTime=3500
+thread_pool.disk_cache_event_queue.startUpSize=1
+ ]]>
+ </source>
+ </subsection>
+ </section>
+ </body>
</document>
Modified: jakarta/jcs/trunk/xdocs/JCSvsEHCache.xml
URL:
http://svn.apache.org/viewcvs/jakarta/jcs/trunk/xdocs/JCSvsEHCache.xml?rev=378644&r1=378643&r2=378644&view=diff
==============================================================================
--- jakarta/jcs/trunk/xdocs/JCSvsEHCache.xml (original)
+++ jakarta/jcs/trunk/xdocs/JCSvsEHCache.xml Fri Feb 17 14:33:31 2006
@@ -7,189 +7,217 @@
</properties>
<body>
- <section name="Initial Results">
- <p>
- I just built both EHCache (1.2-beta4) and JCS
(1.2.7.0)
- from head, configured both similarly and ran 20
rounds
- of 50,000 puts and gets, that is 1,000,000 puts
and gets
- in total. Using the default LRU Memory Cache,
the same
- algorithm that EHCache uses by default,
- <b>JCS proved to be nearly twice as fast as
EHCache</b>
- in multiple trials for both puts and gets. I
have the
- log levels for both set at info. I would like
to further
- verify my results, since they completely
contradict the
- information on the EHCache site.
- </p>
- <p>
- From what I can tell so far, JCS is
significantly faster
- than EHCache when you are retrieving items that
exist in
- the cache and when you are putting items into a
cache
- that has not reached its size limit.
- </p>
- <p>
- Additional testing shows that when the size
limit it
- reached, JCS and EHCache perform similarly for
puts and
- gets. Although JCS gets are significantly
faster when
- the items are present, they are almost exactly
the same
- when the items are not in the cache. My initial
tests
- revealed a less than 1% difference, but
subsequent runs
- showed JCS as 20% faster. More tests are needed
before
- the results are conclusive.
- </p>
- <p>
- Since, neither cache will be a relevant
bottleneck in
- any application where a cache would be useful,
the
- differences in performance may be beside the
point.
- Nevertheless, it is important to note that the
EHCache
- web site provides, what appears to be, false
test data.
- </p>
- <p>
- The peculiar result is that a few years back
EHCache
- took the JCS source code, removed most of its
features,
- and ended up with something that performs worse.
- </p>
- </section>
+ <section name="JCS vs EHCache Memory Performance">
+ <subsection name="Initial Test Results">
+ <p>
+ I just built both EHCache (1.2-beta4)
and JCS
+ (1.2.7.0) from head, configured both
similarly and
+ ran 20 rounds of 50,000 puts and gets,
that is
+ 1,000,000 puts and gets in total. Using
the default
+ LRU Memory Cache, the same algorithm
that EHCache
+ uses by default,
+ <b>
+ JCS proved to be nearly twice
as fast as EHCache
+ </b>
+ in multiple trials for both puts and
gets. I have
+ the log levels for both set at info. I
would like to
+ further verify my results, since they
completely
+ contradict the information on the
EHCache site.
+ </p>
+ <p>
+ From what I can tell so far, JCS is
significantly
+ faster than EHCache when you are
retrieving items
+ that exist in the cache and when you
are putting
+ items into a cache that has not reached
its size
+ limit.
+ </p>
+ <p>
+ Additional testing shows that when the
size limit it
+ reached, JCS and EHCache perform
similarly for puts
+ and gets. Although JCS gets are
significantly faster
+ when the items are present, they are
almost exactly
+ the same when the items are not in the
cache. My
+ initial tests revealed a less than 1%
difference,
+ but subsequent runs showed JCS as 20%
faster. More
+ tests are needed before the results are
conclusive.
+ </p>
+ <p>
+ Since, neither cache will be a relevant
bottleneck
+ in any application where a cache would
be useful,
+ the differences in performance may be
beside the
+ point. Nevertheless, it is important to
note that
+ the EHCache web site provides, what
appears to be,
+ false test data.
+ </p>
+ <p>
+ The peculiar result is that a few years
back EHCache
+ took the JCS source code, removed most
of its
+ features, and ended up with something
that performs
+ worse.
+ </p>
+ </subsection>
+
+
+ <subsection name="Test Data">
+ <p>Here is the data from the first test:</p>
+ <p>
+ JCS put time for 50000 = 651; millis
per = 0.01302
+ JCS get time for 50000 = 160; millis
per = 0.0032
+ EHCache put time for 50000 = 481;
millis per =
+ 0.00962 EHCache get time for 50000 =
110; millis per
+ = 0.0022
+ </p>
+ <p>
+ JCS put time for 50000 = 240; millis
per = 0.0048
+ JCS get time for 50000 = 90; millis per
= 0.0018
+ EHCache put time for 50000 = 491;
millis per =
+ 0.00982 EHCache get time for 50000 =
120; millis per
+ = 0.0024
+ </p>
+ <p>
+ JCS put time for 50000 = 241; millis
per = 0.00482
+ JCS get time for 50000 = 80; millis per
= 0.0016
+ EHCache put time for 50000 = 551;
millis per =
+ 0.01102 EHCache get time for 50000 =
110; millis per
+ = 0.0022
+ </p>
+ <p>
+ JCS put time for 50000 = 240; millis
per = 0.0048
+ JCS get time for 50000 = 90; millis per
= 0.0018
+ EHCache put time for 50000 = 481;
millis per =
+ 0.00962 EHCache get time for 50000 =
130; millis per
+ = 0.0026
+ </p>
+ <p>
+ JCS put time for 50000 = 230; millis
per = 0.0046
+ JCS get time for 50000 = 181; millis
per = 0.00362
+ EHCache put time for 50000 = 520;
millis per =
+ 0.0104 EHCache get time for 50000 =
101; millis per
+ = 0.00202
+ </p>
+ <p>
+ JCS put time for 50000 = 220; millis
per = 0.0044
+ JCS get time for 50000 = 90; millis per
= 0.0018
+ EHCache put time for 50000 = 641;
millis per =
+ 0.01282 EHCache get time for 50000 =
110; millis per
+ = 0.0022
+ </p>
+ <p>
+ JCS put time for 50000 = 250; millis
per = 0.0050
+ JCS get time for 50000 = 121; millis
per = 0.00242
+ EHCache put time for 50000 = 590;
millis per =
+ 0.0118 EHCache get time for 50000 =
101; millis per
+ = 0.00202
+ </p>
+ <p>
+ JCS put time for 50000 = 260; millis
per = 0.0052
+ JCS get time for 50000 = 100; millis
per = 0.0020
+ EHCache put time for 50000 = 581;
millis per =
+ 0.01162 EHCache get time for 50000 =
100; millis per
+ = 0.0020
+ </p>
+ <p>
+ JCS put time for 50000 = 290; millis
per = 0.0058
+ JCS get time for 50000 = 121; millis
per = 0.00242
+ EHCache put time for 50000 = 570;
millis per =
+ 0.0114 EHCache get time for 50000 =
121; millis per
+ = 0.00242
+ </p>
+ <p>
+ JCS put time for 50000 = 210; millis
per = 0.0042
+ JCS get time for 50000 = 120; millis
per = 0.0024
+ EHCache put time for 50000 = 561;
millis per =
+ 0.01122 EHCache get time for 50000 =
130; millis per
+ = 0.0026
+ </p>
+ <p>
+ JCS put time for 50000 = 250; millis
per = 0.0050
+ JCS get time for 50000 = 151; millis
per = 0.00302
+ EHCache put time for 50000 = 560;
millis per =
+ 0.0112 EHCache get time for 50000 =
111; millis per
+ = 0.00222
+ </p>
+ <p>
+ JCS put time for 50000 = 250; millis
per = 0.0050
+ JCS get time for 50000 = 100; millis
per = 0.0020
+ EHCache put time for 50000 = 711;
millis per =
+ 0.01422 EHCache get time for 50000 =
100; millis per
+ = 0.0020
+ </p>
+ <p>
+ JCS put time for 50000 = 251; millis
per = 0.00502
+ JCS get time for 50000 = 90; millis per
= 0.0018
+ EHCache put time for 50000 = 511;
millis per =
+ 0.01022 EHCache get time for 50000 =
90; millis per
+ = 0.0018
+ </p>
+ <p>
+ JCS put time for 50000 = 220; millis
per = 0.0044
+ JCS get time for 50000 = 100; millis
per = 0.0020
+ EHCache put time for 50000 = 491;
millis per =
+ 0.00982 EHCache get time for 50000 =
90; millis per
+ = 0.0018
+ </p>
+ <p>
+ JCS put time for 50000 = 230; millis
per = 0.0046
+ JCS get time for 50000 = 80; millis per
= 0.0016
+ EHCache put time for 50000 = 201;
millis per =
+ 0.00402 EHCache get time for 50000 =
390; millis per
+ = 0.0078
+ </p>
+ <p>
+ JCS put time for 50000 = 201; millis
per = 0.00402
+ JCS get time for 50000 = 120; millis
per = 0.0024
+ EHCache put time for 50000 = 180;
millis per =
+ 0.0036 EHCache get time for 50000 =
411; millis per
+ = 0.00822
+ </p>
+ <p>
+ JCS put time for 50000 = 210; millis
per = 0.0042
+ JCS get time for 50000 = 100; millis
per = 0.0020
+ EHCache put time for 50000 = 210;
millis per =
+ 0.0042 EHCache get time for 50000 =
381; millis per
+ = 0.00762
+ </p>
+ <p>
+ JCS put time for 50000 = 240; millis
per = 0.0048
+ JCS get time for 50000 = 90; millis per
= 0.0018
+ EHCache put time for 50000 = 211;
millis per =
+ 0.00422 EHCache get time for 50000 =
410; millis per
+ = 0.0082
+ </p>
+ <p>
+ JCS put time for 50000 = 221; millis
per = 0.00442
+ JCS get time for 50000 = 80; millis per
= 0.0016
+ EHCache put time for 50000 = 210;
millis per =
+ 0.0042 EHCache get time for 50000 =
411; millis per
+ = 0.00822
+ </p>
+ <p>
+ JCS put time for 50000 = 220; millis
per = 0.0044
+ JCS get time for 50000 = 80; millis per
= 0.0016
+ EHCache put time for 50000 = 190;
millis per =
+ 0.0038 EHCache get time for 50000 =
411; millis per
+ = 0.00822
+ </p>
+ <p>Finished 20 loops of 50000 gets and puts</p>
+ <p>
+ Put average for JCS = 256 Put average
for EHCache =
+ 447 JCS puts took 0.57270694 times the
EHCache , the
+ goal is less than 1.0x
+ </p>
+ <p>
+ Get average for JCS = 107 Get average
for EHCache =
+ 196 JCS gets took 0.54591835 times the
EHCache , the
+ goal is less than 1.0x
+ </p>
+ </subsection>
- <section name="Test Data">
- <p>Here is the data from the first test:</p>
- <p>
- JCS put time for 50000 = 651; millis per =
0.01302 JCS
- get time for 50000 = 160; millis per = 0.0032
EHCache
- put time for 50000 = 481; millis per = 0.00962
EHCache
- get time for 50000 = 110; millis per = 0.0022
- </p>
- <p>
- JCS put time for 50000 = 240; millis per =
0.0048 JCS
- get time for 50000 = 90; millis per = 0.0018
EHCache put
- time for 50000 = 491; millis per = 0.00982
EHCache get
- time for 50000 = 120; millis per = 0.0024
- </p>
- <p>
- JCS put time for 50000 = 241; millis per =
0.00482 JCS
- get time for 50000 = 80; millis per = 0.0016
EHCache put
- time for 50000 = 551; millis per = 0.01102
EHCache get
- time for 50000 = 110; millis per = 0.0022
- </p>
- <p>
- JCS put time for 50000 = 240; millis per =
0.0048 JCS
- get time for 50000 = 90; millis per = 0.0018
EHCache put
- time for 50000 = 481; millis per = 0.00962
EHCache get
- time for 50000 = 130; millis per = 0.0026
- </p>
- <p>
- JCS put time for 50000 = 230; millis per =
0.0046 JCS
- get time for 50000 = 181; millis per = 0.00362
EHCache
- put time for 50000 = 520; millis per = 0.0104
EHCache
- get time for 50000 = 101; millis per = 0.00202
- </p>
- <p>
- JCS put time for 50000 = 220; millis per =
0.0044 JCS
- get time for 50000 = 90; millis per = 0.0018
EHCache put
- time for 50000 = 641; millis per = 0.01282
EHCache get
- time for 50000 = 110; millis per = 0.0022
- </p>
- <p>
- JCS put time for 50000 = 250; millis per =
0.0050 JCS
- get time for 50000 = 121; millis per = 0.00242
EHCache
- put time for 50000 = 590; millis per = 0.0118
EHCache
- get time for 50000 = 101; millis per = 0.00202
- </p>
- <p>
- JCS put time for 50000 = 260; millis per =
0.0052 JCS
- get time for 50000 = 100; millis per = 0.0020
EHCache
- put time for 50000 = 581; millis per = 0.01162
EHCache
- get time for 50000 = 100; millis per = 0.0020
- </p>
- <p>
- JCS put time for 50000 = 290; millis per =
0.0058 JCS
- get time for 50000 = 121; millis per = 0.00242
EHCache
- put time for 50000 = 570; millis per = 0.0114
EHCache
- get time for 50000 = 121; millis per = 0.00242
- </p>
- <p>
- JCS put time for 50000 = 210; millis per =
0.0042 JCS
- get time for 50000 = 120; millis per = 0.0024
EHCache
- put time for 50000 = 561; millis per = 0.01122
EHCache
- get time for 50000 = 130; millis per = 0.0026
- </p>
- <p>
- JCS put time for 50000 = 250; millis per =
0.0050 JCS
- get time for 50000 = 151; millis per = 0.00302
EHCache
- put time for 50000 = 560; millis per = 0.0112
EHCache
- get time for 50000 = 111; millis per = 0.00222
- </p>
- <p>
- JCS put time for 50000 = 250; millis per =
0.0050 JCS
- get time for 50000 = 100; millis per = 0.0020
EHCache
- put time for 50000 = 711; millis per = 0.01422
EHCache
- get time for 50000 = 100; millis per = 0.0020
- </p>
- <p>
- JCS put time for 50000 = 251; millis per =
0.00502 JCS
- get time for 50000 = 90; millis per = 0.0018
EHCache put
- time for 50000 = 511; millis per = 0.01022
EHCache get
- time for 50000 = 90; millis per = 0.0018
- </p>
- <p>
- JCS put time for 50000 = 220; millis per =
0.0044 JCS
- get time for 50000 = 100; millis per = 0.0020
EHCache
- put time for 50000 = 491; millis per = 0.00982
EHCache
- get time for 50000 = 90; millis per = 0.0018
- </p>
- <p>
- JCS put time for 50000 = 230; millis per =
0.0046 JCS
- get time for 50000 = 80; millis per = 0.0016
EHCache put
- time for 50000 = 201; millis per = 0.00402
EHCache get
- time for 50000 = 390; millis per = 0.0078
- </p>
- <p>
- JCS put time for 50000 = 201; millis per =
0.00402 JCS
- get time for 50000 = 120; millis per = 0.0024
EHCache
- put time for 50000 = 180; millis per = 0.0036
EHCache
- get time for 50000 = 411; millis per = 0.00822
- </p>
- <p>
- JCS put time for 50000 = 210; millis per =
0.0042 JCS
- get time for 50000 = 100; millis per = 0.0020
EHCache
- put time for 50000 = 210; millis per = 0.0042
EHCache
- get time for 50000 = 381; millis per = 0.00762
- </p>
- <p>
- JCS put time for 50000 = 240; millis per =
0.0048 JCS
- get time for 50000 = 90; millis per = 0.0018
EHCache put
- time for 50000 = 211; millis per = 0.00422
EHCache get
- time for 50000 = 410; millis per = 0.0082
- </p>
- <p>
- JCS put time for 50000 = 221; millis per =
0.00442 JCS
- get time for 50000 = 80; millis per = 0.0016
EHCache put
- time for 50000 = 210; millis per = 0.0042
EHCache get
- time for 50000 = 411; millis per = 0.00822
- </p>
- <p>
- JCS put time for 50000 = 220; millis per =
0.0044 JCS
- get time for 50000 = 80; millis per = 0.0016
EHCache put
- time for 50000 = 190; millis per = 0.0038
EHCache get
- time for 50000 = 411; millis per = 0.00822
- </p>
- <p>Finished 20 loops of 50000 gets and puts</p>
- <p>
- Put average for JCS = 256 Put average for
EHCache = 447
- JCS puts took 0.57270694 times the EHCache ,
the goal is
- less than 1.0x
- </p>
- <p>
- Get average for JCS = 107 Get average for
EHCache = 196
- JCS gets took 0.54591835 times the EHCache ,
the goal is
- less than 1.0x
- </p>
- </section>
+ <subsection name="A Test Class">
+ <p>Here is the test class:</p>
- <section name="A Test Class">
- <p>Here is the test class:</p>
-
- <source>
- <![CDATA[
+ <source>
+ <![CDATA[
package org.apache.jcs;
import junit.framework.TestCase;
@@ -385,7 +413,77 @@
}
]]>
- </source>
+ </source>
+ </subsection>
+ </section>
+
+
+ <section name="JCS vs EHCache Disk Cache">
+ <p>
+ It is very difficult to compare the ehcache
disk store
+ and the JCS Indexed Disk Cache.
+ </p>
+ <p>The JCS version is much more sophisticated.</p>
+ <p>
+ JCS puts items into a queue called purgatory.
While they
+ are in this queue, they are still accessible.
This queue
+ gets worked when items are in it. The number of
threads
+ used in the system as a whole for disk caches is
+ configurable using the thread pool
configuration options
+ in JCS. I could have 1000 regions and only use
3 threads
+ to work the disk queues. From what I can tell
EH will
+ use 1 thread per region. This is worse than the
JCS
+ default, which uses a queue that kills its
threads when
+ they are not used. . . . and much worse than
using JCS
+ with a thread pool.
+ </p>
+ <p>
+ The size of JCS purgatory is configurable, so
you can
+ avoid catastrophe if something goes wrong with
the queue
+ worker. EH doesn't have any such safety.
+ </p>
+ <p>
+ JCS limits the number of keys that can be kept
for the
+ disk cache. EH cannot do this.
+ </p>
+ <p>
+ The ehcache disk version is very simple. It
puts an
+ unlimited number of items in a temporary store.
You can
+ easily fill this up and run out of memory. You
can put
+ items into JCS prugatory faster than they can
be gc's
+ but it is much more difficult. The EH store is
then
+ flushed to disk every 200ms. While EH is
flushing the
+ entire disk cache blocks!
+ </p>
+ <p>
+ JCS disk cache is based on a continuous
spooling model,
+ not a stop the world model like EH. In most
cases the EH
+ model will work out, but not if you put a lot
of big
+ items on disk at once. If you want an even
distribution
+ of disk cache response times, then you should
use JCS.
+ </p>
+ <p>
+ The EH disk store also seems to just keep
growing. After
+ several tests, the size of the data file was 10
times
+ that of JCS and EH was taking 10 times as long.
+ </p>
+ <p>
+ You can saturate the EH version much more
quickly, since
+ it will hold as many items as you can put in in
200 ms.
+ </p>
+ <p>
+ I tried with 100k and JCS could handle it, but
EH died
+ with an out of memory exception.
+ </p>
+ <p>
+ EH cache developed its disk store in response
to a bug
+ in the JCS version. This bug was fixed a few
years ago .
+ . . The nice thing about JCS is that it is
completely
+ pluggable. It would take about 30 minutes to
plug a
+ different disk cache implementation into JCS if
you so
+ pleased . . . .
+ </p>
</section>
+
</body>
</document>
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]