Add a --summary-count switch to configure statistics

The summary size tracked by the TopKeyMap is now configurable from the
command line.

Change-Id: Ic1b352428b60c8dc8b37fd20846fa37efdf9d649
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/HitBooleanTable.java b/src/main/java/com/googlesource/gerrit/plugins/task/HitBooleanTable.java
index 91d7ad4..8d9b9ec 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/HitBooleanTable.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/HitBooleanTable.java
@@ -28,7 +28,7 @@
     public int numberOfRows;
     public int numberOfColumns;
     public Long sumNanosecondsLoading;
-    public TopKeyMap<V> topNanosecondsLoadingKeys = new TopKeyMap<>();
+    public TopKeyMap<V> topNanosecondsLoadingKeys;
   }
 
   protected Statistics<TopKeyMap.TableKeyValue<R, C>> statistics;
@@ -67,14 +67,15 @@
   }
 
   @Override
-  public void initStatistics() {
+  public void initStatistics(int summaryCount) {
     statistics = new Statistics<>();
+    statistics.topNanosecondsLoadingKeys = new TopKeyMap<>(summaryCount);
   }
 
   @Override
-  public void ensureStatistics() {
+  public void ensureStatistics(int summaryCount) {
     if (statistics == null) {
-      initStatistics();
+      initStatistics(summaryCount);
     }
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMap.java b/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMap.java
index 433b091..6ea5a13 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMap.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMap.java
@@ -27,7 +27,7 @@
     public long hits;
     public int size;
     public Long sumNanosecondsLoading;
-    public TopKeyMap<K> topNanosecondsLoadingKeys = new TopKeyMap<>();
+    public TopKeyMap<K> topNanosecondsLoadingKeys;
     public List<Object> elements;
   }
 
@@ -37,12 +37,6 @@
 
   public HitHashMap() {}
 
-  public HitHashMap(boolean initStatistics) {
-    if (initStatistics) {
-      initStatistics();
-    }
-  }
-
   @Override
   public V get(Object key) {
     V v = super.get(key);
@@ -93,7 +87,7 @@
   @Override
   public V put(K key, V value) {
     if (statistics != null && value instanceof TracksStatistics) {
-      ((TracksStatistics) value).ensureStatistics();
+      ((TracksStatistics) value).ensureStatistics(statistics.topNanosecondsLoadingKeys.size());
     }
     return super.put(key, value);
   }
@@ -144,14 +138,15 @@
   }
 
   @Override
-  public void initStatistics() {
+  public void initStatistics(int summaryCount) {
     statistics = new Statistics<>();
+    statistics.topNanosecondsLoadingKeys = new TopKeyMap<>(summaryCount);
   }
 
   @Override
-  public void ensureStatistics() {
+  public void ensureStatistics(int summaryCount) {
     if (statistics == null) {
-      initStatistics();
+      initStatistics(summaryCount);
     }
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMapOfCollection.java b/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMapOfCollection.java
index 82d04fc..67b2dde 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMapOfCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/HitHashMapOfCollection.java
@@ -33,15 +33,9 @@
 
   public HitHashMapOfCollection() {}
 
-  public HitHashMapOfCollection(boolean initStatistics) {
-    if (initStatistics) {
-      initStatistics();
-    }
-  }
-
   @Override
-  public void initStatistics() {
-    super.initStatistics();
+  public void initStatistics(int summaryCount) {
+    super.initStatistics(summaryCount);
     statistics = new Statistics<>();
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java b/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
index df0b921..08fa5ce 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/MatchCache.java
@@ -55,8 +55,8 @@
     return isMatched;
   }
 
-  public void initStatistics() {
-    resultByChangeByQuery.initStatistics();
+  public void initStatistics(int summaryCount) {
+    resultByChangeByQuery.initStatistics(summaryCount);
   }
 
   public Object getStatistics() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
index 6f8d5cd..4ef065e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Modules.java
@@ -64,6 +64,9 @@
     @Option(name = "--include-statistics", usage = "Include statistcs about the task evaluations")
     public boolean includeStatistics = false;
 
+    @Option(name = "--summary-count", usage = "number of items to output in statistics summaries")
+    public int summaryCount = 5;
+
     @Option(
         name = "--preview",
         metaVar = "{CHANGE,PATCHSET}",
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 279729e..4aa6f57 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/PredicateCache.java
@@ -63,9 +63,9 @@
                 config.getStringList(pluginName, "cacheable-predicates", "byBranch-className")));
   }
 
-  public void initStatistics() {
+  public void initStatistics(int summaryCount) {
     statistics = new Statistics();
-    predicatesByQuery.initStatistics();
+    predicatesByQuery.initStatistics(summaryCount);
   }
 
   public Object getStatistics() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java b/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
index 6721c86..e3a5700 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Preloader.java
@@ -222,9 +222,9 @@
     return extended;
   }
 
-  public void initStatistics() {
+  public void initStatistics(int summaryCount) {
     statistics = new Statistics();
-    optionalTaskByExpression.initStatistics();
+    optionalTaskByExpression.initStatistics(summaryCount);
   }
 
   public Statistics getStatistics() {
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 414ca25..02840de 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskAttributeFactory.java
@@ -347,10 +347,10 @@
   public void initStatistics() {
     if (options.includeStatistics) {
       statistics = new Statistics();
-      definitions.predicateCache.initStatistics();
-      definitions.matchCache.initStatistics();
-      definitions.preloader.initStatistics();
-      definitions.initStatistics();
+      definitions.predicateCache.initStatistics(options.summaryCount);
+      definitions.matchCache.initStatistics(options.summaryCount);
+      definitions.preloader.initStatistics(options.summaryCount);
+      definitions.initStatistics(options.summaryCount);
     }
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
index 70cd039..ef860bb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TaskTree.java
@@ -73,6 +73,7 @@
     public Object definitionsByBranchBySubSectionCache;
     public Object changesByNamesFactoryQueryCache;
     public Properties.Statistics properties;
+    public transient int summaryCount;
   }
 
   protected static final String TASK_DIR = "task";
@@ -504,12 +505,12 @@
           if (filterable.isPresent()) {
             if (!isChange()) {
               if (nodesByBranch == null) {
-                nodesByBranch = new HitHashMapOfCollection<>(statistics != null);
+                nodesByBranch = initStatistics(new HitHashMapOfCollection<>());
               }
               nodesByBranch.put(branch, filterable.get());
             } else {
               if (definitionsByBranch == null) {
-                definitionsByBranch = new HitHashMap<>(statistics != null);
+                definitionsByBranch = initStatistics(new HitHashMap<>());
                 definitionsByBranchBySubSection.put(subSection, definitionsByBranch);
               }
               definitionsByBranch.put(
@@ -611,11 +612,19 @@
     return changeDataList;
   }
 
-  public void initStatistics() {
+  public void initStatistics(int summaryCount) {
     statistics = new Statistics();
-    definitionsBySubSection.initStatistics();
-    definitionsByBranchBySubSection.initStatistics();
-    changesByNamesFactoryQuery.initStatistics();
+    statistics.summaryCount = summaryCount;
+    definitionsBySubSection.initStatistics(summaryCount);
+    definitionsByBranchBySubSection.initStatistics(summaryCount);
+    changesByNamesFactoryQuery.initStatistics(summaryCount);
+  }
+
+  protected <T extends TracksStatistics> T initStatistics(T tracker) {
+    if (statistics != null) {
+      tracker.initStatistics(statistics.summaryCount);
+    }
+    return tracker;
   }
 
   public Statistics getStatistics() {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TopKeyMap.java b/src/main/java/com/googlesource/gerrit/plugins/task/TopKeyMap.java
index 5753b52..d4b7987 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TopKeyMap.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TopKeyMap.java
@@ -15,8 +15,8 @@
 package com.googlesource.gerrit.plugins.task;
 
 /**
- * A TopKeyMap is a lightweight limited size (5) map with 'long' keys designed to store only the
- * elements with the top five largest keys.
+ * A TopKeyMap is a lightweight limited size (default 5) map with 'long' keys designed to store only
+ * the elements with the top five largest keys.
  *
  * <p>A TopKeyMap is array based and has O(n) insertion time. Despite not having O(1) insertion
  * times, it should likely be much faster than a hash based map for small n sizes. It also is more
@@ -55,10 +55,15 @@
     }
   }
 
-  @SuppressWarnings("unchecked")
-  protected Entry[] entries = (Entry[]) new Object[5];
+  protected Entry[] entries;
 
   public TopKeyMap() {
+    this(5);
+  }
+
+  @SuppressWarnings("unchecked")
+  public TopKeyMap(int length) {
+    entries = (Entry[]) new Object[length];
     for (int i = 0; i < entries.length; i++) {
       entries[i] = new Entry();
     }
@@ -82,4 +87,8 @@
       }
     }
   }
+
+  public int size() {
+    return entries.length;
+  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/TracksStatistics.java b/src/main/java/com/googlesource/gerrit/plugins/task/TracksStatistics.java
index d7d0651..12d8722 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/TracksStatistics.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/TracksStatistics.java
@@ -15,9 +15,9 @@
 package com.googlesource.gerrit.plugins.task;
 
 public interface TracksStatistics {
-  void initStatistics();
+  void initStatistics(int summaryCount);
 
-  void ensureStatistics();
+  void ensureStatistics(int summaryCount);
 
   Object getStatistics();
 }