Add support for forwarding cache eviction for custom caches
Allow to specify cache.pattern in the plugin configuration, which
will add additional patterns to the regex to test if a cache eviction
should be forwarded. This will allow caches created by other plugins
to be handled in addition to the default core caches.
For example:
[cache]
synchronize = true
pattern = ^my_cache.*
pattern = other_cache
Note that evictions for core caches are always forwarded. Specifying
cache.pattern only adds extra matches; it doesn't override forwarding
of eviction for the core caches.
Change-Id: Ia415d53a3c08d744324e88a6f7115a761f94c1f6
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index 6c56a8c..4ae47fe 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -28,6 +28,9 @@
import com.google.inject.Singleton;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,6 +58,7 @@
// cache section
static final String CACHE_SECTION = "cache";
+ static final String PATTERN_KEY = "pattern";
// event section
static final String EVENT_SECTION = "event";
@@ -242,15 +246,21 @@
public static class Cache extends Forwarding {
private final int threadPoolSize;
+ private final List<String> patterns;
private Cache(Config cfg) {
super(cfg, CACHE_SECTION);
threadPoolSize = getInt(cfg, CACHE_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
+ patterns = Arrays.asList(cfg.getStringList(CACHE_SECTION, null, PATTERN_KEY));
}
public int threadPoolSize() {
return threadPoolSize;
}
+
+ public List<String> patterns() {
+ return Collections.unmodifiableList(patterns);
+ }
}
public static class Event extends Forwarding {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
index 43e3642..f8d71f3 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
@@ -14,9 +14,12 @@
package com.ericsson.gerrit.plugins.highavailability.cache;
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
+import com.google.inject.Inject;
import com.google.inject.Singleton;
+import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@@ -34,8 +37,11 @@
private final Pattern pattern;
- public CachePatternMatcher() {
- this.pattern = Pattern.compile(Joiner.on("|").join(DEFAULT_PATTERNS));
+ @Inject
+ public CachePatternMatcher(Configuration cfg) {
+ List<String> patterns = new ArrayList<>(DEFAULT_PATTERNS);
+ patterns.addAll(cfg.cache().patterns());
+ this.pattern = Pattern.compile(Joiner.on("|").join(patterns));
}
public boolean matches(String cacheName) {
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
index 6b047d3..94c3d30 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
@@ -15,7 +15,7 @@
package com.ericsson.gerrit.plugins.highavailability.cache;
public final class Constants {
-
+ public static final String GERRIT = "gerrit";
public static final String PROJECT_LIST = "project_list";
public static final String ACCOUNTS = "accounts";
public static final String GROUPS = "groups";
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
index b388b0b..253ff4a 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServlet.java
@@ -19,6 +19,7 @@
import com.ericsson.gerrit.plugins.highavailability.cache.Constants;
import com.ericsson.gerrit.plugins.highavailability.forwarder.Context;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Splitter;
import com.google.common.cache.Cache;
import com.google.gerrit.extensions.registration.DynamicMap;
@@ -37,7 +38,6 @@
class CacheRestApiServlet extends HttpServlet {
private static final int CACHENAME_INDEX = 1;
private static final long serialVersionUID = -1L;
- private static final String GERRIT = "gerrit";
private static final Logger logger = LoggerFactory.getLogger(CacheRestApiServlet.class);
private final DynamicMap<Cache<?, ?>> cacheMap;
@@ -57,10 +57,17 @@
String cacheName = params.get(CACHENAME_INDEX);
String json = req.getReader().readLine();
Object key = GsonParser.fromJson(cacheName, json);
- Cache<?, ?> cache = cacheMap.get(GERRIT, cacheName);
- Context.setForwardedEvent(true);
- evictCache(cache, cacheName, key);
- rsp.setStatus(SC_NO_CONTENT);
+ CacheParameters cacheKey = getCacheParameters(cacheName);
+ Cache<?, ?> cache = cacheMap.get(cacheKey.pluginName, cacheKey.cacheName);
+ if (cache == null) {
+ String msg = String.format("cache %s not found", cacheName);
+ logger.error("Failed to process eviction request: " + msg);
+ sendError(rsp, SC_BAD_REQUEST, msg);
+ } else {
+ Context.setForwardedEvent(true);
+ evictCache(cache, cacheKey.cacheName, key);
+ rsp.setStatus(SC_NO_CONTENT);
+ }
} catch (IOException e) {
logger.error("Failed to process eviction request: " + e.getMessage(), e);
sendError(rsp, SC_BAD_REQUEST, e.getMessage());
@@ -69,6 +76,26 @@
}
}
+ @VisibleForTesting
+ public static class CacheParameters {
+ public final String pluginName;
+ public final String cacheName;
+
+ public CacheParameters(String pluginName, String cacheName) {
+ this.pluginName = pluginName;
+ this.cacheName = cacheName;
+ }
+ }
+
+ @VisibleForTesting
+ public static CacheParameters getCacheParameters(String cache) {
+ int dot = cache.indexOf(".");
+ if (dot > 0) {
+ return new CacheParameters(cache.substring(0, dot), cache.substring(dot + 1));
+ }
+ return new CacheParameters(Constants.GERRIT, cache);
+ }
+
private static void sendError(HttpServletResponse rsp, int statusCode, String message) {
try {
rsp.sendError(statusCode, message);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonParser.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonParser.java
index 23f42ab..8a177de 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonParser.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/GsonParser.java
@@ -44,7 +44,11 @@
key = gson.fromJson(Strings.nullToEmpty(json), Object.class);
break;
default:
- key = gson.fromJson(Strings.nullToEmpty(json).trim(), String.class);
+ try {
+ key = gson.fromJson(Strings.nullToEmpty(json).trim(), String.class);
+ } catch (Exception e) {
+ key = gson.fromJson(Strings.nullToEmpty(json), Object.class);
+ }
}
return key;
}
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 8ec9432..1ab2858 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -62,6 +62,13 @@
: Maximum number of threads used to send cache evictions to the target instance.
Defaults to 1.
+cache.pattern
+: Pattern to match names of custom caches for which evictions should be
+ forwarded (in addition to the core caches that are always forwarded). May be
+ specified more than once to add multiple patterns.
+ Defaults to an empty list, meaning only evictions of the core caches are
+ forwarded.
+
event.synchronize
: Whether to synchronize stream events.
Defaults to true.