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 2022/01/14 07:39:04 UTC
[camel] branch main updated: [CAMEL-17481] Caffeine cache improvements (#6728)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new a402c15 [CAMEL-17481] Caffeine cache improvements (#6728)
a402c15 is described below
commit a402c1543eb4aeeedd80bab14983219b33a93f7a
Author: Andreas Klug <an...@de.bosch.com>
AuthorDate: Fri Jan 14 08:38:00 2022 +0100
[CAMEL-17481] Caffeine cache improvements (#6728)
* CAMEL-17481: Caffeine cache improvements
* CAMEL-17481: Caffeine cache improvements (rework)
Co-authored-by: Klug Andreas (CI/XDM1) <kg...@bosch.com>
---
.../src/main/docs/caffeine-cache-component.adoc | 4 ++
.../component/caffeine/CaffeineConstants.java | 1 +
.../caffeine/cache/CaffeineCacheEndpoint.java | 40 +++++++++-------
.../caffeine/cache/CaffeineCacheProducer.java | 18 +++++++-
.../caffeine/load/CaffeineLoadCacheEndpoint.java | 42 ++++++++++-------
.../caffeine/load/CaffeineLoadCacheProducer.java | 17 ++++++-
.../caffeine/cache/CaffeineCacheProducerTest.java | 46 +++++++++++++++++++
... CaffeineCacheRemovalListenerProducerTest.java} | 2 +-
.../caffeine/cache/MetricsStatsCounter.java | 8 ++--
.../loadcache/CaffeineLoadCacheProducerTest.java | 53 ++++++++++++++++++++++
10 files changed, 191 insertions(+), 40 deletions(-)
diff --git a/components/camel-caffeine/src/main/docs/caffeine-cache-component.adoc b/components/camel-caffeine/src/main/docs/caffeine-cache-component.adoc
index 0d33c12..543824b 100644
--- a/components/camel-caffeine/src/main/docs/caffeine-cache-component.adoc
+++ b/components/camel-caffeine/src/main/docs/caffeine-cache-component.adoc
@@ -56,6 +56,10 @@ You can use your cache with the following code:
[source,java]
------------------------------------------------------------
+
+@BindToRegistry("cache")
+Cache cache = Caffeine.newBuilder().recordStats().build();
+
@Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/CaffeineConstants.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/CaffeineConstants.java
index e5d551e..e7ad766 100644
--- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/CaffeineConstants.java
+++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/CaffeineConstants.java
@@ -32,4 +32,5 @@ public interface CaffeineConstants {
String ACTION_GET_ALL = "GET_ALL";
String ACTION_INVALIDATE = "INVALIDATE";
String ACTION_INVALIDATE_ALL = "INVALIDATE_ALL";
+ String ACTION_AS_MAP = "AS_MAP";
}
diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java
index bf64db8..521bfe5 100644
--- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java
+++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheEndpoint.java
@@ -64,27 +64,33 @@ public class CaffeineCacheEndpoint extends DefaultEndpoint {
@Override
protected void doStart() throws Exception {
+
cache = CamelContextHelper.lookup(getCamelContext(), cacheName, Cache.class);
if (cache == null) {
- Caffeine<?, ?> builder = Caffeine.newBuilder();
- if (configuration.getEvictionType() == EvictionType.SIZE_BASED) {
- builder.initialCapacity(configuration.getInitialCapacity());
- builder.maximumSize(configuration.getMaximumSize());
- } else if (configuration.getEvictionType() == EvictionType.TIME_BASED) {
- builder.expireAfterAccess(configuration.getExpireAfterAccessTime(), TimeUnit.SECONDS);
- builder.expireAfterWrite(configuration.getExpireAfterWriteTime(), TimeUnit.SECONDS);
- }
- if (configuration.isStatsEnabled()) {
- if (ObjectHelper.isEmpty(configuration.getStatsCounter())) {
- builder.recordStats();
- } else {
- builder.recordStats(configuration::getStatsCounter);
+ if (configuration.isCreateCacheIfNotExist()) {
+ Caffeine<?, ?> builder = Caffeine.newBuilder();
+ if (configuration.getEvictionType() == EvictionType.SIZE_BASED) {
+ builder.initialCapacity(configuration.getInitialCapacity());
+ builder.maximumSize(configuration.getMaximumSize());
+ } else if (configuration.getEvictionType() == EvictionType.TIME_BASED) {
+ builder.expireAfterAccess(configuration.getExpireAfterAccessTime(), TimeUnit.SECONDS);
+ builder.expireAfterWrite(configuration.getExpireAfterWriteTime(), TimeUnit.SECONDS);
}
+ if (configuration.isStatsEnabled()) {
+ if (ObjectHelper.isEmpty(configuration.getStatsCounter())) {
+ builder.recordStats();
+ } else {
+ builder.recordStats(configuration::getStatsCounter);
+ }
+ }
+ if (ObjectHelper.isNotEmpty(configuration.getRemovalListener())) {
+ builder.removalListener(configuration.getRemovalListener());
+ }
+ cache = builder.build();
+ } else {
+ throw new IllegalArgumentException(
+ "Cache instance '" + cacheName + "' not found and createCacheIfNotExist is set to false");
}
- if (ObjectHelper.isNotEmpty(configuration.getRemovalListener())) {
- builder.removalListener(configuration.getRemovalListener());
- }
- cache = builder.build();
}
super.doStart();
}
diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducer.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducer.java
index 8a61087..713b82e 100644
--- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducer.java
+++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducer.java
@@ -87,11 +87,27 @@ public class CaffeineCacheProducer extends HeaderSelectorProducer {
@InvokeOnHeader(CaffeineConstants.ACTION_INVALIDATE_ALL)
public void onInvalidateAll(Message message) {
- cache.invalidateAll(message.getHeader(CaffeineConstants.KEYS, Collections::emptySet, Set.class));
+
+ Set<?> keys = message.getHeader(CaffeineConstants.KEYS, Set.class);
+ /* Empty cache if no key set is provided
+ - implies no deletions at all if an empty key set is provided */
+ if (keys == null) {
+ cache.invalidateAll();
+ } else {
+ cache.invalidateAll(keys);
+ }
setResult(message, true, null, null);
}
+ @InvokeOnHeader(CaffeineConstants.ACTION_AS_MAP)
+ public void onAsMap(Message message) {
+ Map<?, ?> result = cache.asMap();
+
+ message.setHeader(CaffeineConstants.KEYS, result.keySet());
+ setResult(message, true, result, null);
+ }
+
// ****************************
// Helpers
// ****************************
diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java
index 6e09285..c15e89e 100644
--- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java
+++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheEndpoint.java
@@ -18,6 +18,7 @@ package org.apache.camel.component.caffeine.load;
import java.util.concurrent.TimeUnit;
+import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.apache.camel.Category;
@@ -64,27 +65,34 @@ public class CaffeineLoadCacheEndpoint extends DefaultEndpoint {
@Override
protected void doStart() throws Exception {
+
cache = CamelContextHelper.lookup(getCamelContext(), cacheName, LoadingCache.class);
if (cache == null) {
- Caffeine<Object, Object> builder = Caffeine.newBuilder();
- if (configuration.getEvictionType() == EvictionType.SIZE_BASED) {
- builder.initialCapacity(configuration.getInitialCapacity());
- builder.maximumSize(configuration.getMaximumSize());
- } else if (configuration.getEvictionType() == EvictionType.TIME_BASED) {
- builder.expireAfterAccess(configuration.getExpireAfterAccessTime(), TimeUnit.SECONDS);
- builder.expireAfterWrite(configuration.getExpireAfterWriteTime(), TimeUnit.SECONDS);
- }
- if (configuration.isStatsEnabled()) {
- if (ObjectHelper.isEmpty(configuration.getStatsCounter())) {
- builder.recordStats();
- } else {
- builder.recordStats(configuration::getStatsCounter);
+ if (configuration.isCreateCacheIfNotExist()) {
+ Caffeine<Object, Object> builder = Caffeine.newBuilder();
+ if (configuration.getEvictionType() == EvictionType.SIZE_BASED) {
+ builder.initialCapacity(configuration.getInitialCapacity());
+ builder.maximumSize(configuration.getMaximumSize());
+ } else if (configuration.getEvictionType() == EvictionType.TIME_BASED) {
+ builder.expireAfterAccess(configuration.getExpireAfterAccessTime(), TimeUnit.SECONDS);
+ builder.expireAfterWrite(configuration.getExpireAfterWriteTime(), TimeUnit.SECONDS);
}
+ if (configuration.isStatsEnabled()) {
+ if (ObjectHelper.isEmpty(configuration.getStatsCounter())) {
+ builder.recordStats();
+ } else {
+ builder.recordStats(configuration::getStatsCounter);
+ }
+ }
+ if (ObjectHelper.isNotEmpty(configuration.getRemovalListener())) {
+ builder.removalListener(configuration.getRemovalListener());
+ }
+ cache = builder.build(configuration.getCacheLoader());
+ } else {
+ throw new IllegalArgumentException(
+ "Loading cache instance '" + cacheName
+ + "' not found and createCacheIfNotExist is set to false");
}
- if (ObjectHelper.isNotEmpty(configuration.getRemovalListener())) {
- builder.removalListener(configuration.getRemovalListener());
- }
- cache = builder.build(configuration.getCacheLoader());
}
super.doStart();
}
diff --git a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheProducer.java b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheProducer.java
index 51a7c5b..c2236c8 100644
--- a/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheProducer.java
+++ b/components/camel-caffeine/src/main/java/org/apache/camel/component/caffeine/load/CaffeineLoadCacheProducer.java
@@ -87,11 +87,26 @@ public class CaffeineLoadCacheProducer extends HeaderSelectorProducer {
@InvokeOnHeader(CaffeineConstants.ACTION_INVALIDATE_ALL)
public void onInvalidateAll(Message message) {
- cache.invalidateAll(message.getHeader(CaffeineConstants.KEYS, Collections::emptySet, Set.class));
+ Set<?> keys = message.getHeader(CaffeineConstants.KEYS, Set.class);
+ /* Empty cache if no key set is provided
+ - implies no deletions at all if an empty key set is provided */
+ if (keys == null) {
+ cache.invalidateAll();
+ } else {
+ cache.invalidateAll(keys);
+ }
setResult(message, true, null, null);
}
+ @InvokeOnHeader(CaffeineConstants.ACTION_AS_MAP)
+ public void onAsMap(Message message) {
+ Map<?, ?> result = cache.asMap();
+
+ message.setHeader(CaffeineConstants.KEYS, result.keySet());
+ setResult(message, true, result, null);
+ }
+
// ****************************
// Helpers
// ****************************
diff --git a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducerTest.java b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducerTest.java
index 98f3b52..db9ac7f 100644
--- a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducerTest.java
+++ b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheProducerTest.java
@@ -21,6 +21,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import com.github.benmanes.caffeine.cache.Cache;
+import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.caffeine.CaffeineConstants;
import org.apache.camel.component.mock.MockEndpoint;
@@ -194,6 +195,51 @@ public class CaffeineCacheProducerTest extends CaffeineCacheTestSupport {
}
@Test
+ void testCacheInvalidateAllWithoutKeys() throws Exception {
+ final Cache<Object, Object> cache = getTestCache();
+ final Map<String, String> map = generateRandomMapOfString(3);
+
+ cache.putAll(map);
+
+ final MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_HAS_RESULT, false);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_SUCCEEDED, true);
+
+ fluentTemplate().withHeader(CaffeineConstants.ACTION, CaffeineConstants.ACTION_INVALIDATE_ALL)
+ .to("direct://start").send();
+
+ assertMockEndpointsSatisfied();
+
+ assertTrue(getTestCache().asMap().keySet().isEmpty());
+ }
+
+ @Test
+ void testCacheAsMap() throws Exception {
+ final Cache<Object, Object> cache = getTestCache();
+ final Map<String, String> map = generateRandomMapOfString(3);
+ final Set<String> keys = map.keySet();
+
+ cache.putAll(map);
+
+ final MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_HAS_RESULT, true);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_SUCCEEDED, true);
+
+ final Exchange exchange = fluentTemplate().withHeader(CaffeineConstants.ACTION, CaffeineConstants.ACTION_AS_MAP)
+ .to("direct://start").send();
+
+ assertMockEndpointsSatisfied();
+
+ final Map<String, String> elements = exchange.getMessage().getBody(Map.class);
+ keys.forEach(k -> {
+ assertTrue(elements.containsKey(k));
+ assertEquals(map.get(k), elements.get(k));
+ });
+ }
+
+ @Test
void testStats() {
final Map<String, String> map = generateRandomMapOfString(3);
final Set<String> keys = map.keySet().stream().limit(2).collect(Collectors.toSet());
diff --git a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovaListenerProducerTest.java b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovalListenerProducerTest.java
similarity index 99%
rename from components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovaListenerProducerTest.java
rename to components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovalListenerProducerTest.java
index 3bd9656..accb622 100644
--- a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovaListenerProducerTest.java
+++ b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/CaffeineCacheRemovalListenerProducerTest.java
@@ -32,7 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
-public class CaffeineCacheRemovaListenerProducerTest extends CaffeineCacheTestSupport {
+public class CaffeineCacheRemovalListenerProducerTest extends CaffeineCacheTestSupport {
// ****************************
// Clear
diff --git a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/MetricsStatsCounter.java b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/MetricsStatsCounter.java
index 6a576a4..bfe963d 100644
--- a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/MetricsStatsCounter.java
+++ b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/cache/MetricsStatsCounter.java
@@ -21,6 +21,7 @@ import java.util.concurrent.TimeUnit;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
+import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.github.benmanes.caffeine.cache.stats.StatsCounter;
@@ -66,19 +67,20 @@ public class MetricsStatsCounter implements StatsCounter {
}
@Override
+ @Deprecated
public void recordEviction() {
- recordEviction(1);
+ recordEviction(1, RemovalCause.EXPLICIT);
}
@Override
- public void recordEviction(int weight) {
+ public void recordEviction(int weight, RemovalCause removalCause) {
evictionCount.inc();
evictionWeight.inc(weight);
}
@Override
public CacheStats snapshot() {
- return new CacheStats(
+ return CacheStats.of(
hitCount.getCount(), missCount.getCount(), loadSuccessCount.getCount(), loadFailureCount.getCount(),
totalLoadTime.getCount(),
evictionCount.getCount(), evictionWeight.getCount());
diff --git a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/loadcache/CaffeineLoadCacheProducerTest.java b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/loadcache/CaffeineLoadCacheProducerTest.java
index 8377f25..18507db 100644
--- a/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/loadcache/CaffeineLoadCacheProducerTest.java
+++ b/components/camel-caffeine/src/test/java/org/apache/camel/component/caffeine/loadcache/CaffeineLoadCacheProducerTest.java
@@ -22,6 +22,7 @@ import java.util.Set;
import java.util.stream.Collectors;
import com.github.benmanes.caffeine.cache.Cache;
+import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.caffeine.CaffeineConstants;
import org.apache.camel.component.mock.MockEndpoint;
@@ -200,6 +201,58 @@ public class CaffeineLoadCacheProducerTest extends CaffeineLoadCacheTestSupport
});
}
+ @Test
+ void testCacheInvalidateAllWithoutKeys() throws Exception {
+ final Cache<Object, Object> cache = getTestCache();
+ final Map<Integer, Integer> map = new HashMap<>();
+ map.put(1, 1);
+ map.put(2, 2);
+ map.put(3, 3);
+
+ cache.putAll(map);
+
+ final MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_HAS_RESULT, false);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_SUCCEEDED, true);
+
+ fluentTemplate().withHeader(CaffeineConstants.ACTION, CaffeineConstants.ACTION_INVALIDATE_ALL)
+ .to("direct://start").send();
+
+ assertMockEndpointsSatisfied();
+
+ assertTrue(getTestCache().asMap().keySet().isEmpty());
+ }
+
+ @Test
+ void testCacheAsMap() throws Exception {
+ final Cache<Object, Object> cache = getTestCache();
+ final Map<String, String> map = new HashMap<>();
+ map.put("A", "AA");
+ map.put("B", "BB");
+ map.put("C", "CC");
+
+ final Set<String> keys = map.keySet();
+
+ cache.putAll(map);
+
+ final MockEndpoint mock = getMockEndpoint("mock:result");
+ mock.expectedMinimumMessageCount(1);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_HAS_RESULT, true);
+ mock.expectedHeaderReceived(CaffeineConstants.ACTION_SUCCEEDED, true);
+
+ final Exchange exchange = fluentTemplate().withHeader(CaffeineConstants.ACTION, CaffeineConstants.ACTION_AS_MAP)
+ .to("direct://start").send();
+
+ assertMockEndpointsSatisfied();
+
+ final Map<String, String> elements = exchange.getMessage().getBody(Map.class);
+ keys.forEach(k -> {
+ assertTrue(elements.containsKey(k));
+ assertEquals(map.get(k), elements.get(k));
+ });
+ }
+
// ****************************
// Route
// ****************************