Merge selected bugfixes from trunk into 2.1-RC branch
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC@1781732 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/README.md b/README.md
index 49374d7..78ebaca 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jcs</artifactId>
- <version>2.0</version>
+ <version>2.1</version>
</dependency>
```
diff --git a/commons-jcs-core/pom.xml b/commons-jcs-core/pom.xml
index 480dfae..ea02976 100644
--- a/commons-jcs-core/pom.xml
+++ b/commons-jcs-core/pom.xml
@@ -33,9 +33,9 @@
<name>Apache Commons JCS :: Core</name>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-core</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-core</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-core</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-core</url>
</scm>
<properties>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
index 0b3d656..653220d 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/auxiliary/remote/AbstractRemoteAuxiliaryCache.java
@@ -26,8 +26,8 @@
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -77,7 +77,7 @@
private IRemoteCacheAttributes remoteCacheAttributes;
/** A thread pool for gets if configured. */
- private ExecutorService pool = null;
+ private ThreadPoolExecutor pool = null;
/** Should we get asynchronously using a pool. */
private boolean usePoolForGet = false;
@@ -113,12 +113,15 @@
if ( getRemoteCacheAttributes().getGetTimeoutMillis() > 0 )
{
- pool = ThreadPoolManager.getInstance().getExecutorService( getRemoteCacheAttributes().getThreadPoolName() );
+ pool = ThreadPoolManager.getInstance().getPool( getRemoteCacheAttributes().getThreadPoolName() );
if ( log.isDebugEnabled() )
{
log.debug( "Thread Pool = " + pool );
}
- usePoolForGet = true;
+ if ( pool != null )
+ {
+ usePoolForGet = true;
+ }
}
}
@@ -142,7 +145,7 @@
getRemoteCacheListener().dispose();
}
}
- catch ( IOException ex )
+ catch ( Exception ex )
{
log.error( "Couldn't dispose", ex );
handleException( ex, "Failed to dispose [" + cacheName + "]", ICacheEventLogger.DISPOSE_EVENT );
@@ -570,7 +573,8 @@
if ( pool != null )
{
- elems.add(new StatElement<ExecutorService>( "Pool", pool ) );
+ elems.add(new StatElement<Integer>( "Pool Size", Integer.valueOf(pool.getPoolSize()) ) );
+ elems.add(new StatElement<Integer>( "Maximum Pool Size", Integer.valueOf(pool.getMaximumPoolSize()) ) );
}
if ( getRemoteCacheService() instanceof ZombieCacheServiceNonLocal )
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
index 9f37b0c..216a94d 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/AbstractCacheEventQueue.java
@@ -64,6 +64,9 @@
/** in milliseconds */
private int waitBeforeRetry;
+ /** this is true if there is any worker thread. */
+ private final AtomicBoolean alive = new AtomicBoolean(false);
+
/**
* 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.
@@ -105,27 +108,21 @@
* If they queue has an active thread it is considered alive.
* <p>
* @return The alive value
- *
- * @deprecated The alive-logic is not used
*/
- @Deprecated
- @Override
+ @Override
public boolean isAlive()
{
- return true;
+ return alive.get();
}
/**
* Sets whether the queue is actively processing -- if there are working threads.
* <p>
* @param aState
- *
- * @deprecated The alive-logic is not used
*/
- @Deprecated
- public void setAlive( boolean aState )
+ public void setAlive( boolean aState )
{
- // do nothing
+ alive.set(aState);
}
/**
@@ -182,9 +179,17 @@
* @throws IOException
*/
@Override
- public void addPutEvent( ICacheElement<K, V> ce )
+ public synchronized void addPutEvent( ICacheElement<K, V> ce )
+ throws IOException
{
- put( new PutEvent( ce ) );
+ if ( isWorking() )
+ {
+ put( new PutEvent( ce ) );
+ }
+ else if ( log.isWarnEnabled() )
+ {
+ log.warn( "Not enqueuing Put Event for [" + this + "] because it's non-functional." );
+ }
}
/**
@@ -195,28 +200,54 @@
* @throws IOException
*/
@Override
- public void addRemoveEvent( K key )
+ public synchronized void addRemoveEvent( K key )
+ throws IOException
{
- put( new RemoveEvent( key ) );
+ if ( isWorking() )
+ {
+ put( new RemoveEvent( key ) );
+ }
+ else if ( log.isWarnEnabled() )
+ {
+ log.warn( "Not enqueuing Remove Event for [" + this + "] because it's non-functional." );
+ }
}
/**
* This adds a remove all event to the queue. When it is processed, all elements will be removed
* from the cache.
+ * <p>
+ * @throws IOException
*/
@Override
- public void addRemoveAllEvent()
+ public synchronized void addRemoveAllEvent()
+ throws IOException
{
- put( new RemoveAllEvent() );
+ if ( isWorking() )
+ {
+ put( new RemoveAllEvent() );
+ }
+ else if ( log.isWarnEnabled() )
+ {
+ log.warn( "Not enqueuing RemoveAll Event for [" + this + "] because it's non-functional." );
+ }
}
/**
- * This adds a dispose event to the queue. When it is processed, the cache is shut down
+ * @throws IOException
*/
@Override
- public void addDisposeEvent()
+ public synchronized void addDisposeEvent()
+ throws IOException
{
- put( new DisposeEvent() );
+ if ( isWorking() )
+ {
+ put( new DisposeEvent() );
+ }
+ else if ( log.isWarnEnabled() )
+ {
+ log.warn( "Not enqueuing Dispose Event for [" + this + "] because it's non-functional." );
+ }
}
/**
@@ -262,7 +293,8 @@
log.warn( "Error while running event from Queue: " + this
+ ". Dropping Event and marking Event Queue as non-functional." );
}
- destroy();
+ setWorking( false );
+ setAlive( false );
return;
}
if ( log.isInfoEnabled() )
@@ -280,7 +312,10 @@
{
log.warn( "Interrupted while sleeping for retry on event " + this + "." );
}
- destroy();
+ // TODO consider if this is best. maybe we should just
+ // destroy
+ setWorking( false );
+ setAlive( false );
}
}
}
@@ -307,8 +342,10 @@
* Constructor for the PutEvent object.
* <p>
* @param ice
+ * @throws IOException
*/
PutEvent( ICacheElement<K, V> ice )
+ throws IOException
{
this.ice = ice;
}
@@ -354,8 +391,10 @@
* Constructor for the RemoveEvent object
* <p>
* @param key
+ * @throws IOException
*/
RemoveEvent( K key )
+ throws IOException
{
this.key = key;
}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
index bf2758f..58fc27b 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/CacheEventQueue.java
@@ -1,5 +1,9 @@
package org.apache.commons.jcs.engine;
+import java.util.ArrayList;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -20,19 +24,35 @@
*/
import org.apache.commons.jcs.engine.behavior.ICacheListener;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.engine.stats.StatElement;
+import org.apache.commons.jcs.engine.stats.Stats;
+import org.apache.commons.jcs.engine.stats.behavior.IStatElement;
+import org.apache.commons.jcs.engine.stats.behavior.IStats;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* An event queue is used to propagate ordered cache events to one and only one target listener.
+ * <p>
+ * This is a modified version of the experimental version. It should lazy initialize the processor
+ * thread, and kill the thread if the queue goes empty for a specified period, now set to 1 minute.
+ * If something comes in after that a new processor thread should be created.
*/
public class CacheEventQueue<K, V>
- extends PooledCacheEventQueue<K, V>
+ extends AbstractCacheEventQueue<K, V>
{
+ /** The logger. */
+ private static final Log log = LogFactory.getLog( CacheEventQueue.class );
+
/** The type of queue -- there are pooled and single */
private static final QueueType queueType = QueueType.SINGLE;
+ /** the thread that works the queue. */
+ private Thread processorThread;
+
+ /** Queue implementation */
+ private LinkedBlockingQueue<AbstractCacheEvent> queue = new LinkedBlockingQueue<AbstractCacheEvent>();
+
/**
* Constructs with the specified listener and the cache name.
* <p>
@@ -57,29 +77,7 @@
public CacheEventQueue( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
int waitBeforeRetry )
{
- super( listener, listenerId, cacheName, maxFailure, waitBeforeRetry, null );
- }
-
- /**
- * Initializes the queue.
- * <p>
- * @param listener
- * @param listenerId
- * @param cacheName
- * @param maxFailure
- * @param waitBeforeRetry
- * @param threadPoolName
- */
- @Override
- protected void initialize( ICacheListener<K, V> listener, long listenerId, String cacheName, int maxFailure,
- int waitBeforeRetry, String threadPoolName )
- {
- super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
-
- // create a default pool with one worker thread to mimic the SINGLE queue behavior
- pool = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, 1, 0, getWaitToDieMillis(), WhenBlockedPolicy.RUN, 0),
- "CacheEventQueue.QProcessor-" + getCacheName());
+ initialize( listener, listenerId, cacheName, maxFailure, waitBeforeRetry );
}
/**
@@ -92,4 +90,192 @@
{
return queueType;
}
+
+ /**
+ * Kill the processor thread and indicate that the queue is destroyed and no longer alive, but it
+ * can still be working.
+ */
+ protected void stopProcessing()
+ {
+ setAlive(false);
+ processorThread = null;
+ }
+
+ /**
+ * Event Q is empty.
+ * <p>
+ * Calling destroy interrupts the processor thread.
+ */
+ @Override
+ public void destroy()
+ {
+ if ( isAlive() )
+ {
+ setAlive(false);
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Destroying queue, stats = " + getStatistics() );
+ }
+
+ if ( processorThread != null )
+ {
+ processorThread.interrupt();
+ processorThread = null;
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Cache event queue destroyed: " + this );
+ }
+ }
+ else
+ {
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Destroy was called after queue was destroyed. Doing nothing. Stats = " + getStatistics() );
+ }
+ }
+ }
+
+ /**
+ * Adds an event to the queue.
+ * <p>
+ * @param event
+ */
+ @Override
+ protected void put( AbstractCacheEvent event )
+ {
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "Event entering Queue for " + getCacheName() + ": " + event );
+ }
+
+ queue.offer(event);
+
+ if ( isWorking() )
+ {
+ if ( !isAlive() )
+ {
+ setAlive(true);
+ processorThread = new QProcessor();
+ processorThread.start();
+ if ( log.isInfoEnabled() )
+ {
+ log.info( "Cache event queue created: " + this );
+ }
+ }
+ }
+ }
+
+ // /////////////////////////// Inner classes /////////////////////////////
+
+ /**
+ * This is the thread that works the queue.
+ * <p>
+ * @author asmuts
+ * @created January 15, 2002
+ */
+ protected class QProcessor
+ extends Thread
+ {
+ /**
+ * Constructor for the QProcessor object
+ * <p>
+ * @param aQueue the event queue to take items from.
+ */
+ QProcessor()
+ {
+ super( "CacheEventQueue.QProcessor-" + getCacheName() );
+ setDaemon( true );
+ }
+
+ /**
+ * Main processing method for the QProcessor object.
+ * <p>
+ * Waits for a specified time (waitToDieMillis) for something to come in and if no new
+ * events come in during that period the run method can exit and the thread is dereferenced.
+ */
+ @Override
+ public void run()
+ {
+
+ while ( CacheEventQueue.this.isAlive() )
+ {
+ AbstractCacheEvent event = null;
+
+ try
+ {
+ event = queue.poll(getWaitToDieMillis(), TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ // is ok
+ }
+
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "Event from queue = " + event );
+ }
+
+ if ( event == null )
+ {
+ stopProcessing();
+ }
+
+ if ( event != null && isWorking() && CacheEventQueue.this.isAlive() )
+ {
+ event.run();
+ }
+ }
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "QProcessor exiting for " + getCacheName() );
+ }
+ }
+ }
+
+ /**
+ * This method returns semi-structured data on this queue.
+ * <p>
+ * @see org.apache.commons.jcs.engine.behavior.ICacheEventQueue#getStatistics()
+ * @return information on the status and history of the queue
+ */
+ @Override
+ public IStats getStatistics()
+ {
+ IStats stats = new Stats();
+ stats.setTypeName( "Cache Event Queue" );
+
+ ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
+
+ elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(this.isWorking()) ) );
+ elems.add(new StatElement<Boolean>( "Alive", Boolean.valueOf(this.isAlive()) ) );
+ elems.add(new StatElement<Boolean>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
+ elems.add(new StatElement<Integer>( "Size", Integer.valueOf(this.size()) ) );
+
+ stats.setStatElements( elems );
+
+ return stats;
+ }
+
+ /**
+ * @return whether there are any items in the queue.
+ */
+ @Override
+ public boolean isEmpty()
+ {
+ return queue.isEmpty();
+ }
+
+ /**
+ * Returns the number of elements in the queue.
+ * <p>
+ * @return number of items in the queue.
+ */
+ @Override
+ public int size()
+ {
+ return queue.size();
+ }
}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
index e4b1089..81dfe23 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/PooledCacheEventQueue.java
@@ -2,7 +2,6 @@
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
/*
@@ -53,10 +52,7 @@
private static final QueueType queueType = QueueType.POOLED;
/** The Thread Pool to execute events with. */
- protected ExecutorService pool = null;
-
- /** The Thread Pool queue */
- protected BlockingQueue<Runnable> queue = null;
+ private ThreadPoolExecutor pool = null;
/**
* Constructor for the CacheEventQueue object
@@ -90,13 +86,8 @@
super.initialize(listener, listenerId, cacheName, maxFailure, waitBeforeRetry);
// this will share the same pool with other event queues by default.
- pool = ThreadPoolManager.getInstance().getExecutorService(
+ pool = ThreadPoolManager.getInstance().getPool(
(threadPoolName == null) ? "cache_event_queue" : threadPoolName );
-
- if (pool instanceof ThreadPoolExecutor)
- {
- queue = ((ThreadPoolExecutor) pool).getQueue();
- }
}
/**
@@ -114,9 +105,9 @@
@Override
public synchronized void destroy()
{
- if ( isWorking() )
+ if ( isAlive() )
{
- setWorking(false);
+ setAlive(false);
pool.shutdownNow();
if ( log.isInfoEnabled() )
{
@@ -147,15 +138,20 @@
ArrayList<IStatElement<?>> elems = new ArrayList<IStatElement<?>>();
- elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(isWorking()) ) );
+ elems.add(new StatElement<Boolean>( "Working", Boolean.valueOf(super.isWorking()) ) );
+ elems.add(new StatElement<Boolean>( "Alive", Boolean.valueOf(this.isAlive()) ) );
elems.add(new StatElement<Boolean>( "Empty", Boolean.valueOf(this.isEmpty()) ) );
- if ( queue != null )
+ if ( pool.getQueue() != null )
{
- elems.add(new StatElement<Integer>( "Queue Size", Integer.valueOf(queue.size()) ) );
- elems.add(new StatElement<Integer>( "Queue Capacity", Integer.valueOf(queue.remainingCapacity()) ) );
+ BlockingQueue<Runnable> bb = pool.getQueue();
+ elems.add(new StatElement<Integer>( "Queue Size", Integer.valueOf(bb.size()) ) );
+ elems.add(new StatElement<Integer>( "Queue Capacity", Integer.valueOf(bb.remainingCapacity()) ) );
}
+ elems.add(new StatElement<Integer>( "Pool Size", Integer.valueOf(pool.getPoolSize()) ) );
+ elems.add(new StatElement<Integer>( "Maximum Pool Size", Integer.valueOf(pool.getMaximumPoolSize()) ) );
+
stats.setStatElements( elems );
return stats;
@@ -170,25 +166,32 @@
@Override
public boolean isEmpty()
{
- return size() == 0;
+ if ( pool.getQueue() == null )
+ {
+ return true;
+ }
+ else
+ {
+ return pool.getQueue().size() == 0;
+ }
}
/**
* Returns the number of elements in the queue. If the queue cannot determine the size
- * accurately it will return 0.
+ * accurately it will return 1.
* <p>
* @return number of items in the queue.
*/
@Override
public int size()
{
- if ( queue == null )
+ if ( pool.getQueue() == null )
{
return 0;
}
else
{
- return queue.size();
+ return pool.getQueue().size();
}
}
}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
index 44ab573..1a6e9bd 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/control/event/ElementEventQueue.java
@@ -20,14 +20,14 @@
*/
import java.io.IOException;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -45,16 +45,20 @@
/** shutdown or not */
private boolean destroyed = false;
+ /** The event queue */
+ private LinkedBlockingQueue<Runnable> queue;
+
/** The worker thread pool. */
- private ExecutorService queueProcessor;
+ private ThreadPoolExecutor queueProcessor;
/**
* Constructor for the ElementEventQueue object
*/
public ElementEventQueue()
{
- queueProcessor = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, 1, 1, 0, WhenBlockedPolicy.RUN, 1), THREAD_PREFIX);
+ queue = new LinkedBlockingQueue<Runnable>();
+ queueProcessor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
+ queue, new DaemonThreadFactory(THREAD_PREFIX));
if ( log.isDebugEnabled() )
{
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
index 5f85104..b5523d7 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractDoubleLinkedListMemoryCache.java
@@ -20,10 +20,15 @@
*/
import java.io.IOException;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.commons.jcs.engine.CacheConstants;
import org.apache.commons.jcs.engine.behavior.ICacheElement;
import org.apache.commons.jcs.engine.control.CompositeCache;
import org.apache.commons.jcs.engine.control.group.GroupAttrName;
@@ -194,6 +199,74 @@
}
/**
+ * Get an item from the cache If the item is found, it is removed from the list and added first.
+ * <p>
+ *
+ * @param key
+ * Identifies item to find
+ * @return ICacheElement<K, V> if found, else null
+ * @throws IOException
+ */
+ @Override
+ public final ICacheElement<K, V> get(K key) throws IOException
+ {
+ ICacheElement<K, V> ce = null;
+
+ if (log.isDebugEnabled())
+ {
+ log.debug(getCacheName() + ": getting item for key " + key);
+ }
+
+ MemoryElementDescriptor<K, V> me = map.get(key);
+
+ if (me != null)
+ {
+ hitCnt.incrementAndGet();
+
+ lock.lock();
+ try
+ {
+ ce = me.getCacheElement();
+ // ABSTRACT
+ adjustListForGet(me);
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug(getCacheName() + ": LRUMemoryCache hit for " + key);
+ }
+ }
+ else
+ {
+ missCnt.incrementAndGet();
+
+ if (log.isDebugEnabled())
+ {
+ log.debug(getCacheName() + ": LRUMemoryCache miss for " + key);
+ }
+ }
+
+ if (log.isDebugEnabled())
+ {
+ verifyCache();
+ }
+
+ return ce;
+ }
+
+ /**
+ * Adjust the list as needed for a get. This allows children to control the algorithm
+ * <p>
+ *
+ * @param me
+ */
+ protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
+
+ /**
* This instructs the memory cache to remove the <i>numberToFree</i> according to its eviction
* policy. For example, the LRUMemoryCache will remove the <i>numberToFree</i> least recently
* used items. These will be spooled to disk if a disk auxiliary is available.
@@ -270,61 +343,116 @@
}
/**
- * @see org.apache.commons.jcs.engine.memory.AbstractMemoryCache#get(java.lang.Object)
- */
- @Override
- public ICacheElement<K, V> get(K key) throws IOException
- {
- ICacheElement<K, V> ce = super.get(key);
-
- if (log.isDebugEnabled())
- {
- verifyCache();
- }
-
- return ce;
- }
-
- /**
- * Adjust the list as needed for a get. This allows children to control the algorithm
+ * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+ * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+ * starting with the argument String will be removed.
* <p>
*
- * @param me
- */
- protected abstract void adjustListForGet(MemoryElementDescriptor<K, V> me);
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
+ * @param key
+ * @return true if the removal was successful
+ * @throws IOException
*/
@Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ public boolean remove(K key) throws IOException
{
- adjustListForGet(me);
+ if (log.isDebugEnabled())
+ {
+ log.debug("removing item for key: " + key);
+ }
+
+ boolean removed = false;
+
+ // handle partial removal
+ if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
+ {
+ // remove all keys of the same name hierarchy.
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if (k instanceof String && ((String) k).startsWith(key.toString()))
+ {
+ lock.lock();
+ try
+ {
+ list.remove(entry.getValue());
+ itr.remove();
+ removed = true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+ }
+ }
+ else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+ {
+ // remove all keys of the same name hierarchy.
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
+ {
+ lock.lock();
+ try
+ {
+ list.remove(entry.getValue());
+ itr.remove();
+ removed = true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+ }
+ }
+ else
+ {
+ // remove single item.
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> me = map.remove(key);
+ if (me != null)
+ {
+ list.remove(me);
+ removed = true;
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ return removed;
}
/**
- * Remove element from control structure
- * (guarded by the lock)
+ * Remove all of the elements from both the Map and the linked list implementation. Overrides
+ * base class.
+ * <p>
*
- * @param me the memory element descriptor
+ * @throws IOException
*/
@Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ public void removeAll() throws IOException
{
- list.remove(me);
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- @Override
- protected void lockedRemoveAll()
- {
- list.removeAll();
+ lock.lock();
+ try
+ {
+ list.removeAll();
+ map.clear();
+ }
+ finally
+ {
+ lock.unlock();
+ }
}
// --------------------------- internal methods (linked list implementation)
@@ -503,6 +631,17 @@
}
/**
+ * Get an Array of the keys for all elements in the memory cache
+ *
+ * @return An Object[]
+ */
+ @Override
+ public Set<K> getKeySet()
+ {
+ return new LinkedHashSet<K>(map.keySet());
+ }
+
+ /**
* This returns semi-structured information on the memory cache, such as the size, put count,
* hit count, and miss count.
* <p>
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
index dc4bf5c..87929fa 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/AbstractMemoryCache.java
@@ -22,19 +22,16 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import org.apache.commons.jcs.engine.CacheConstants;
+import org.apache.commons.jcs.engine.CacheStatus;
import org.apache.commons.jcs.engine.behavior.ICacheElement;
import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
import org.apache.commons.jcs.engine.control.CompositeCache;
-import org.apache.commons.jcs.engine.control.group.GroupAttrName;
import org.apache.commons.jcs.engine.memory.behavior.IMemoryCache;
import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
import org.apache.commons.jcs.engine.stats.StatElement;
@@ -46,6 +43,9 @@
/**
* This base includes some common code for memory caches.
+ * <p>
+ * This keeps a static reference to a memory shrinker clock daemon. If this region is configured to
+ * use the shrinker, the clock daemon will be setup to run the shrinker on this region.
*/
public abstract class AbstractMemoryCache<K, V>
implements IMemoryCache<K, V>
@@ -59,6 +59,9 @@
/** The cache region this store is associated with */
private CompositeCache<K, V> cache;
+ /** status */
+ private CacheStatus status;
+
/** How many to spool at a time. */
protected int chunkSize;
@@ -93,6 +96,8 @@
this.cache = hub;
this.map = createMap();
+
+ this.status = CacheStatus.ALIVE;
}
/**
@@ -104,6 +109,28 @@
public abstract Map<K, MemoryElementDescriptor<K, V>> createMap();
/**
+ * Removes an item from the cache
+ * <p>
+ * @param key Identifies item to be removed
+ * @return Description of the Return Value
+ * @throws IOException Description of the Exception
+ */
+ @Override
+ public abstract boolean remove( K key )
+ throws IOException;
+
+ /**
+ * Get an item from the cache
+ * <p>
+ * @param key Description of the Parameter
+ * @return Description of the Return Value
+ * @throws IOException Description of the Exception
+ */
+ @Override
+ public abstract ICacheElement<K, V> get( K key )
+ throws IOException;
+
+ /**
* Gets multiple items from the cache based on the given set of keys.
* <p>
* @param keys
@@ -176,32 +203,26 @@
throws IOException;
/**
+ * Get a set of the keys for all elements in the memory cache
+ * <p>
+ * @return A set of the key type
+ */
+ @Override
+ public abstract Set<K> getKeySet();
+
+ /**
* Removes all cached items from the cache.
* <p>
* @throws IOException
*/
@Override
- public void removeAll() throws IOException
+ public void removeAll()
+ throws IOException
{
- lock.lock();
- try
- {
- lockedRemoveAll();
- map.clear();
- }
- finally
- {
- lock.unlock();
- }
+ map.clear();
}
/**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- protected abstract void lockedRemoveAll();
-
- /**
* Prepares for shutdown. Reset statistics
* <p>
* @throws IOException
@@ -249,6 +270,16 @@
}
/**
+ * Returns the cache status.
+ * <p>
+ * @return The status value
+ */
+ public CacheStatus getStatus()
+ {
+ return this.status;
+ }
+
+ /**
* Returns the cache (aka "region") name.
* <p>
* @return The cacheName value
@@ -320,204 +351,4 @@
{
return this.cache;
}
-
- /**
- * Remove all keys of the same group hierarchy.
- * @param key the key
- * @return true if something has been removed
- */
- protected boolean removeByGroup(K key)
- {
- boolean removed = false;
-
- // remove all keys of the same group hierarchy.
- for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
- {
- Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
- K k = entry.getKey();
-
- if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
- {
- lock.lock();
- try
- {
- itr.remove();
- lockedRemoveElement(entry.getValue());
- removed = true;
- }
- finally
- {
- lock.unlock();
- }
- }
- }
-
- return removed;
- }
-
- /**
- * Remove all keys of the same name hierarchy.
- *
- * @param key the key
- * @return true if something has been removed
- */
- protected boolean removeByHierarchy(K key)
- {
- boolean removed = false;
-
- // remove all keys of the same name hierarchy.
- for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext();)
- {
- Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
- K k = entry.getKey();
-
- if (k instanceof String && ((String) k).startsWith(key.toString()))
- {
- lock.lock();
- try
- {
- itr.remove();
- lockedRemoveElement(entry.getValue());
- removed = true;
- }
- finally
- {
- lock.unlock();
- }
- }
- }
-
- return removed;
- }
-
- /**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- protected abstract void lockedRemoveElement(MemoryElementDescriptor<K, V> me);
-
- /**
- * Removes an item from the cache. This method handles hierarchical removal. If the key is a
- * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
- * starting with the argument String will be removed.
- * <p>
- *
- * @param key
- * @return true if the removal was successful
- * @throws IOException
- */
- @Override
- public boolean remove(K key) throws IOException
- {
- if (log.isDebugEnabled())
- {
- log.debug("removing item for key: " + key);
- }
-
- boolean removed = false;
-
- // handle partial removal
- if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
- {
- removed = removeByHierarchy(key);
- }
- else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
- {
- removed = removeByGroup(key);
- }
- else
- {
- // remove single item.
- lock.lock();
- try
- {
- MemoryElementDescriptor<K, V> me = map.remove(key);
- if (me != null)
- {
- lockedRemoveElement(me);
- removed = true;
- }
- }
- finally
- {
- lock.unlock();
- }
- }
-
- return removed;
- }
-
- /**
- * Get an Array of the keys for all elements in the memory cache
- *
- * @return An Object[]
- */
- @Override
- public Set<K> getKeySet()
- {
- return new LinkedHashSet<K>(map.keySet());
- }
-
- /**
- * Get an item from the cache.
- * <p>
- *
- * @param key Identifies item to find
- * @return ICacheElement<K, V> if found, else null
- * @throws IOException
- */
- @Override
- public ICacheElement<K, V> get(K key) throws IOException
- {
- ICacheElement<K, V> ce = null;
-
- if (log.isDebugEnabled())
- {
- log.debug(getCacheName() + ": getting item for key " + key);
- }
-
- MemoryElementDescriptor<K, V> me = map.get(key);
-
- if (me != null)
- {
- hitCnt.incrementAndGet();
- ce = me.getCacheElement();
-
- lock.lock();
- try
- {
- lockedGetElement(me);
- }
- finally
- {
- lock.unlock();
- }
-
- if (log.isDebugEnabled())
- {
- log.debug(getCacheName() + ": MemoryCache hit for " + key);
- }
- }
- else
- {
- missCnt.incrementAndGet();
-
- if (log.isDebugEnabled())
- {
- log.debug(getCacheName() + ": MemoryCache miss for " + key);
- }
- }
-
- return ce;
- }
-
- /**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
- */
- protected abstract void lockedGetElement(MemoryElementDescriptor<K, V> me);
}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
index 2679fb7..b6ff779 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/lru/LHMLRUMemoryCache.java
@@ -21,10 +21,15 @@
import java.io.IOException;
import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.Map;
+import java.util.Set;
+import org.apache.commons.jcs.engine.CacheConstants;
import org.apache.commons.jcs.engine.behavior.ICacheElement;
import org.apache.commons.jcs.engine.control.CompositeCache;
+import org.apache.commons.jcs.engine.control.group.GroupAttrName;
import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
import org.apache.commons.jcs.engine.stats.behavior.IStats;
@@ -78,37 +83,124 @@
}
/**
- * Update control structures after get
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
+ * Get an item from the cache
+ * <p>
+ * @param key Identifies item to find
+ * @return ICacheElement<K, V> if found, else null
+ * @throws IOException
*/
@Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ public ICacheElement<K, V> get( K key )
+ throws IOException
{
- // empty
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "getting item from cache " + getCacheName() + " for key " + key );
+ }
+
+ MemoryElementDescriptor<K, V> me = map.get( key );
+
+ if ( me != null )
+ {
+ hitCnt.incrementAndGet();
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( getCacheName() + ": LHMLRUMemoryCache hit for " + key );
+ }
+ return me.getCacheElement();
+ }
+ else
+ {
+ missCnt.incrementAndGet();
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( getCacheName() + ": LHMLRUMemoryCache miss for " + key );
+ }
+ }
+
+ return null;
}
/**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
+ * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+ * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+ * starting with the argument String will be removed.
+ * <p>
+ * @param key
+ * @return true if removed
+ * @throws IOException
*/
@Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ public boolean remove( K key )
+ throws IOException
{
- // empty
+ if ( log.isDebugEnabled() )
+ {
+ log.debug( "removing item for key: " + key );
+ }
+
+ boolean removed = false;
+
+ // handle partial removal
+ if ( key instanceof String && ( (String) key ).endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
+ {
+ // remove all keys of the same name hierarchy.
+ synchronized ( map )
+ {
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if ( k instanceof String && ( (String) k ).startsWith( key.toString() ) )
+ {
+ itr.remove();
+ removed = true;
+ }
+ }
+ }
+ }
+ else if ( key instanceof GroupAttrName && ((GroupAttrName<?>)key).attrName == null )
+ {
+ // remove all keys of the same name hierarchy.
+ synchronized ( map )
+ {
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator(); itr.hasNext(); )
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if ( k instanceof GroupAttrName &&
+ ((GroupAttrName<?>)k).groupId.equals(((GroupAttrName<?>)key).groupId) )
+ {
+ itr.remove();
+ removed = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // remove single item.
+ MemoryElementDescriptor<K, V> me = map.remove( key );
+ if ( me != null )
+ {
+ removed = true;
+ }
+ }
+
+ return removed;
}
/**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
+ * Get an Array of the keys for all elements in the memory cache
+ * <p>
+ * @return An Object[]
*/
@Override
- protected void lockedRemoveAll()
+ public Set<K> getKeySet()
{
- // empty
+ return new LinkedHashSet<K>(map.keySet());
}
/**
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
index b5c703b..5108c66 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/engine/memory/soft/SoftReferenceMemoryCache.java
@@ -22,6 +22,7 @@
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -29,9 +30,11 @@
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.LinkedBlockingQueue;
+import org.apache.commons.jcs.engine.CacheConstants;
import org.apache.commons.jcs.engine.behavior.ICacheElement;
import org.apache.commons.jcs.engine.behavior.ICompositeCacheAttributes;
import org.apache.commons.jcs.engine.control.CompositeCache;
+import org.apache.commons.jcs.engine.control.group.GroupAttrName;
import org.apache.commons.jcs.engine.memory.AbstractMemoryCache;
import org.apache.commons.jcs.engine.memory.util.MemoryElementDescriptor;
import org.apache.commons.jcs.engine.memory.util.SoftReferenceElementDescriptor;
@@ -144,41 +147,107 @@
}
/**
- * Update control structures after get
- * (guarded by the lock)
+ * Removes an item from the cache. This method handles hierarchical removal. If the key is a
+ * String and ends with the CacheConstants.NAME_COMPONENT_DELIMITER, then all items with keys
+ * starting with the argument String will be removed.
+ * <p>
*
- * @param me the memory element descriptor
+ * @param key
+ * @return true if the removal was successful
+ * @throws IOException
*/
@Override
- protected void lockedGetElement(MemoryElementDescriptor<K, V> me)
+ public boolean remove(K key) throws IOException
{
- ICacheElement<K, V> val = me.getCacheElement();
- val.getElementAttributes().setLastAccessTimeNow();
+ if (log.isDebugEnabled())
+ {
+ log.debug("removing item for key: " + key);
+ }
- // update the ordering of the strong references
- strongReferences.add(val);
- trimStrongReferences();
+ boolean removed = false;
+
+ // handle partial removal
+ if (key instanceof String && ((String) key).endsWith(CacheConstants.NAME_COMPONENT_DELIMITER))
+ {
+ // remove all keys of the same name hierarchy.
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
+ itr.hasNext();)
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if (k instanceof String && ((String) k).startsWith(key.toString()))
+ {
+ lock.lock();
+ try
+ {
+ strongReferences.remove(entry.getValue().getCacheElement());
+ itr.remove();
+ removed = true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+ }
+ }
+ else if (key instanceof GroupAttrName && ((GroupAttrName<?>) key).attrName == null)
+ {
+ // remove all keys of the same name hierarchy.
+ for (Iterator<Map.Entry<K, MemoryElementDescriptor<K, V>>> itr = map.entrySet().iterator();
+ itr.hasNext();)
+ {
+ Map.Entry<K, MemoryElementDescriptor<K, V>> entry = itr.next();
+ K k = entry.getKey();
+
+ if (k instanceof GroupAttrName && ((GroupAttrName<?>) k).groupId.equals(((GroupAttrName<?>) key).groupId))
+ {
+ lock.lock();
+ try
+ {
+ strongReferences.remove(entry.getValue().getCacheElement());
+ itr.remove();
+ removed = true;
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+ }
+ }
+ else
+ {
+ // remove single item.
+ lock.lock();
+ try
+ {
+ MemoryElementDescriptor<K, V> me = map.remove(key);
+ if (me != null)
+ {
+ strongReferences.remove(me.getCacheElement());
+ removed = true;
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ return removed;
}
/**
- * Remove element from control structure
- * (guarded by the lock)
- *
- * @param me the memory element descriptor
+ * Removes all cached items from the cache.
+ * <p>
+ * @throws IOException
*/
@Override
- protected void lockedRemoveElement(MemoryElementDescriptor<K, V> me)
+ public void removeAll() throws IOException
{
- strongReferences.remove(me.getCacheElement());
- }
-
- /**
- * Removes all cached items from the cache control structures.
- * (guarded by the lock)
- */
- @Override
- protected void lockedRemoveAll()
- {
+ super.removeAll();
strongReferences.clear();
}
@@ -225,6 +294,48 @@
}
/**
+ * Get an item from the cache
+ * <p>
+ * @param key Description of the Parameter
+ * @return Description of the Return Value
+ * @throws IOException Description of the Exception
+ */
+ @Override
+ public ICacheElement<K, V> get(K key) throws IOException
+ {
+ ICacheElement<K, V> val = null;
+ lock.lock();
+
+ try
+ {
+ val = getQuiet(key);
+ if (val != null)
+ {
+ val.getElementAttributes().setLastAccessTimeNow();
+
+ // update the ordering of the strong references
+ strongReferences.add(val);
+ trimStrongReferences();
+ }
+ }
+ finally
+ {
+ lock.unlock();
+ }
+
+ if (val == null)
+ {
+ missCnt.incrementAndGet();
+ }
+ else
+ {
+ hitCnt.incrementAndGet();
+ }
+
+ return val;
+ }
+
+ /**
* This can't be implemented.
* <p>
* @param numberToFree
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
index 07a6687..e8f9cba 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/discovery/UDPDiscoveryReceiver.java
@@ -25,15 +25,14 @@
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
-import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.jcs.engine.CacheInfo;
import org.apache.commons.jcs.engine.behavior.IShutdownObserver;
import org.apache.commons.jcs.io.ObjectInputStreamClassLoaderAware;
import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration;
-import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
-import org.apache.commons.jcs.utils.threadpool.ThreadPoolManager;
+import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -57,7 +56,7 @@
private static final int maxPoolSize = 2;
/** The processor */
- private ExecutorService pooledExecutor = null;
+ private ThreadPoolExecutor pooledExecutor = null;
/** number of messages received. For debugging and testing. */
private int cnt = 0;
@@ -92,9 +91,10 @@
this.multicastPort = multicastPort;
// create a small thread pool to handle a barrage
- pooledExecutor = ThreadPoolManager.getInstance().createPool(
- new PoolConfiguration(false, 0, maxPoolSize, maxPoolSize, 0, WhenBlockedPolicy.DISCARDOLDEST, maxPoolSize),
- "JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY);
+ pooledExecutor = (ThreadPoolExecutor)Executors.newFixedThreadPool(maxPoolSize,
+ new DaemonThreadFactory("JCS-UDPDiscoveryReceiver-", Thread.MIN_PRIORITY));
+ pooledExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
+ //pooledExecutor.setMinimumPoolSize(1);
if ( log.isInfoEnabled() )
{
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
index 9effd97..c747f4c 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/AbstractLRUMap.java
@@ -64,20 +64,22 @@
private final DoubleLinkedList<LRUElementDescriptor<K, V>> list;
/** Map where items are stored by key. */
- private final Map<K, LRUElementDescriptor<K, V>> map;
+ private Map<K, LRUElementDescriptor<K, V>> map;
- /** lock to keep map and list synchronous */
+ /** stats */
+ int hitCnt = 0;
+
+ /** stats */
+ int missCnt = 0;
+
+ /** stats */
+ int putCnt = 0;
+
+ /** make configurable */
+ private int chunkSize = 1;
+
private final Lock lock = new ReentrantLock();
- /** stats */
- private long hitCnt = 0;
-
- /** stats */
- private long missCnt = 0;
-
- /** stats */
- private long putCnt = 0;
-
/**
* This creates an unbounded version. Setting the max objects will result in spooling on
* subsequent puts.
@@ -194,7 +196,7 @@
@Override
public V get( Object key )
{
- V retVal;
+ V retVal = null;
if ( log.isDebugEnabled() )
{
@@ -203,28 +205,22 @@
LRUElementDescriptor<K, V> me = map.get( key );
- if ( me == null )
- {
- missCnt++;
- retVal = null;
- }
- else
+ if ( me != null )
{
hitCnt++;
- retVal = me.getPayload();
- list.makeFirst( me );
- }
-
- if ( log.isDebugEnabled() )
- {
- if ( me == null )
- {
- log.debug( "LRUMap miss for " + key );
- }
- else
+ if ( log.isDebugEnabled() )
{
log.debug( "LRUMap hit for " + key );
}
+
+ retVal = me.getPayload();
+
+ list.makeFirst( me );
+ }
+ else
+ {
+ missCnt++;
+ log.debug( "LRUMap miss for " + key );
}
// verifyCache();
@@ -242,23 +238,20 @@
public V getQuiet( Object key )
{
V ce = null;
- LRUElementDescriptor<K, V> me = map.get( key );
+ LRUElementDescriptor<K, V> me = map.get( key );
if ( me != null )
{
- ce = me.getPayload();
- }
-
- if ( log.isDebugEnabled() )
- {
- if ( me == null )
- {
- log.debug( "LRUMap quiet miss for " + key );
- }
- else
+ if ( log.isDebugEnabled() )
{
log.debug( "LRUMap quiet hit for " + key );
}
+
+ ce = me.getPayload();
+ }
+ else if ( log.isDebugEnabled() )
+ {
+ log.debug( "LRUMap quiet miss for " + key );
}
return ce;
@@ -307,16 +300,17 @@
putCnt++;
LRUElementDescriptor<K, V> old = null;
- LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, value);
-
lock.lock();
try
{
- list.addFirst( me );
- old = map.put(key, me);
+ // TODO address double synchronization of addFirst, use write lock
+ addFirst( key, value );
+ // this must be synchronized
+ LRUElementDescriptor<K, V> first = list.getFirst();
+ old = map.put(first.getKey(), first);
// If the node was the same as an existing node, remove it.
- if ( old != null && key.equals(old.getKey()))
+ if ( old != null && first.getKey().equals(old.getKey()))
{
list.remove( old );
}
@@ -327,6 +321,7 @@
}
// If the element limit is reached, we need to spool
+
if (shouldRemove())
{
if (log.isDebugEnabled())
@@ -337,6 +332,7 @@
// The spool will put them in a disk event queue, so there is no
// need to pre-queue the queuing. This would be a bit wasteful
// and wouldn't save much time in this synchronous call.
+
while ( shouldRemove() )
{
lock.lock();
@@ -370,10 +366,10 @@
{
log.debug( "update: After spool map size: " + map.size() );
}
- if ( map.size() != list.size() )
+ if ( map.size() != dumpCacheSize() )
{
- log.error("update: After spool, size mismatch: map.size() = " + map.size() +
- ", linked list size = " + list.size());
+ log.error("update: After spool, size mismatch: map.size() = " + map.size() + ", linked list size = "
+ + dumpCacheSize());
}
}
@@ -386,6 +382,37 @@
protected abstract boolean shouldRemove();
+
+ /**
+ * Adds a new node to the start of the link list.
+ * <p>
+ * @param key
+ * @param val The feature to be added to the First
+ */
+ private void addFirst(K key, V val)
+ {
+ lock.lock();
+ try
+ {
+ LRUElementDescriptor<K, V> me = new LRUElementDescriptor<K, V>(key, val);
+ list.addFirst( me );
+ }
+ finally
+ {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Returns the size of the list.
+ * <p>
+ * @return int
+ */
+ private int dumpCacheSize()
+ {
+ return list.size();
+ }
+
/**
* Dump the cache entries from first to list for debugging.
*/
@@ -431,8 +458,8 @@
}
boolean found = false;
- log.debug( "verifycache: mapContains " + map.size() +
- " elements, linked list contains " + list.size() + " elements" );
+ log.debug( "verifycache: mapContains " + map.size() + " elements, linked list contains " + dumpCacheSize()
+ + " elements" );
log.debug( "verifycache: checking linked list by key " );
for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
{
@@ -510,6 +537,37 @@
}
/**
+ * Logs an error is an element that should be in the cache is not.
+ * <p>
+ * @param key
+ */
+ @SuppressWarnings("unchecked") // No generics for public fields
+ protected void verifyCache( Object key )
+ {
+ if ( !log.isDebugEnabled() )
+ {
+ return;
+ }
+
+ boolean found = false;
+
+ // go through the linked list looking for the key
+ for (LRUElementDescriptor<K, V> li = list.getFirst(); li != null; li = (LRUElementDescriptor<K, V>) li.next )
+ {
+ if ( li.getKey() == key )
+ {
+ found = true;
+ log.debug( "verifycache(key) key match: " + key );
+ break;
+ }
+ }
+ if ( !found )
+ {
+ log.error( "verifycache(key), couldn't find key! : " + key );
+ }
+ }
+
+ /**
* This is called when an item is removed from the LRU. We just log some information.
* <p>
* Children can implement this method for special behavior.
@@ -526,6 +584,24 @@
}
/**
+ * The chunk size is the number of items to remove when the max is reached. By default it is 1.
+ * <p>
+ * @param chunkSize The chunkSize to set.
+ */
+ public void setChunkSize( int chunkSize )
+ {
+ this.chunkSize = chunkSize;
+ }
+
+ /**
+ * @return Returns the chunkSize.
+ */
+ public int getChunkSize()
+ {
+ return chunkSize;
+ }
+
+ /**
* @return IStats
*/
public IStats getStatistics()
@@ -537,9 +613,9 @@
elems.add(new StatElement<Integer>( "List Size", Integer.valueOf(list.size()) ) );
elems.add(new StatElement<Integer>( "Map Size", Integer.valueOf(map.size()) ) );
- elems.add(new StatElement<Long>( "Put Count", Long.valueOf(putCnt) ) );
- elems.add(new StatElement<Long>( "Hit Count", Long.valueOf(hitCnt) ) );
- elems.add(new StatElement<Long>( "Miss Count", Long.valueOf(missCnt) ) );
+ elems.add(new StatElement<Integer>( "Put Count", Integer.valueOf(putCnt) ) );
+ elems.add(new StatElement<Integer>( "Hit Count", Integer.valueOf(hitCnt) ) );
+ elems.add(new StatElement<Integer>( "Miss Count", Integer.valueOf(missCnt) ) );
stats.setStatElements( elems );
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
index 84ff231..fa100b2 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/struct/LRUMap.java
@@ -19,6 +19,8 @@
* under the License.
*/
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
*
* @author Wiktor Niesiobędzki
@@ -30,8 +32,10 @@
*/
public class LRUMap<K, V> extends AbstractLRUMap<K, V>
{
+
/** if the max is less than 0, there is no limit! */
- private int maxObjects = -1;
+ int maxObjects = -1;
+ AtomicInteger counter = new AtomicInteger(0);
public LRUMap()
{
@@ -45,7 +49,7 @@
*/
public LRUMap(int maxObjects)
{
- this();
+ super();
this.maxObjects = maxObjects;
}
@@ -54,4 +58,9 @@
{
return maxObjects > 0 && this.size() > maxObjects;
}
+
+ public Object getMaxCounter()
+ {
+ return maxObjects;
+ }
}
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
index f4e886d..05f17e7 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/PoolConfiguration.java
@@ -27,46 +27,23 @@
public final class PoolConfiguration
implements Cloneable
{
- /**
- * DEFAULT SETTINGS
- */
- private static final boolean DEFAULT_USE_BOUNDARY = true;
-
- /** Default queue size limit */
- private static final int DEFAULT_BOUNDARY_SIZE = 2000;
-
- /** Default max size */
- private static final int DEFAULT_MAXIMUM_POOL_SIZE = 150;
-
- /** Default min */
- private static final int DEFAULT_MINIMUM_POOL_SIZE = Runtime.getRuntime().availableProcessors();
-
- /** Default keep alive */
- private static final int DEFAULT_KEEPALIVE_TIME = 1000 * 60 * 5;
-
- /** Default when blocked */
- private static final WhenBlockedPolicy DEFAULT_WHEN_BLOCKED_POLICY = WhenBlockedPolicy.RUN;
-
- /** Default startup size */
- private static final int DEFAULT_STARTUP_SIZE = DEFAULT_MINIMUM_POOL_SIZE;
-
/** Should we bound the queue */
- private boolean useBoundary = DEFAULT_USE_BOUNDARY;
+ private boolean useBoundary = true;
/** If the queue is bounded, how big can it get */
- private int boundarySize = DEFAULT_BOUNDARY_SIZE;
+ private int boundarySize = 2000;
/** only has meaning if a boundary is used */
- private int maximumPoolSize = DEFAULT_MAXIMUM_POOL_SIZE;
+ private int maximumPoolSize = 150;
/**
* the exact number that will be used in a boundless queue. If the queue has a boundary, more
* will be created if the queue fills.
*/
- private int minimumPoolSize = DEFAULT_MINIMUM_POOL_SIZE;
+ private int minimumPoolSize = 4;
/** How long idle threads above the minimum should be kept alive. */
- private int keepAliveTime = DEFAULT_KEEPALIVE_TIME;
+ private int keepAliveTime = 1000 * 60 * 5;
public enum WhenBlockedPolicy {
/** abort when queue is full and max threads is reached. */
@@ -86,10 +63,10 @@
}
/** should be ABORT, BLOCK, RUN, WAIT, DISCARDOLDEST, */
- private WhenBlockedPolicy whenBlockedPolicy = DEFAULT_WHEN_BLOCKED_POLICY;
+ private WhenBlockedPolicy whenBlockedPolicy = WhenBlockedPolicy.RUN;
/** The number of threads to create on startup */
- private int startUpSize = DEFAULT_MINIMUM_POOL_SIZE;
+ private int startUpSize = 4;
/**
* @param useBoundary The useBoundary to set.
@@ -112,9 +89,7 @@
*/
public PoolConfiguration()
{
- this( DEFAULT_USE_BOUNDARY, DEFAULT_BOUNDARY_SIZE, DEFAULT_MAXIMUM_POOL_SIZE,
- DEFAULT_MINIMUM_POOL_SIZE, DEFAULT_KEEPALIVE_TIME,
- DEFAULT_WHEN_BLOCKED_POLICY, DEFAULT_STARTUP_SIZE );
+ // nop
}
/**
diff --git a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
index 93ca842..0c9346c 100644
--- a/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
+++ b/commons-jcs-core/src/main/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManager.java
@@ -23,14 +23,11 @@
import java.util.Properties;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
-import org.apache.commons.jcs.utils.config.PropertySetter;
+import org.apache.commons.jcs.utils.threadpool.PoolConfiguration.WhenBlockedPolicy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -42,12 +39,30 @@
* This manager forces you to use a bounded queue. By default it uses the current thread for
* execution when the buffer is full and no free threads can be created.
* <p>
- * You can specify the props file to use or pass in a properties object prior to configuration.
+ * You can specify the props file to use or pass in a properties object prior to configuration. By
+ * default it looks for configuration information in thread_pool.properties.
* <p>
* If set, the Properties object will take precedence.
* <p>
- * If a value is not set for a particular pool, the hard coded defaults in <code>PoolConfiguration</code> will be used.
- * You can configure default settings by specifying <code>thread_pool.default</code> in the properties, ie "cache.ccf"
+ * If a value is not set for a particular pool, the hard coded defaults will be used.
+ *
+ * <pre>
+ * int boundarySize_DEFAULT = 2000;
+ *
+ * int maximumPoolSize_DEFAULT = 150;
+ *
+ * int minimumPoolSize_DEFAULT = 4;
+ *
+ * int keepAliveTime_DEFAULT = 1000 * 60 * 5;
+ *
+ * boolean abortWhenBlocked = false;
+ *
+ * String whenBlockedPolicy_DEFAULT = IPoolConfiguration.POLICY_RUN;
+ *
+ * int startUpSize_DEFAULT = 4;
+ * </pre>
+ *
+ * You can configure default settings by specifying a default pool in the properties, ie "cache.ccf"
* <p>
* @author Aaron Smuts
*/
@@ -56,8 +71,31 @@
/** The logger */
private static final Log log = LogFactory.getLog( ThreadPoolManager.class );
+ /**
+ * DEFAULT SETTINGS, these are not final since they can be set via the properties file or object
+ */
+ private static boolean useBoundary_DEFAULT = true;
+
+ /** Default queue size limit */
+ private static int boundarySize_DEFAULT = 2000;
+
+ /** Default max size */
+ private static int maximumPoolSize_DEFAULT = 150;
+
+ /** Default min */
+ private static int minimumPoolSize_DEFAULT = 4;
+
+ /** Default keep alive */
+ private static int keepAliveTime_DEFAULT = 1000 * 60 * 5;
+
+ /** Default when blocked */
+ private static WhenBlockedPolicy whenBlockedPolicy_DEFAULT = WhenBlockedPolicy.RUN;
+
+ /** Default startup size */
+ private static int startUpSize_DEFAULT = 4;
+
/** The default config, created using property defaults if present, else those above. */
- private PoolConfiguration defaultConfig;
+ private static PoolConfiguration defaultConfig;
/** the root property name */
private static final String PROP_NAME_ROOT = "thread_pool";
@@ -65,13 +103,7 @@
/** default property file name */
private static final String DEFAULT_PROP_NAME_ROOT = "thread_pool.default";
- /** the scheduler root property name */
- private static final String PROP_NAME_SCHEDULER_ROOT = "scheduler_pool";
-
- /** default scheduler property file name */
- private static final String DEFAULT_PROP_NAME_SCHEDULER_ROOT = "scheduler_pool.default";
-
- /**
+ /**
* You can specify the properties to be used to configure the thread pool. Setting this post
* initialization will have no effect.
*/
@@ -81,42 +113,24 @@
private static ThreadPoolManager INSTANCE = null;
/** Map of names to pools. */
- private ConcurrentHashMap<String, ExecutorService> pools;
-
- /** Map of names to scheduler pools. */
- private ConcurrentHashMap<String, ScheduledExecutorService> schedulerPools;
+ private ConcurrentHashMap<String, ThreadPoolExecutor> pools;
/**
* No instances please. This is a singleton.
*/
private ThreadPoolManager()
{
- this.pools = new ConcurrentHashMap<String, ExecutorService>();
- this.schedulerPools = new ConcurrentHashMap<String, ScheduledExecutorService>();
+ this.pools = new ConcurrentHashMap<String, ThreadPoolExecutor>();
configure();
}
/**
* Creates a pool based on the configuration info.
* <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @return A ThreadPool wrapper
+ * @param config
+ * @return A ThreadPoll wrapper
*/
- public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix)
- {
- return createPool(config, threadNamePrefix, Thread.NORM_PRIORITY);
- }
-
- /**
- * Creates a pool based on the configuration info.
- * <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @param threadPriority the priority of the created threads
- * @return A ThreadPool wrapper
- */
- public ExecutorService createPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
+ private ThreadPoolExecutor createPool( PoolConfiguration config )
{
BlockingQueue<Runnable> queue = null;
if ( config.isUseBoundary() )
@@ -143,7 +157,7 @@
config.getKeepAliveTime(),
TimeUnit.MILLISECONDS,
queue,
- new DaemonThreadFactory(threadNamePrefix, threadPriority));
+ new DaemonThreadFactory("JCS-ThreadPoolManager-"));
// when blocked policy
switch (config.getWhenBlockedPolicy())
@@ -173,23 +187,6 @@
}
/**
- * Creates a scheduler pool based on the configuration info.
- * <p>
- * @param config the pool configuration
- * @param threadNamePrefix prefix for the thread names of the pool
- * @param threadPriority the priority of the created threads
- * @return A ScheduledExecutorService
- */
- public ScheduledExecutorService createSchedulerPool( PoolConfiguration config, String threadNamePrefix, int threadPriority )
- {
- ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(
- config.getMaximumPoolSize(),
- new DaemonThreadFactory(threadNamePrefix, threadPriority));
-
- return scheduler;
- }
-
- /**
* Returns a configured instance of the ThreadPoolManger To specify a configuration file or
* Properties object to use call the appropriate setter prior to calling getInstance.
* <p>
@@ -211,46 +208,34 @@
{
if ( INSTANCE != null )
{
- for ( ExecutorService pool : INSTANCE.pools.values() )
+ for ( String poolName : INSTANCE.getPoolNames())
{
try
{
- pool.shutdownNow();
+ INSTANCE.getPool(poolName).shutdownNow();
}
catch (Throwable t)
{
- log.warn("Failed to close pool " + pool, t);
+ log.warn("Failed to close pool " + poolName, t);
}
}
-
- for ( ScheduledExecutorService pool : INSTANCE.schedulerPools.values() )
- {
- try
- {
- pool.shutdownNow();
- }
- catch (Throwable t)
- {
- log.warn("Failed to close pool " + pool, t);
- }
- }
-
+
INSTANCE = null;
}
}
/**
- * Returns an executor service by name. If a service by this name does not exist in the configuration file or
+ * Returns a pool by name. If a pool by this name does not exist in the configuration file or
* properties, one will be created using the default values.
* <p>
- * Services are lazily created.
+ * Pools are lazily created.
* <p>
* @param name
- * @return The executor service configured for the name.
+ * @return The thread pool configured for the name.
*/
- public ExecutorService getExecutorService( String name )
+ public ThreadPoolExecutor getPool( String name )
{
- ExecutorService pool = pools.get( name );
+ ThreadPoolExecutor pool = pools.get( name );
if ( pool == null )
{
@@ -260,17 +245,12 @@
}
PoolConfiguration config = loadConfig( PROP_NAME_ROOT + "." + name );
- ExecutorService _pool = createPool( config, "JCS-ThreadPoolManager-" + name + "-" );
- pool = pools.putIfAbsent( name, _pool );
- if (pool == null)
+ pool = createPool( config );
+ ThreadPoolExecutor _pool = pools.putIfAbsent( name, pool );
+ if (_pool != null)
{
pool = _pool;
}
- else
- {
- // already created in another thread
- _pool.shutdownNow();
- }
if ( log.isDebugEnabled() )
{
@@ -280,61 +260,6 @@
return pool;
}
-
- /**
- * Returns a pool by name. If a pool by this name does not exist in the configuration file or
- * properties, one will be created using the default values.
- * <p>
- * Pools are lazily created.
- * <p>
- * @param name
- * @return The thread pool configured for the name.
- *
- * @deprecated Use getExecutorService() instead
- */
- @Deprecated
- public ThreadPoolExecutor getPool( String name )
- {
- return (ThreadPoolExecutor) getExecutorService(name);
- }
-
- /**
- * Returns a scheduler pool by name. If a pool by this name does not exist in the configuration file or
- * properties, one will be created using the default values.
- * <p>
- * Pools are lazily created.
- * <p>
- * @param name
- * @return The scheduler pool configured for the name.
- */
- public ScheduledExecutorService getSchedulerPool( String name )
- {
- ScheduledExecutorService pool = schedulerPools.get( name );
-
- if ( pool == null )
- {
- if ( log.isDebugEnabled() )
- {
- log.debug( "Creating scheduler pool for name [" + name + "]" );
- }
-
- PoolConfiguration defaultSchedulerConfig = loadConfig( DEFAULT_PROP_NAME_SCHEDULER_ROOT );
- PoolConfiguration config = loadConfig( PROP_NAME_SCHEDULER_ROOT + "." + name, defaultSchedulerConfig );
- ScheduledExecutorService _pool = createSchedulerPool( config, "JCS-ThreadPoolManager-" + name + "-", Thread.NORM_PRIORITY );
- pool = schedulerPools.putIfAbsent( name, _pool );
- if (pool == null)
- {
- pool = _pool;
- }
- else
- {
- // already created in another thread
- _pool.shutdownNow();
- }
- }
-
- return pool;
- }
/**
* Returns the names of all configured pools.
@@ -360,7 +285,7 @@
/**
* Initialize the ThreadPoolManager and create all the pools defined in the configuration.
*/
- private void configure()
+ private static void configure()
{
if ( log.isDebugEnabled() )
{
@@ -375,36 +300,88 @@
// set intial default and then override if new
// settings are available
- defaultConfig = new PoolConfiguration();
+ defaultConfig = new PoolConfiguration( useBoundary_DEFAULT, boundarySize_DEFAULT, maximumPoolSize_DEFAULT,
+ minimumPoolSize_DEFAULT, keepAliveTime_DEFAULT,
+ whenBlockedPolicy_DEFAULT, startUpSize_DEFAULT );
+
defaultConfig = loadConfig( DEFAULT_PROP_NAME_ROOT );
}
/**
- * Configures the PoolConfiguration settings.
+ * Configures the default PoolConfiguration settings.
* <p>
- * @param root the configuration key prefix
+ * @param root
* @return PoolConfiguration
*/
- private PoolConfiguration loadConfig( String root )
+ private static PoolConfiguration loadConfig( String root )
{
- return loadConfig(root, defaultConfig);
- }
-
- /**
- * Configures the PoolConfiguration settings.
- * <p>
- * @param root the configuration key prefix
- * @param defaultPoolConfiguration the default configuration
- * @return PoolConfiguration
- */
- private PoolConfiguration loadConfig( String root, PoolConfiguration defaultPoolConfiguration )
- {
- PoolConfiguration config = defaultPoolConfiguration.clone();
- PropertySetter.setProperties( config, props, root + "." );
+ PoolConfiguration config = defaultConfig.clone();
- if ( log.isDebugEnabled() )
+ try
{
- log.debug( root + " PoolConfiguration = " + config );
+ config.setUseBoundary( Boolean.parseBoolean( props.getProperty( root + ".useBoundary", "false" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "useBoundary not a boolean.", nfe );
+ }
+
+ // load default if they exist
+ try
+ {
+ config.setBoundarySize( Integer.parseInt( props.getProperty( root + ".boundarySize", "2000" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "boundarySize not a number.", nfe );
+ }
+
+ // maximum pool size
+ try
+ {
+ config.setMaximumPoolSize( Integer.parseInt( props.getProperty( root + ".maximumPoolSize", "150" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "maximumPoolSize not a number.", nfe );
+ }
+
+ // minimum pool size
+ try
+ {
+ config.setMinimumPoolSize( Integer.parseInt( props.getProperty( root + ".minimumPoolSize", "4" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "minimumPoolSize not a number.", nfe );
+ }
+
+ // keep alive
+ try
+ {
+ config.setKeepAliveTime( Integer.parseInt( props.getProperty( root + ".keepAliveTime", "300000" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "keepAliveTime not a number.", nfe );
+ }
+
+ // when blocked
+ config.setWhenBlockedPolicy( props.getProperty( root + ".whenBlockedPolicy", "RUN" ) );
+
+ // startupsize
+ try
+ {
+ config.setStartUpSize( Integer.parseInt( props.getProperty( root + ".startUpSize", "4" ) ) );
+ }
+ catch ( NumberFormatException nfe )
+ {
+ log.error( "startUpSize not a number.", nfe );
+ }
+
+ if ( log.isInfoEnabled() )
+ {
+ log.info( root + " PoolConfiguration = " + config );
}
return config;
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
index 231841a..fe671ae 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/auxiliary/remote/RemoteCacheNoWaitUnitTest.java
@@ -1,16 +1,5 @@
package org.apache.commons.jcs.auxiliary.remote;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.commons.jcs.engine.CacheElement;
-import org.apache.commons.jcs.engine.CacheStatus;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.utils.timing.SleepUtil;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -31,6 +20,16 @@
*/
import junit.framework.TestCase;
+import org.apache.commons.jcs.engine.CacheElement;
+import org.apache.commons.jcs.engine.CacheStatus;
+import org.apache.commons.jcs.engine.behavior.ICacheElement;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs.utils.timing.SleepUtil;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
/**
* Unit tests for the remote cache no wait. The no wait manages a queue on top of the client.
@@ -199,7 +198,7 @@
// DO WORK
noWait.update( element );
SleepUtil.sleepAtLeast( 10 );
- // ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
+ ICacheEventQueue<String, String> originalQueue = noWait.getCacheEventQueue();
noWait.fixCache( service );
@@ -209,7 +208,7 @@
// VERIFY
assertEquals( "Wrong status", service, client.fixed );
- // assertFalse( "Original queue should not alive", originalQueue.isAlive() );
+ assertFalse( "Original queue should not alive", originalQueue.isAlive() );
assertTrue( "New queue should be alive." + newQueue, newQueue.isAlive() );
}
}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
index 60b72f3..3925b63 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/CacheEventQueueFactoryUnitTest.java
@@ -1,10 +1,5 @@
package org.apache.commons.jcs.engine;
-import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
-import org.apache.commons.jcs.engine.behavior.ICacheEventQueue.QueueType;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -25,6 +20,10 @@
*/
import junit.framework.TestCase;
+import org.apache.commons.jcs.auxiliary.remote.MockRemoteCacheListener;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue;
+import org.apache.commons.jcs.engine.behavior.ICacheEventQueue.QueueType;
+import org.apache.commons.jcs.engine.behavior.ICacheListener;
/** Unit tests for the CacheEventQueueFactory */
public class CacheEventQueueFactoryUnitTest
@@ -45,7 +44,7 @@
// VERIFY
assertNotNull( "Should have a result", result );
- assertTrue( "Wrong type", result.getQueueType() == QueueType.SINGLE );
+ assertTrue( "Wrong type", result instanceof CacheEventQueue );
}
/** Test create */
@@ -63,6 +62,6 @@
// VERIFY
assertNotNull( "Should have a result", result );
- assertTrue( "Wrong type", result.getQueueType() == QueueType.POOLED );
+ assertTrue( "Wrong type", result instanceof PooledCacheEventQueue );
}
}
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
index 799ebf4..8aa4bb8 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/engine/EventQueueConcurrentLoadTest.java
@@ -21,13 +21,13 @@
import java.io.IOException;
-import org.apache.commons.jcs.engine.behavior.ICacheElement;
-import org.apache.commons.jcs.engine.behavior.ICacheListener;
-
import junit.extensions.ActiveTestSuite;
import junit.framework.Test;
import junit.framework.TestCase;
+import org.apache.commons.jcs.engine.behavior.ICacheElement;
+import org.apache.commons.jcs.engine.behavior.ICacheListener;
+
/**
* This test case is designed to makes sure there are no deadlocks in the event queue. The time to
* live should be set to a very short interval to make a deadlock more likely.
@@ -109,6 +109,16 @@
}
} );
+ suite.addTest( new EventQueueConcurrentLoadTest( "testStopProcessing1" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runStopProcessingTest();
+ }
+ } );
+
suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutTest4" )
{
@Override
@@ -129,6 +139,16 @@
}
} );
+ suite.addTest( new EventQueueConcurrentLoadTest( "testStopProcessing2" )
+ {
+ @Override
+ public void runTest()
+ throws Exception
+ {
+ this.runStopProcessingTest();
+ }
+ } );
+
suite.addTest( new EventQueueConcurrentLoadTest( "testRunPutDelayTest" )
{
@Override
@@ -202,6 +222,16 @@
}
/**
+ * Add remove events to the event queue.
+ * @throws Exception
+ */
+ public void runStopProcessingTest()
+ throws Exception
+ {
+ queue.stopProcessing();
+ }
+
+ /**
* Test putting and a delay. Waits until queue is empty to start.
* @param end
* @param expectedPutCount
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
index 6ce5625..09b6005 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapConcurrentUnitTest.java
@@ -1,7 +1,5 @@
package org.apache.commons.jcs.utils.struct;
-import java.util.Iterator;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -25,6 +23,8 @@
import junit.framework.TestCase;
import junit.framework.TestSuite;
+import java.util.Iterator;
+
/**
* Tests the LRUMap
*
@@ -150,6 +150,7 @@
{
int total = 10;
LRUMap<String, String> map = new LRUMap<String, String>( total );
+ map.setChunkSize( 1 );
// put the max in
for ( int i = 0; i < total; i++ )
@@ -188,6 +189,7 @@
{
int total = 10000;
LRUMap<String, String> map = new LRUMap<String, String>( total );
+ map.setChunkSize( 1 );
// put the max in
for ( int i = 0; i < total * 2; i++ )
@@ -199,6 +201,7 @@
for ( int i = total - 1; i >= 0; i-- )
{
assertNull( map.get( i + ":key" ) );
+
}
// get the total to total *2 items out, these should be found.
@@ -209,6 +212,7 @@
}
// System.out.println( map.getStatistics() );
+
}
/**
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
index e11d7ab..bbf851f 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/struct/LRUMapPerformanceTest.java
@@ -1,9 +1,5 @@
package org.apache.commons.jcs.utils.struct;
-import java.util.Map;
-
-import org.apache.commons.jcs.JCSvsHashtablePerformanceTest;
-
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -26,6 +22,9 @@
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
+import org.apache.commons.jcs.JCSvsHashtablePerformanceTest;
+
+import java.util.Map;
/**
* This ensures that the jcs version of the LRU map is as fast as the commons
@@ -107,7 +106,7 @@
try
{
- LRUMap<String, String> cache = new LRUMap<String, String>( tries );
+ Map<String, String> cache = new LRUMap<String, String>( tries );
for ( int j = 0; j < loops; j++ )
{
@@ -135,12 +134,9 @@
System.out.println( name + " get time for " + tries + " = " + time + "; millis per = " + tPer );
///////////////////////////////////////////////////////////////
- cache2Name = "LRUMap (commons)";
+ cache2Name = "LRUMapJCS (commons)";
//or LRUMapJCS
Map<String, String> cache2 = new org.apache.commons.collections4.map.LRUMap<String, String>( tries );
-// Map<String, String> cache2 = new ConcurrentLinkedHashMap.Builder<String, String>()
-// .maximumWeightedCapacity( tries )
-// .build();
//cache2Name = "Hashtable";
//Hashtable cache2 = new Hashtable();
start = System.currentTimeMillis();
diff --git a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
index 1c89cc5..e2210a1 100644
--- a/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
+++ b/commons-jcs-core/src/test/java/org/apache/commons/jcs/utils/threadpool/ThreadPoolManagerUnitTest.java
@@ -21,14 +21,12 @@
import java.util.ArrayList;
import java.util.Properties;
-import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-
-import org.apache.commons.jcs.utils.props.PropertyLoader;
import junit.framework.TestCase;
+import org.apache.commons.jcs.utils.props.PropertyLoader;
+
/**
* Verify that the manager can create pools as intended by the default and
* specified file names.
@@ -65,39 +63,6 @@
}
/**
- * Make sure it can load a certain configuration
- */
- public void testSpecialConfig()
- {
- Properties props = PropertyLoader.loadProperties( "thread_pool.properties" );
- ThreadPoolManager.setProps( props );
- ThreadPoolManager mgr = ThreadPoolManager.getInstance();
- assertNotNull( mgr );
-
- ThreadPoolExecutor pool = mgr.getPool( "aborttest" );
- assertNotNull( pool );
-
- int poolSize = pool.getCorePoolSize();
- int expectedPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.startUpSize" ) );
- assertEquals( expectedPoolSize, poolSize);
-
- int minPoolSize = pool.getPoolSize();
- int expectedMinPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.minimumPoolSize" ) );
- assertEquals( expectedMinPoolSize, minPoolSize );
-
- int maxPoolSize = pool.getMaximumPoolSize();
- int expectedMaxPoolSize = Integer.parseInt( props.getProperty( "thread_pool.aborttest.maximumPoolSize" ) );
- assertEquals( expectedMaxPoolSize, maxPoolSize );
-
- long keepAliveTime = pool.getKeepAliveTime(TimeUnit.MILLISECONDS);
- long expectedKeepAliveTime = Long.parseLong( props.getProperty( "thread_pool.aborttest.keepAliveTime" ) );
- assertEquals( expectedKeepAliveTime, keepAliveTime );
-
- RejectedExecutionHandler whenBlockedPolicy = pool.getRejectedExecutionHandler();
- assertTrue( whenBlockedPolicy instanceof ThreadPoolExecutor.AbortPolicy );
- }
-
- /**
* Try to get an undefined pool from an existing default file.
*/
public void testDefaultConfigUndefinedPool()
@@ -126,10 +91,10 @@
assertNotNull( mgr );
String poolName1 = "testGetPoolNames1";
- mgr.getExecutorService( poolName1 );
+ mgr.getPool( poolName1 );
String poolName2 = "testGetPoolNames2";
- mgr.getExecutorService( poolName2 );
+ mgr.getPool( poolName2 );
ArrayList<String> names = mgr.getPoolNames();
assertTrue( "Should have name in list.", names.contains( poolName1 ) );
diff --git a/commons-jcs-core/src/test/test-conf/thread_pool.properties b/commons-jcs-core/src/test/test-conf/thread_pool.properties
index b6a3326..cbf5284 100644
--- a/commons-jcs-core/src/test/test-conf/thread_pool.properties
+++ b/commons-jcs-core/src/test/test-conf/thread_pool.properties
@@ -44,13 +44,13 @@
thread_pool.maxtest.whenBlockedPolicy=RUN
thread_pool.maxtest.startUpSize=5
-# abort test thread pool config
-thread_pool.aborttest.boundarySize=1
-thread_pool.aborttest.maximumPoolSize=11
-thread_pool.aborttest.minimumPoolSize=1
-thread_pool.aborttest.keepAliveTime=1
-thread_pool.aborttest.whenBlockedPolicy=ABORT
-thread_pool.aborttest.startUpSize=1
+# wait test thread pool config
+thread_pool.waittest.boundarySize=1
+thread_pool.waittest.maximumPoolSize=11
+thread_pool.waittest.minimumPoolSize=1
+thread_pool.waittest.keepAliveTime=1
+thread_pool.waittest.whenBlockedPolicy=WAIT
+thread_pool.waittest.startUpSize=1
# with boundary test thread pool config
thread_pool.withbound.useBoundary=true
@@ -58,7 +58,7 @@
thread_pool.withbound.maximumPoolSize=11
thread_pool.withbound.minimumPoolSize=1
thread_pool.withbound.keepAliveTime=1
-thread_pool.withbound.whenBlockedPolicy=ABORT
+thread_pool.withbound.whenBlockedPolicy=WAIT
thread_pool.withbound.startUpSize=1
@@ -68,5 +68,5 @@
thread_pool.nobound.maximumPoolSize=11
thread_pool.nobound.minimumPoolSize=1
thread_pool.nobound.keepAliveTime=1
-thread_pool.nobound.whenBlockedPolicy=ABORT
+thread_pool.nobound.whenBlockedPolicy=WAIT
thread_pool.nobound.startUpSize=1
diff --git a/commons-jcs-dist/pom.xml b/commons-jcs-dist/pom.xml
index 559b600..0991542 100644
--- a/commons-jcs-dist/pom.xml
+++ b/commons-jcs-dist/pom.xml
@@ -32,9 +32,9 @@
<description>Creates the Apache Commons JCS multimodule distribution.</description>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-dist</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-dist</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-dist</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-dist</url>
</scm>
<!-- NOTE: These dependency declarations are only required to sort this project to the
diff --git a/commons-jcs-jcache-extras/pom.xml b/commons-jcs-jcache-extras/pom.xml
index 091cbea..741923f 100644
--- a/commons-jcs-jcache-extras/pom.xml
+++ b/commons-jcs-jcache-extras/pom.xml
@@ -30,9 +30,9 @@
<name>Apache Commons JCS :: JCache Extras</name>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-extras</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-extras</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache-extras</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-extras</url>
</scm>
<dependencies>
diff --git a/commons-jcs-jcache-openjpa/pom.xml b/commons-jcs-jcache-openjpa/pom.xml
index a83133b..b7efa57 100644
--- a/commons-jcs-jcache-openjpa/pom.xml
+++ b/commons-jcs-jcache-openjpa/pom.xml
@@ -30,9 +30,9 @@
<name>Apache Commons JCS :: JCache OpenJPA</name>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache-openjpa</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache-openjpa</url>
</scm>
<dependencies>
diff --git a/commons-jcs-jcache/pom.xml b/commons-jcs-jcache/pom.xml
index 15d2c8d..b6fb71e 100644
--- a/commons-jcs-jcache/pom.xml
+++ b/commons-jcs-jcache/pom.xml
@@ -32,9 +32,9 @@
<name>Apache Commons JCS :: JCache</name>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-jcache</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-jcache</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-jcache</url>
</scm>
<dependencies>
diff --git a/commons-jcs-tck-tests/pom.xml b/commons-jcs-tck-tests/pom.xml
index 7ecb150..4e61e0b 100644
--- a/commons-jcs-tck-tests/pom.xml
+++ b/commons-jcs-tck-tests/pom.xml
@@ -39,9 +39,9 @@
<name>Apache Commons JCS :: JCache TCK</name>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-tck-tests</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk/commons-jcs-tck-tests</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk/commons-jcs-tck-tests</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC/commons-jcs-tck-tests</url>
</scm>
<properties>
diff --git a/pom.xml b/pom.xml
index c51c573..094c6b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,9 +51,9 @@
</issueManagement>
<scm>
- <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/trunk</connection>
- <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/trunk</developerConnection>
- <url>http://svn.apache.org/viewvc/commons/proper/jcs/trunk</url>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC</connection>
+ <developerConnection>scm:svn:https://svn.apache.org/repos/asf/commons/proper/jcs/branches/commons-jcs-2.1-RC</developerConnection>
+ <url>http://svn.apache.org/viewvc/commons/proper/jcs/branches/commons-jcs-2.1-RC</url>
</scm>
<mailingLists>
@@ -519,8 +519,8 @@
<maven.compiler.target>1.6</maven.compiler.target>
<commons.componentid>jcs</commons.componentid>
- <commons.release.version>2.0</commons.release.version>
- <commons.release.name>commons-jcs-dist-2.0</commons.release.name>
+ <commons.release.version>2.1</commons.release.version>
+ <commons.release.name>commons-jcs-dist-2.1</commons.release.name>
<commons.release.desc>(Java 6.0+)</commons.release.desc>
<!-- The RC version used in the staging repository URL. -->
<commons.rc.version>RC1</commons.rc.version>