Merge branch 'stable-3.5' into stable-3.6
* stable-3.5:
Allow specify either avgKeySize or avgValueSize as command parameters
Fix avg value and key size calculation when auto-adjusting caches
Apply Flogger fixes from Ia4e5a3c513
Change-Id: Ic4238ee6137910f946ae8f0b669aa68d11482bdb
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..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
@@ -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;
@@ -57,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<>();
@@ -95,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);
}
@@ -119,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());
@@ -185,29 +211,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/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 5e4fe22..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
@@ -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
@@ -169,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();