Allow specify either avgKeySize or avgValueSize as command parameters

Change-Id: Ib538318a3e8c8766df50f8190f8b5c6bccdbd624
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCaches.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCaches.java
index a6ccb01..a851c58 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCaches.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCaches.java
@@ -58,6 +58,8 @@
 
   private boolean dryRun;
   private boolean adjustCachesOnDefaults;
+  private Optional<Long> optionalAvgKeySize = Optional.empty();
+  private Optional<Long> optionalAvgValueSize = Optional.empty();
   private Optional<Long> optionalMaxEntries = Optional.empty();
   private Set<String> cacheNames = new HashSet<>();
 
@@ -96,10 +98,26 @@
     return optionalMaxEntries;
   }
 
+  public Optional<Long> getOptionalAvgKeySize() {
+    return optionalAvgKeySize;
+  }
+
+  public Optional<Long> getOptionalAvgValueSize() {
+    return optionalAvgValueSize;
+  }
+
   public void setOptionalMaxEntries(Optional<Long> maxEntries) {
     this.optionalMaxEntries = maxEntries;
   }
 
+  public void setAvgKeySize(Optional<Long> avgKeySize) {
+    this.optionalAvgKeySize = avgKeySize;
+  }
+
+  public void setAvgValueSize(Optional<Long> avgValueSize) {
+    this.optionalAvgValueSize = avgValueSize;
+  }
+
   public void addCacheNames(List<String> cacheNames) {
     this.cacheNames.addAll(cacheNames);
   }
