Fix avg value and key size calculation when auto-adjusting caches Current logic is broken and doesn't calculate an average Change-Id: Ib6ab3aba74a6989c4add84150674b967fe383c65
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 a07d8c4..a6ccb01 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
@@ -15,6 +15,7 @@ import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheFactory.getCacheDir; +import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.Cache; import com.google.common.flogger.FluentLogger; import com.google.gerrit.common.Nullable; @@ -185,29 +186,31 @@ String cacheName, ConcurrentMap<KeyWrapper<Object>, TimedValue<Object>> store, ProgressMonitor progressMonitor) { - long kAvg = 0; - long vAvg = 0; + long kTotal = 0; + long vTotal = 0; - if (store.isEmpty()) return ImmutablePair.of(kAvg, vAvg); + if (store.isEmpty()) return ImmutablePair.of(kTotal, vTotal); progressMonitor.beginTask( String.format("[%s] calculate average key/value size", cacheName), store.size()); - int i = 1; for (Map.Entry<KeyWrapper<Object>, TimedValue<Object>> entry : store.entrySet()) { - kAvg = kAvg + (serializedKeyLength(cacheName, entry.getKey()) - kAvg) / i; - vAvg = vAvg + (serializedValueLength(cacheName, entry.getValue()) - vAvg) / i; + kTotal += serializedKeyLength(cacheName, entry.getKey()); + vTotal += serializedValueLength(cacheName, entry.getValue()); progressMonitor.update(1); } progressMonitor.endTask(); - return ImmutablePair.of(kAvg, vAvg); + long numCacheEntries = store.entrySet().size(); + return ImmutablePair.of(kTotal / numCacheEntries, vTotal / numCacheEntries); } - private static int serializedKeyLength(String cacheName, KeyWrapper<Object> keyWrapper) { + @VisibleForTesting + static int serializedKeyLength(String cacheName, KeyWrapper<Object> keyWrapper) { return CacheSerializers.getKeySerializer(cacheName).serialize(keyWrapper.getValue()).length; } - private static int serializedValueLength(String cacheName, TimedValue<Object> timedValue) { + @VisibleForTesting + static int serializedValueLength(String cacheName, TimedValue<Object> timedValue) { return CacheSerializers.getValueSerializer(cacheName).serialize(timedValue.getValue()).length; }
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 5e4fe22..21e62b1 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
@@ -17,6 +17,8 @@ import static com.google.common.truth.Truth.assertThat; import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCaches.MAX_ENTRIES_MULTIPLIER; import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCaches.PERCENTAGE_SIZE_INCREASE_THRESHOLD; +import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCaches.serializedKeyLength; +import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCaches.serializedValueLength; import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCachesCommand.CONFIG_HEADER; import static com.googlesource.gerrit.modules.cache.chroniclemap.AutoAdjustCachesCommand.TUNED_INFIX; import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.Defaults.maxBloatFactorFor; @@ -134,13 +136,20 @@ @Test @GerritConfig(name = "cache.test_cache.maxEntries", value = "10") @GerritConfig(name = "cache.test_cache.maxBloatFactor", value = "1") - public void shouldIncreaseCacheSizeWhenIsGettingFull() throws Exception { + public void shouldCorrectlyIncreaseCacheSizeWhenIsGettingFull() throws Exception { ChronicleMapCacheImpl<String, String> chronicleMapCache = (ChronicleMapCacheImpl<String, String>) testCache; + long elemsAdded = 0; + long totalKeySize = 0; + long totalValueSize = 0; while (chronicleMapCache.percentageUsedAutoResizes() < PERCENTAGE_SIZE_INCREASE_THRESHOLD) { - String aString = UUID.randomUUID().toString(); - testCache.put(aString, aString); + String key = UUID.randomUUID() + "someExtraValue"; + String value = UUID.randomUUID().toString(); + elemsAdded += 1; + totalKeySize += serializedKeyLength(TEST_CACHE_NAME, new KeyWrapper<>(key)); + totalValueSize += serializedValueLength(TEST_CACHE_NAME, new TimedValue<>(value)); + testCache.put(key, value); } String tuneResult = adminSshSession.exec(SSH_CMD + " " + TEST_CACHE_NAME); @@ -150,6 +159,10 @@ assertThat(tunedConfig.getSubsections("cache")).contains(TEST_CACHE_NAME); assertThat(tunedConfig.getLong("cache", TEST_CACHE_NAME, "maxEntries", 0)) .isEqualTo(chronicleMapCache.getConfig().getMaxEntries() * MAX_ENTRIES_MULTIPLIER); + assertThat(tunedConfig.getLong("cache", TEST_CACHE_NAME, "avgKeySize", 0)) + .isEqualTo(totalKeySize / elemsAdded); + assertThat(tunedConfig.getLong("cache", TEST_CACHE_NAME, "avgValueSize", 0)) + .isEqualTo(totalValueSize / elemsAdded); } @Test