You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2011/05/02 15:59:46 UTC
svn commit: r1098574 - in /camel/trunk/camel-core/src:
main/java/org/apache/camel/ main/java/org/apache/camel/component/bean/
main/java/org/apache/camel/component/properties/
main/java/org/apache/camel/impl/ main/java/org/apache/camel/impl/converter/
m...
Author: davsclaus
Date: Mon May 2 13:59:45 2011
New Revision: 1098574
URL: http://svn.apache.org/viewvc?rev=1098574&view=rev
Log:
CAMEL-3922: Added LRUSoftCache for soft reference cache. This is more ideal cache for the JVM so it can GC values in case its low on memory.
Added:
camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedConsumerCache.java
- copied, changed from r1098295, camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProducerCache.java
camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUSoftCache.java
- copied, changed from r1098295, camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUCache.java
camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedConsumerCacheTest.java
- copied, changed from r1098295, camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedProducerCacheTest.java
camel/trunk/camel-core/src/test/java/org/apache/camel/util/LRUSoftCacheTest.java
Modified:
camel/trunk/camel-core/src/main/java/org/apache/camel/CamelContext.java
camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfoCache.java
camel/trunk/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ConsumerCache.java
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultConsumerTemplate.java
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/EndpointRegistry.java
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ProducerCache.java
camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java
camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
camel/trunk/camel-core/src/test/java/org/apache/camel/impl/DefaultConsumerCacheTest.java
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/CamelContext.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/CamelContext.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/CamelContext.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/CamelContext.java Mon May 2 13:59:45 2011
@@ -626,8 +626,6 @@ public interface CamelContext extends Su
/**
* Creates a new {@link ProducerTemplate} which is <b>started</b> and therefore ready to use right away.
* <p/>
- * You <b>must</b> start the template before its being used.
- * <p/>
* See this FAQ before use: <a href="http://camel.apache.org/why-does-camel-use-too-many-threads-with-producertemplate.html">
* Why does Camel use too many threads with ProducerTemplate?</a>
*
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfoCache.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfoCache.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfoCache.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/bean/MethodInfoCache.java Mon May 2 13:59:45 2011
@@ -21,11 +21,11 @@ import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.util.CastUtils;
-import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUSoftCache;
/**
* Represents a cache of {@link MethodInfo} objects to avoid the expense of introspection for each
- * invocation of a method via a proxy,
+ * invocation of a method via a proxy.
*
* @version
*/
@@ -77,7 +77,8 @@ public class MethodInfoCache {
}
protected static Map<Object, Object> createLruCache(int size) {
- return new LRUCache<Object, Object>(size);
+ // use a soft cache
+ return new LRUSoftCache<Object, Object>(size);
}
private static Map<Class<?>, BeanInfo> createClassCache(int size) {
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/component/properties/PropertiesComponent.java Mon May 2 13:59:45 2011
@@ -25,6 +25,7 @@ import org.apache.camel.Endpoint;
import org.apache.camel.impl.DefaultComponent;
import org.apache.camel.util.LRUCache;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -144,8 +145,14 @@ public class PropertiesComponent extends
}
@Override
+ protected void doStart() throws Exception {
+ ServiceHelper.startService(cacheMap);
+ super.doStart();
+ }
+
+ @Override
protected void doStop() throws Exception {
- cacheMap.clear();
+ ServiceHelper.stopService(cacheMap);
super.doStop();
}
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ConsumerCache.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ConsumerCache.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ConsumerCache.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ConsumerCache.java Mon May 2 13:59:45 2011
@@ -26,6 +26,7 @@ import org.apache.camel.IsSingleton;
import org.apache.camel.PollingConsumer;
import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUSoftCache;
import org.apache.camel.util.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,18 +40,33 @@ public class ConsumerCache extends Servi
private static final transient Logger LOG = LoggerFactory.getLogger(ConsumerCache.class);
private final CamelContext camelContext;
private final Map<String, PollingConsumer> consumers;
+ private final Object source;
- public ConsumerCache(CamelContext camelContext) {
- this(camelContext, CamelContextHelper.getMaximumCachePoolSize(camelContext));
+ public ConsumerCache(Object source, CamelContext camelContext) {
+ this(source, camelContext, CamelContextHelper.getMaximumCachePoolSize(camelContext));
}
- public ConsumerCache(CamelContext camelContext, int maximumCacheSize) {
- this(camelContext, new LRUCache<String, PollingConsumer>(maximumCacheSize));
+ public ConsumerCache(Object source, CamelContext camelContext, int cacheSize) {
+ this(source, camelContext, createLRUCache(cacheSize));
}
- public ConsumerCache(CamelContext camelContext, Map<String, PollingConsumer> cache) {
+ public ConsumerCache(Object source, CamelContext camelContext, Map<String, PollingConsumer> cache) {
this.camelContext = camelContext;
this.consumers = cache;
+ this.source = source;
+ }
+
+ /**
+ * Creates the {@link LRUCache} to be used.
+ * <p/>
+ * This implementation returns a {@link org.apache.camel.util.LRUSoftCache} instance.
+
+ * @param cacheSize the cache size
+ * @return the cache
+ */
+ protected static LRUCache<String, PollingConsumer> createLRUCache(int cacheSize) {
+ // We use a soft reference cache to allow the JVM to re-claim memory if it runs low on memory.
+ return new LRUSoftCache<String, PollingConsumer>(cacheSize);
}
public synchronized PollingConsumer getConsumer(Endpoint endpoint) {
@@ -104,22 +120,56 @@ public class ConsumerCache extends Servi
return camelContext;
}
- protected void doStart() throws Exception {
- ServiceHelper.startServices(consumers);
+ /**
+ * Gets the source which uses this cache
+ *
+ * @return the source
+ */
+ public Object getSource() {
+ return source;
}
- protected void doStop() throws Exception {
- ServiceHelper.stopServices(consumers);
- consumers.clear();
+ /**
+ * Returns the current size of the cache
+ *
+ * @return the current size
+ */
+ public int size() {
+ int size = consumers.size();
+ LOG.trace("size = {}", size);
+ return size;
}
/**
- * Returns the current size of the consumer cache
+ * Gets the maximum cache size (capacity).
+ * <p/>
+ * Will return <tt>-1</tt> if it cannot determine this if a custom cache was used.
*
- * @return the current size
+ * @return the capacity
+ */
+ public int getCapacity() {
+ int capacity = -1;
+ if (consumers instanceof LRUCache) {
+ LRUCache cache = (LRUCache) consumers;
+ capacity = cache.getMaxCacheSize();
+ }
+ return capacity;
+ }
+
+ /**
+ * Purges this cache
*/
- int size() {
- return consumers.size();
+ public synchronized void purge() {
+ consumers.clear();
+ }
+
+ protected void doStart() throws Exception {
+ ServiceHelper.startServices(consumers);
+ }
+
+ protected void doStop() throws Exception {
+ ServiceHelper.stopServices(consumers);
+ consumers.clear();
}
}
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultConsumerTemplate.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultConsumerTemplate.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultConsumerTemplate.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/DefaultConsumerTemplate.java Mon May 2 13:59:45 2011
@@ -254,9 +254,9 @@ public class DefaultConsumerTemplate ext
protected void doStart() throws Exception {
if (consumerCache == null) {
if (maximumCacheSize > 0) {
- consumerCache = new ConsumerCache(context, maximumCacheSize);
+ consumerCache = new ConsumerCache(this, context, maximumCacheSize);
} else {
- consumerCache = new ConsumerCache(context);
+ consumerCache = new ConsumerCache(this, context);
}
}
ServiceHelper.startService(consumerCache);
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/EndpointRegistry.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/EndpointRegistry.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/EndpointRegistry.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/EndpointRegistry.java Mon May 2 13:59:45 2011
@@ -21,14 +21,16 @@ import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.util.CamelContextHelper;
-import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUSoftCache;
/**
- * Endpoint registry which is a based on a {@link org.apache.camel.util.LRUCache}.
+ * Endpoint registry which is a based on a {@link org.apache.camel.util.LRUSoftCache}.
+ * <p/>
+ * We use a soft reference cache to allow the JVM to re-claim memory if it runs low on memory.
*
* @version
*/
-public class EndpointRegistry extends LRUCache<EndpointKey, Endpoint> {
+public class EndpointRegistry extends LRUSoftCache<EndpointKey, Endpoint> {
private final CamelContext context;
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ProducerCache.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ProducerCache.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ProducerCache.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/ProducerCache.java Mon May 2 13:59:45 2011
@@ -36,6 +36,7 @@ import org.apache.camel.spi.ServicePool;
import org.apache.camel.util.CamelContextHelper;
import org.apache.camel.util.EventHelper;
import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUSoftCache;
import org.apache.camel.util.ServiceHelper;
import org.apache.camel.util.StopWatch;
import org.slf4j.Logger;
@@ -59,7 +60,7 @@ public class ProducerCache extends Servi
}
public ProducerCache(Object source, CamelContext camelContext, int cacheSize) {
- this(source, camelContext, camelContext.getProducerServicePool(), new LRUCache<String, Producer>(cacheSize));
+ this(source, camelContext, camelContext.getProducerServicePool(), createLRUCache(cacheSize));
}
public ProducerCache(Object source, CamelContext camelContext, ServicePool<Endpoint, Producer> producerServicePool, Map<String, Producer> cache) {
@@ -68,7 +69,20 @@ public class ProducerCache extends Servi
this.pool = producerServicePool;
this.producers = cache;
}
-
+
+ /**
+ * Creates the {@link LRUCache} to be used.
+ * <p/>
+ * This implementation returns a {@link LRUSoftCache} instance.
+
+ * @param cacheSize the cache size
+ * @return the cache
+ */
+ protected static LRUCache<String, Producer> createLRUCache(int cacheSize) {
+ // We use a soft reference cache to allow the JVM to re-claim memory if it runs low on memory.
+ return new LRUSoftCache<String, Producer>(cacheSize);
+ }
+
public CamelContext getCamelContext() {
return camelContext;
}
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/impl/converter/PropertyEditorTypeConverter.java Mon May 2 13:59:45 2011
@@ -24,8 +24,9 @@ import java.util.Map;
import org.apache.camel.Exchange;
import org.apache.camel.Service;
import org.apache.camel.TypeConverter;
-import org.apache.camel.util.LRUCache;
+import org.apache.camel.util.LRUSoftCache;
import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.ServiceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,9 +39,9 @@ import org.slf4j.LoggerFactory;
public class PropertyEditorTypeConverter implements TypeConverter, Service {
private static final Logger LOG = LoggerFactory.getLogger(PropertyEditorTypeConverter.class);
- // use a bound cache to avoid using too much memory in case a lot of different classes
+ // use a soft bound cache to avoid using too much memory in case a lot of different classes
// is being converted to string
- private final Map<Class, Class> misses = new LRUCache<Class, Class>(1000);
+ private final Map<Class, Class> misses = new LRUSoftCache<Class, Class>(1000);
// we don't anticipate so many property editors so we have unbounded map
private final Map<Class, PropertyEditor> cache = new HashMap<Class, PropertyEditor>();
@@ -116,11 +117,12 @@ public class PropertyEditorTypeConverter
}
public void start() throws Exception {
+ ServiceHelper.startService(misses);
}
public void stop() throws Exception {
cache.clear();
- misses.clear();
+ ServiceHelper.stopService(misses);
}
}
Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/management/DefaultManagementLifecycleStrategy.java Mon May 2 13:59:45 2011
@@ -41,6 +41,7 @@ import org.apache.camel.Service;
import org.apache.camel.VetoCamelContextStartException;
import org.apache.camel.builder.ErrorHandlerBuilder;
import org.apache.camel.component.bean.BeanProcessor;
+import org.apache.camel.impl.ConsumerCache;
import org.apache.camel.impl.DefaultCamelContextNameStrategy;
import org.apache.camel.impl.EndpointRegistry;
import org.apache.camel.impl.EventDrivenConsumerRoute;
@@ -53,6 +54,7 @@ import org.apache.camel.management.mbean
import org.apache.camel.management.mbean.ManagedCamelContext;
import org.apache.camel.management.mbean.ManagedComponent;
import org.apache.camel.management.mbean.ManagedConsumer;
+import org.apache.camel.management.mbean.ManagedConsumerCache;
import org.apache.camel.management.mbean.ManagedDelayer;
import org.apache.camel.management.mbean.ManagedEndpoint;
import org.apache.camel.management.mbean.ManagedEndpointRegistry;
@@ -407,6 +409,8 @@ public class DefaultManagementLifecycleS
return getManagedObjectForProcessor(context, (Processor) service, route);
} else if (service instanceof ThrottlingInflightRoutePolicy) {
answer = new ManagedThrottlingInflightRoutePolicy(context, (ThrottlingInflightRoutePolicy) service);
+ } else if (service instanceof ConsumerCache) {
+ answer = new ManagedConsumerCache(context, (ConsumerCache) service);
} else if (service instanceof ProducerCache) {
answer = new ManagedProducerCache(context, (ProducerCache) service);
} else if (service instanceof EndpointRegistry) {
Copied: camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedConsumerCache.java (from r1098295, camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProducerCache.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedConsumerCache.java?p2=camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedConsumerCache.java&p1=camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProducerCache.java&r1=1098295&r2=1098574&rev=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedProducerCache.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/management/mbean/ManagedConsumerCache.java Mon May 2 13:59:45 2011
@@ -17,7 +17,7 @@
package org.apache.camel.management.mbean;
import org.apache.camel.CamelContext;
-import org.apache.camel.impl.ProducerCache;
+import org.apache.camel.impl.ConsumerCache;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
@@ -25,40 +25,40 @@ import org.springframework.jmx.export.an
/**
* @version
*/
-@ManagedResource(description = "Managed ProducerCache")
-public class ManagedProducerCache extends ManagedService {
- private final ProducerCache producerCache;
+@ManagedResource(description = "Managed ConsumerCache")
+public class ManagedConsumerCache extends ManagedService {
+ private final ConsumerCache consumerCache;
- public ManagedProducerCache(CamelContext context, ProducerCache producerCache) {
- super(context, producerCache);
- this.producerCache = producerCache;
+ public ManagedConsumerCache(CamelContext context, ConsumerCache consumerCache) {
+ super(context, consumerCache);
+ this.consumerCache = consumerCache;
}
- public ProducerCache getProducerCache() {
- return producerCache;
+ public ConsumerCache getConsumerCache() {
+ return consumerCache;
}
@ManagedAttribute(description = "Source")
public String getSource() {
- if (producerCache.getSource() != null) {
- return producerCache.getSource().toString();
+ if (consumerCache.getSource() != null) {
+ return consumerCache.getSource().toString();
}
return null;
}
@ManagedAttribute(description = "Number of elements cached")
public Integer getSize() {
- return producerCache.size();
+ return consumerCache.size();
}
@ManagedAttribute(description = "Maximum cache size (capacity)")
public Integer getMaximumCacheSize() {
- return producerCache.getCapacity();
+ return consumerCache.getCapacity();
}
@ManagedOperation(description = "Purges the cache")
public void purge() {
- producerCache.purge();
+ consumerCache.purge();
}
}
Copied: camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUSoftCache.java (from r1098295, camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUCache.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUSoftCache.java?p2=camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUSoftCache.java&p1=camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUCache.java&r1=1098295&r2=1098574&rev=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUCache.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/util/LRUSoftCache.java Mon May 2 13:59:45 2011
@@ -16,66 +16,174 @@
*/
package org.apache.camel.util;
-import java.util.LinkedHashMap;
+import java.lang.ref.SoftReference;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.Map;
-
-import org.apache.camel.Service;
+import java.util.Set;
/**
- * A Least Recently Used Cache
+ * A Least Recently Used Cache which uses {@link SoftReference}.
+ * <p/>
+ * This implementation uses {@link java.lang.ref.SoftReference} for stored values in the cache, to support the JVM
+ * when it wants to reclaim objects when its running out of memory. Therefore this implementation does
+ * not support <b>all</b> the {@link java.util.Map} methods.
+ * <p/>
+ * The following methods is <b>only</b> be be used:
+ * <ul>
+ * <li>containsKey - To determine if the key is in the cache and refers to a value</li>
+ * <li>entrySet - To return a set of all the entries (as key/value paris)</li>
+ * <li>get - To get a value from the cache</li>
+ * <li>isEmpty - To determine if the cache contains any values</li>
+ * <li>keySet - To return a set of the current keys which refers to a value</li>
+ * <li>put - To add a value to the cache</li>
+ * <li>putAll - To add values to the cache</li>
+ * <li>remove - To remove a value from the cache by its key</li>
+ * <li>size - To get the current size</li>
+ * <li>values - To return a copy of all the value in a list</li>
+ * </ul>
+ * <p/>
+ * The {@link #containsValue(Object)} method should <b>not</b> be used as it's not adjusted to check
+ * for the existence of a value without catering for the soft references.
*
- * @version
+ * @see LRUCache
*/
-public class LRUCache<K, V> extends LinkedHashMap<K, V> implements Service {
- private static final long serialVersionUID = -342098639681884413L;
- private int maxCacheSize = 10000;
-
- public LRUCache(int maximumCacheSize) {
- this(maximumCacheSize, maximumCacheSize, 0.75f, true);
- }
-
- /**
- * Constructs an empty <tt>LRUCache</tt> instance with the
- * specified initial capacity, maximumCacheSize,load factor and ordering mode.
- *
- * @param initialCapacity the initial capacity.
- * @param maximumCacheSize the max capacity.
- * @param loadFactor the load factor.
- * @param accessOrder the ordering mode - <tt>true</tt> for
- * access-order, <tt>false</tt> for insertion-order.
- * @throws IllegalArgumentException if the initial capacity is negative
- * or the load factor is non positive.
- */
- public LRUCache(int initialCapacity, int maximumCacheSize, float loadFactor, boolean accessOrder) {
- super(initialCapacity, loadFactor, accessOrder);
- this.maxCacheSize = maximumCacheSize;
- }
-
- /**
- * Returns the maxCacheSize.
- */
- public int getMaxCacheSize() {
- return maxCacheSize;
- }
-
- protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
- return size() > maxCacheSize;
- }
-
- public void start() throws Exception {
- // noop
- }
-
- public void stop() throws Exception {
- // stop the value and clear the cache
- if (!isEmpty()) {
- ServiceHelper.stopServices(values());
- clear();
+public class LRUSoftCache<K, V> extends LRUCache<K, V> {
+
+ public LRUSoftCache(int maximumCacheSize) {
+ super(maximumCacheSize);
+ }
+
+ public LRUSoftCache(int initialCapacity, int maximumCacheSize, float loadFactor, boolean accessOrder) {
+ super(initialCapacity, maximumCacheSize, loadFactor, accessOrder);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V put(K key, V value) {
+ SoftReference<V> put = new SoftReference<V>(value);
+ SoftReference<V> prev = (SoftReference<V>) super.put(key, (V) put);
+ return prev != null ? prev.get() : null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V get(Object o) {
+ SoftReference<V> ref = (SoftReference<V>) super.get(o);
+ return ref != null ? ref.get() : null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void putAll(Map<? extends K, ? extends V> map) {
+ // do not use entrySet but copy one by one
+ for (K key : map.keySet()) {
+ put(key, map.get(key));
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V remove(Object o) {
+ SoftReference<V> ref = (SoftReference<V>) super.remove(o);
+ return ref != null ? ref.get() : null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Collection<V> values() {
+ // return a copy of all the active values
+ Collection<SoftReference<V>> col = (Collection<SoftReference<V>>) super.values();
+ Collection<V> answer = new ArrayList<V>(col.size());
+ for (SoftReference<V> ref : col) {
+ V value = ref.get();
+ if (value != null) {
+ answer.add(value);
+ }
}
+ return answer;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public int size() {
+ // only count as a size if there is a value
+ int size = 0;
+ Collection<SoftReference<V>> col = (Collection<SoftReference<V>>) super.values();
+ for (SoftReference<V> ref : col) {
+ if (ref.get() != null) {
+ size++;
+ }
+ }
+ return size;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+
+ @Override
+ public boolean containsKey(Object o) {
+ // must lookup if the key has a value, as we only regard a key to be contained
+ // if the value is still there (the JVM can remove the soft reference if it need memory)
+ return get(o) != null;
+ }
+
+ @Override
+ public Set<K> keySet() {
+ // must use a copy of the keys to avoid concurrent modifications
+ Set<K> keys = new LinkedHashSet<K>(super.keySet());
+
+ // filter out un referenced values
+ Set<K> answer = new LinkedHashSet<K>();
+ for (K key : keys) {
+ if (containsKey(key)) {
+ answer.add(key);
+ }
+ }
+ return answer;
+ }
+
+ @Override
+ public Set<Map.Entry<K, V>> entrySet() {
+ Set<Map.Entry<K, V>> original = super.entrySet();
+
+ // must use a copy to avoid concurrent modifications and be able to get/set value using
+ // the soft reference so the returned set is without the soft reference, and thus is
+ // use able for the caller to use
+ Set<Map.Entry<K, V>> answer = new LinkedHashSet<Map.Entry<K, V>>(original.size());
+ for (final Map.Entry<K, V> entry : original) {
+ Map.Entry<K, V> view = new Map.Entry<K, V>() {
+ @Override
+ public K getKey() {
+ return entry.getKey();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V getValue() {
+ SoftReference<V> ref = (SoftReference<V>) entry.getValue();
+ return ref != null ? ref.get() : null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public V setValue(V v) {
+ V put = (V) new SoftReference<V>(v);
+ SoftReference<V> prev = (SoftReference<V>) entry.setValue(put);
+ return prev != null ? prev.get() : null;
+ }
+ };
+ answer.add(view);
+ }
+
+ return answer;
}
@Override
public String toString() {
- return "LRUCache@" + ObjectHelper.getIdentityHashCode(this);
+ return "LRUSoftCache@" + ObjectHelper.getIdentityHashCode(this);
}
}
\ No newline at end of file
Modified: camel/trunk/camel-core/src/test/java/org/apache/camel/impl/DefaultConsumerCacheTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/impl/DefaultConsumerCacheTest.java?rev=1098574&r1=1098573&r2=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/impl/DefaultConsumerCacheTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/impl/DefaultConsumerCacheTest.java Mon May 2 13:59:45 2011
@@ -26,7 +26,7 @@ import org.apache.camel.PollingConsumer;
public class DefaultConsumerCacheTest extends ContextTestSupport {
public void testCacheConsumers() throws Exception {
- ConsumerCache cache = new ConsumerCache(context);
+ ConsumerCache cache = new ConsumerCache(this, context);
cache.start();
assertEquals("Size should be 0", 0, cache.size());
Copied: camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedConsumerCacheTest.java (from r1098295, camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedProducerCacheTest.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedConsumerCacheTest.java?p2=camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedConsumerCacheTest.java&p1=camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedProducerCacheTest.java&r1=1098295&r2=1098574&rev=1098574&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedProducerCacheTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/management/ManagedConsumerCacheTest.java Mon May 2 13:59:45 2011
@@ -22,34 +22,42 @@ import java.util.Set;
import javax.management.MBeanServer;
import javax.management.ObjectName;
+import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.impl.ConsumerCache;
/**
* @version
*/
-public class ManagedProducerCacheTest extends ManagementTestSupport {
+public class ManagedConsumerCacheTest extends ManagementTestSupport {
- public void testManageProducerCache() throws Exception {
- getMockEndpoint("mock:result").expectedMessageCount(1);
+ public void testManageConsumerCache() throws Exception {
+ // always register services in JMX so we can enlist our consumer template/cache
+ context.getManagementStrategy().getManagementAgent().setRegisterAlways(true);
+
+ ConsumerCache cache = new ConsumerCache(this, context);
+ context.addService(cache);
template.sendBody("direct:start", "Hello World");
- assertMockEndpointsSatisfied();
+ Exchange out = cache.getConsumer(context.getEndpoint("seda:queue")).receive(3000);
+ assertNotNull("Should got an exchange", out);
+ assertEquals("Hello World", out.getIn().getBody());
// get the stats for the route
MBeanServer mbeanServer = getMBeanServer();
Set<ObjectName> set = mbeanServer.queryNames(new ObjectName("*:type=services,*"), null);
- assertEquals(7, set.size());
+ assertEquals(8, set.size());
List<ObjectName> list = new ArrayList<ObjectName>(set);
ObjectName on = null;
for (ObjectName name : list) {
- if (name.getCanonicalName().contains("ProducerCache")) {
+ if (name.getCanonicalName().contains("ConsumerCache")) {
on = name;
break;
}
}
- assertNotNull("Should have found ProducerCache", on);
+ assertNotNull("Should have found ConsumerCache", on);
Integer max = (Integer) mbeanServer.getAttribute(on, "MaximumCacheSize");
assertEquals(1000, max.intValue());
@@ -58,7 +66,8 @@ public class ManagedProducerCacheTest ex
assertEquals(1, current.intValue());
String source = (String) mbeanServer.getAttribute(on, "Source");
- assertEquals("sendTo(Endpoint[mock://result])", source);
+ assertNotNull(source);
+ assertTrue(source.contains("testManageConsumerCache"));
// purge
mbeanServer.invoke(on, "purge", null, null);
@@ -72,7 +81,7 @@ public class ManagedProducerCacheTest ex
return new RouteBuilder() {
@Override
public void configure() throws Exception {
- from("direct:start").to("mock:result");
+ from("direct:start").to("seda:queue");
}
};
}
Added: camel/trunk/camel-core/src/test/java/org/apache/camel/util/LRUSoftCacheTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/util/LRUSoftCacheTest.java?rev=1098574&view=auto
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/util/LRUSoftCacheTest.java (added)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/util/LRUSoftCacheTest.java Mon May 2 13:59:45 2011
@@ -0,0 +1,228 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.camel.TestSupport;
+
+/**
+ *
+ */
+public class LRUSoftCacheTest extends TestSupport {
+
+ public void testLRUSoftCacheGetAndPut() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ cache.put(1, "foo");
+ cache.put(2, "bar");
+
+ assertEquals("foo", cache.get(1));
+ assertEquals("bar", cache.get(2));
+ assertEquals(null, cache.get(3));
+
+ assertEquals(2, cache.size());
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCachePutOverride() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ Object old = cache.put(1, "foo");
+ assertNull(old);
+ old = cache.put(2, "bar");
+ assertNull(old);
+
+ assertEquals("foo", cache.get(1));
+ assertEquals("bar", cache.get(2));
+
+ old = cache.put(1, "changed");
+ assertEquals("foo", old);
+ assertEquals("changed", cache.get(1));
+
+ assertEquals(2, cache.size());
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCachePutAll() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ Map<Integer, Object> map = new HashMap<Integer, Object>();
+ map.put(1, "foo");
+ map.put(2, "bar");
+
+ cache.putAll(map);
+
+ assertEquals("foo", cache.get(1));
+ assertEquals("bar", cache.get(2));
+ assertEquals(null, cache.get(3));
+ assertEquals(2, cache.size());
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCacheRemove() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ cache.put(1, "foo");
+ cache.put(2, "bar");
+
+ assertEquals("bar", cache.get(2));
+ cache.remove(2);
+ assertEquals(null, cache.get(2));
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCacheValues() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ cache.put(1, "foo");
+ cache.put(2, "bar");
+
+ Collection col = cache.values();
+ assertEquals(2, col.size());
+
+ Iterator it = col.iterator();
+ assertEquals("foo", it.next());
+ assertEquals("bar", it.next());
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCacheEmpty() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ assertTrue(cache.isEmpty());
+
+ cache.put(1, "foo");
+ assertFalse(cache.isEmpty());
+
+ cache.put(2, "bar");
+ assertFalse(cache.isEmpty());
+
+ cache.remove(2);
+ assertFalse(cache.isEmpty());
+
+ cache.clear();
+ assertTrue(cache.isEmpty());
+
+ cache.stop();
+ assertTrue(cache.isEmpty());
+ }
+
+ public void testLRUSoftCacheStopEmpty() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ assertTrue(cache.isEmpty());
+
+ cache.put(1, "foo");
+ cache.put(2, "bar");
+ assertFalse(cache.isEmpty());
+
+ cache.stop();
+ assertTrue(cache.isEmpty());
+ }
+
+ public void testLRUSoftCacheContainsKey() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ assertFalse(cache.containsKey(1));
+ cache.put(1, "foo");
+ assertTrue(cache.containsKey(1));
+
+ assertFalse(cache.containsKey(2));
+ cache.put(2, "foo");
+ assertTrue(cache.containsKey(2));
+
+ cache.stop();
+ assertFalse(cache.containsKey(1));
+ assertFalse(cache.containsKey(2));
+ }
+
+ public void testLRUSoftCacheKeySet() throws Exception {
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(1000);
+ cache.start();
+
+ cache.put(1, "foo");
+ cache.put(2, "foo");
+
+ Set<Integer> keys = cache.keySet();
+ assertEquals(2, keys.size());
+
+ Iterator<Integer> it = keys.iterator();
+ assertEquals(1, it.next().intValue());
+ assertEquals(2, it.next().intValue());
+
+ cache.stop();
+ }
+
+ public void testLRUSoftCacheNotRunOutOfMemory() throws Exception {
+ // we should not run out of memory using the soft cache
+ // if you run this test with LRUCache then you will run out of memory
+ LRUSoftCache<Integer, Object> cache = new LRUSoftCache<Integer, Object>(250);
+ cache.start();
+
+ for (int i = 0; i < 1000; i++) {
+ Object data = createData();
+ Integer key = new Integer(i);
+ log.info("Putting {}", key);
+ cache.put(key, data);
+ }
+
+ int size = cache.size();
+ log.info("Cache size {}", size);
+ assertTrue("Cache size should not be max, was: " + size, size < cache.getMaxCacheSize());
+
+ // should be the last keys
+ List<Integer> list = new ArrayList<Integer>(cache.keySet());
+ log.info("Keys: " + list);
+
+ assertTrue("Cache size should not be max, was: " + list.size(), list.size() < cache.getMaxCacheSize());
+
+ // first key should not be 0
+ int first = list.get(0).intValue();
+ assertTrue("First key should not be 0, was: " + first, first != 0);
+
+ // last key should be 999
+ assertEquals(999, list.get(list.size() - 1).intValue());
+
+ cache.stop();
+ }
+
+ private Object createData() {
+ // 1mb data
+ byte[] buf = new byte[1 * 1024 * 1024];
+ return buf;
+ }
+}