Use HitHashMap in PredicateCache

Using a common class to gather hit rates makes reporting statistics more
consistent and removes a bunch of code from the PredicateCache class.
This means that the statistic 'misses' will be more appropriately named
'size' now (in simple cases like this, the size always equates to the
misses, so reserve the use of 'misses' for cases when that is not the
true).

Change-Id: I5c21fa9caa4dbaf5f7a28863d24a0070fb4b1320
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 21d1ed3..8655e6b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
@@ -32,24 +32,22 @@
 import com.google.gerrit.server.query.change.RegexRefPredicate;
 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 {
   public static class Statistics {
-    protected long hits;
-    protected long misses;
+    protected Object predicatesByQueryCache;
+    protected long numberOfMatches;
   }
 
   protected final ChangeQueryBuilder cqb;
   protected final Set<String> cacheableByBranchPredicateClassNames;
   protected final CurrentUser user;
-
-  protected final Map<String, ThrowingProvider<Predicate<ChangeData>, QueryParseException>>
-      predicatesByQuery = new HashMap<>();
+  protected final StatisticsMap<
+          String, ThrowingProvider<Predicate<ChangeData>, QueryParseException>>
+      predicatesByQuery = new HitHashMap<>();
 
   protected Statistics statistics;
 
@@ -69,9 +67,13 @@
 
   public void initStatistics() {
     statistics = new Statistics();
+    predicatesByQuery.initStatistics();
   }
 
-  public Statistics getStatistics() {
+  public Object getStatistics() {
+    if (statistics != null) {
+      statistics.predicatesByQueryCache = predicatesByQuery.getStatistics();
+    }
     return statistics;
   }
 
@@ -80,6 +82,9 @@
     if ("true".equalsIgnoreCase(query)) {
       return true;
     }
+    if (statistics != null) {
+      statistics.numberOfMatches++;
+    }
     return getPredicate(query).asMatchable().match(c);
   }
 
@@ -87,14 +92,8 @@
     ThrowingProvider<Predicate<ChangeData>, QueryParseException> predProvider =
         predicatesByQuery.get(query);
     if (predProvider != null) {
-      if (statistics != null) {
-        statistics.hits++;
-      }
       return predProvider.get();
     }
-    if (statistics != null) {
-      statistics.misses++;
-    }
     // never seen 'query' before
     try {
       Predicate<ChangeData> pred = cqb.parse(query);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
index 4dfeb99..2d7d400 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
@@ -54,7 +54,7 @@
     public long numberOfChanges;
     public long numberOfNodes;
     public long numberOfTaskPluginAttributes;
-    public PredicateCache.Statistics predicateCache;
+    public Object predicateCache;
     public Preloader.Statistics preloader;
     public TaskTree.Statistics treeCaches;
   }