Add an isCacheableByBranch() to the PredicateCache
Add an API to determine if a Predicate's output is assumed to be
constant given any Change destined for the same Branch.NameKey.
Change-Id: I32b52fe04742a344e71a4eee9bc2b69133d112ff
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
index aa3da13..f6d6259 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
@@ -14,27 +14,50 @@
package com.googlesource.gerrit.plugins.task;
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.index.query.AndPredicate;
+import com.google.gerrit.index.query.NotPredicate;
+import com.google.gerrit.index.query.OrPredicate;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
+import com.google.gerrit.server.query.change.DestinationPredicate;
+import com.google.gerrit.server.query.change.ProjectPredicate;
+import com.google.gerrit.server.query.change.RefPredicate;
+import com.google.gerrit.server.query.change.RegexProjectPredicate;
+import com.google.gerrit.server.query.change.RegexRefPredicate;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+import org.eclipse.jgit.lib.Config;
public class PredicateCache {
protected final ChangeQueryBuilder cqb;
+ protected final Set<String> cacheableByBranchPredicateClassNames;
protected final CurrentUser user;
protected final Map<String, ThrowingProvider<Predicate<ChangeData>, QueryParseException>>
predicatesByQuery = new HashMap<>();
@Inject
- public PredicateCache(CurrentUser user, ChangeQueryBuilder cqb) {
+ public PredicateCache(
+ @GerritServerConfig Config config,
+ @PluginName String pluginName,
+ CurrentUser user,
+ ChangeQueryBuilder cqb) {
this.user = user;
this.cqb = cqb;
+ cacheableByBranchPredicateClassNames =
+ new HashSet<>(
+ Arrays.asList(
+ config.getStringList(pluginName, "cacheable-predicates", "byBranch-className")));
}
public boolean match(ChangeData c, String query) throws OrmException, QueryParseException {
@@ -78,4 +101,39 @@
throw e;
}
}
+
+ /**
+ * Can this query's output be assumed to be constant given any Change destined for the same
+ * Branch.NameKey?
+ */
+ public boolean isCacheableByBranch(String query) throws QueryParseException {
+ if (query == null
+ || "".equals(query)
+ || "false".equalsIgnoreCase(query)
+ || "true".equalsIgnoreCase(query)) {
+ return true;
+ }
+ return isCacheableByBranch(getPredicate(query));
+ }
+
+ protected boolean isCacheableByBranch(Predicate<ChangeData> predicate) {
+ if (predicate instanceof AndPredicate
+ || predicate instanceof NotPredicate
+ || predicate instanceof OrPredicate) {
+ for (Predicate<ChangeData> subPred : predicate.getChildren()) {
+ if (!isCacheableByBranch(subPred)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (predicate instanceof DestinationPredicate
+ || predicate instanceof ProjectPredicate
+ || predicate instanceof RefPredicate
+ || predicate instanceof RegexProjectPredicate
+ || predicate instanceof RegexRefPredicate) {
+ return true;
+ }
+ return cacheableByBranchPredicateClassNames.contains(predicate.getClass().getName());
+ }
}
diff --git a/src/main/resources/Documentation/config-gerrit.md b/src/main/resources/Documentation/config-gerrit.md
new file mode 100644
index 0000000..6f0b0a5
--- /dev/null
+++ b/src/main/resources/Documentation/config-gerrit.md
@@ -0,0 +1,25 @@
+# Admin User Guide - Configuration
+
+## File `etc/gerrit.config`
+
+The file `'$site_path'/etc/gerrit.config` is a Git-style config file
+that controls many host specific settings for Gerrit.
+
+### Section @PLUGIN@ "cacheable-predicates"
+
+The @PLUGIN@.cacheable-predicates section configures Change Predicate
+optimizations which the @PLUGIN@ plugin may use when evaluating tasks.
+
+#### @PLUGIN@.cacheable-predicates.byBranch-className
+
+The value set with this key specifies a fully qualified class name
+of a Predicate which can be assumed to always return the same match
+result to all Changes destined for the same project/branch
+combinations. This key may be specified more than once.
+
+Example:
+
+```
+[@PLUGIN@ "cacheable-predicates"]
+ byBranch-className = com.google.gerrit.server.query.change.BranchSetPredicate
+```
\ No newline at end of file