@@ -120,36 +138,43 @@
       ChronicleMapCacheImpl<Object, Object> currCache = cache.getValue();
 
       {
-        ImmutablePair<Long, Long> avgSizes =
-            averageSizes(cacheName, currCache.getStore(), progressMonitor);
-        if (!(avgSizes.getKey() > 0) || !(avgSizes.getValue() > 0)) {
-          logger.atWarning().log(
-              "Cache [%s] has %s entries, but average of (key: %d, value: %d). Skipping.",
-              cacheName, currCache.diskStats().size(), avgSizes.getKey(), avgSizes.getValue());
-          continue;
-        }
+        long newKeySize;
+        long newValueSize;
 
-        long averageKeySize = avgSizes.getKey();
-        long averageValueSize = avgSizes.getValue();
+        if (optionalAvgKeySize.isPresent() && optionalAvgValueSize.isPresent()) {
+          newKeySize = optionalAvgKeySize.get();
+          newValueSize = optionalAvgValueSize.get();
+        } else {
+          ImmutablePair<Long, Long> avgSizes =
+              averageSizes(cacheName, currCache.getStore(), progressMonitor);
+          if (!(avgSizes.getKey() > 0) || !(avgSizes.getValue() > 0)) {
+            logger.atWarning().log(
+                "Cache [%s] has %s entries, but average of (key: %d, value: %d). Skipping.",
+                cacheName, currCache.diskStats().size(), avgSizes.getKey(), avgSizes.getValue());
+            continue;
+          }
+
+          newKeySize = getOptionalAvgKeySize().orElseGet(avgSizes::getKey);
+          newValueSize = getOptionalAvgValueSize().orElseGet(avgSizes::getValue);
+        }
 
         ChronicleMapCacheConfig currCacheConfig = currCache.getConfig();
         long newMaxEntries = newMaxEntries(currCache);
 
-        if (currCacheConfig.getAverageKeySize() == averageKeySize
-            && currCacheConfig.getAverageValueSize() == averageValueSize
+        if (currCacheConfig.getAverageKeySize() == newKeySize
+            && currCacheConfig.getAverageValueSize() == newValueSize
             && currCacheConfig.getMaxEntries() == newMaxEntries) {
           continue;
         }
 
         ChronicleMapCacheConfig newChronicleMapCacheConfig =
-            makeChronicleMapConfig(
-                currCache.getConfig(), newMaxEntries, averageKeySize, averageValueSize);
+            makeChronicleMapConfig(currCache.getConfig(), newMaxEntries, newKeySize, newValueSize);
 
         updateOutputConfig(
             outputChronicleMapConfig,
             cacheName,
-            averageKeySize,
-            averageValueSize,
+            newKeySize,
+            newValueSize,
             newMaxEntries,
             currCache.getConfig().getMaxBloatFactor());
 
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesCommand.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesCommand.java
index 9e7efd3..b49727b 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesCommand.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesCommand.java
@@ -57,6 +57,22 @@
     autoAdjustCachesEngine.setAdjustCachesOnDefaults(adjustCachesOnDefaults);
   }
 
+  @Option(
+      name = "--avg-key-size",
+      aliases = {"-k"},
+      usage = "Set avg key size.")
+  public void setAvgKeySize(long avgKeySize) {
+    autoAdjustCachesEngine.setAvgKeySize(Optional.of(avgKeySize));
+  }
+
+  @Option(
+      name = "--avg-value-size",
+      aliases = {"-v"},
+      usage = "Set avg value size")
+  public void setAvgValueSize(long avgValueSize) {
+    autoAdjustCachesEngine.setAvgValueSize(Optional.of(avgValueSize));
+  }
+
   @Argument(
       index = 0,
       required = false,
diff --git a/src/main/resources/Documentation/tuning.md b/src/main/resources/Documentation/tuning.md
index 7abb4d0..30b9162 100644
--- a/src/main/resources/Documentation/tuning.md
+++ b/src/main/resources/Documentation/tuning.md
@@ -180,6 +180,18 @@
 to increase the size of a particular cache only you should be using this
 together with the `cache-name` parameter.
 
+* `--avg-key-size` or `-k` (SSH), `?avg-key-size` or `?k` (REST-API) optional
+  parameter
+
+It's possible to specify a pre-defined key size in case the user wants to set
+a different value from the one automatically calculated from the auto-adjust tool.
+
+* `--avg-value-size` or `-v` (SSH), `?avg-value-size` or `?v` (REST-API)
+  optional parameter
+
+It's possible to specify a pre-defined value size in case the user wants to set
+a different value from the one automatically calculated from the auto-adjust tool.
+
 * `--adjust-caches-on-defaults` or `-a` (SSH), `?adjust-caches-on-defaults` or `?a` (REST-API)
   optional parameter
 
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesIT.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesIT.java
index 21e62b1..c030bb3 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesIT.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/AutoAdjustCachesIT.java
@@ -182,6 +182,39 @@
   }
 
   @Test
+  public void shouldHonourAvgKeySizeParameter() throws Exception {
+    createChange();
+    Long wantedAvgKeySize = 50L;
+
+    String result =
+        adminSshSession.exec(String.format("%s --avg-key-size %s", SSH_CMD, wantedAvgKeySize));
+
+    adminSshSession.assertSuccess();
+    Config configResult = configResult(result, CONFIG_HEADER);
+
+    for (String cache : EXPECTED_CACHES) {
+      assertThat(configResult.getLong("cache", cache, "avgKeySize", 0)).isEqualTo(wantedAvgKeySize);
+    }
+  }
+
+  @Test
+  public void shouldHonourAvgValueSizeParameter() throws Exception {
+    createChange();
+    Long wantedAvgValueSize = 100L;
+
+    String result =
+        adminSshSession.exec(String.format("%s --avg-value-size %s", SSH_CMD, wantedAvgValueSize));
+
+    adminSshSession.assertSuccess();
+    Config configResult = configResult(result, CONFIG_HEADER);
+
+    for (String cache : EXPECTED_CACHES) {
+      assertThat(configResult.getLong("cache", cache, "avgValueSize", 0))
+          .isEqualTo(wantedAvgValueSize);
+    }
+  }
+
+  @Test
   public void shouldCreateNewCacheFiles() throws Exception {
     createChange();