Allow to configure maxBloatFactor Allow maxBloatFactor to be configured by reading cache.<name>.maxBloatFactor configuration from gerrit.config Tuning this value allow to specify how much the actual size of the cache can differ from the configured number of entries. Bug: Issue 13416 Change-Id: Ib9a95ec2ef3945a5e87a250b777ab41f97a18cb1
diff --git a/config.md b/config.md index 5bbea2b..c74c012 100644 --- a/config.md +++ b/config.md
@@ -44,4 +44,20 @@ [Official docs]( https://www.javadoc.io/doc/net.openhft/chronicle-map/3.8.0/net/openhft/chronicle/map/ChronicleMapBuilder.html#entries-long- +) + +```cache.<name>.maxBloatFactor``` +: the maximum number of times this cache is allowed to grow in size beyond the +configured target number of entries. + +Chronicle Map will allocate memory until the actual number of entries inserted +divided by the number configured through ChronicleMapBuilder.entries() is not +higher than the configured `maxBloatFactor`. + +Chronicle Map works progressively slower when the actual size grows far beyond +the configured size, so the maximum possible maxBloatFactor() is artificially +limited to 1000. Default: *1* + +[Official docs]( +https://www.javadoc.io/doc/net.openhft/chronicle-map/3.8.0/net/openhft/chronicle/hash/ChronicleHashBuilder.html#maxBloatFactor-double- ) \ No newline at end of file
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfig.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfig.java index cb345aa..782c216 100644 --- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfig.java +++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfig.java
@@ -39,12 +39,15 @@ private final long averageValueSize; private final Duration expireAfterWrite; private final Duration refreshAfterWrite; + private final int maxBloatFactor; public static final long DEFAULT_MAX_ENTRIES = 1000; public static final long DEFAULT_AVG_KEY_SIZE = 128; public static final long DEFAULT_AVG_VALUE_SIZE = 2048; + public static final int DEFAULT_MAX_BLOAT_FACTOR = 1; + public interface Factory { ChronicleMapCacheConfig create( @Assisted("Name") String name, @@ -84,6 +87,9 @@ "refreshAfterWrite", toSeconds(refreshAfterWrite), SECONDS)); + + this.maxBloatFactor = + cfg.getInt("cache", configKey, "maxBloatFactor", DEFAULT_MAX_BLOAT_FACTOR); } public Duration getExpireAfterWrite() { @@ -114,6 +120,10 @@ return diskLimit; } + public int getMaxBloatFactor() { + return maxBloatFactor; + } + private static Path getCacheDir(SitePaths site, String name) { if (name == null) { return null;
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheImpl.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheImpl.java index c90381d..25d66e4 100644 --- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheImpl.java +++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheImpl.java
@@ -74,6 +74,8 @@ // avgValueSize) mapBuilder.entries(config.getMaxEntries()); + mapBuilder.maxBloatFactor(config.getMaxBloatFactor()); + if (config.getPersistedFile() == null || config.getDiskLimit() < 0) { store = mapBuilder.create(); } else {
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfigTest.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfigTest.java index 5f003d7..5eaeabb 100644 --- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfigTest.java +++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheConfigTest.java
@@ -16,6 +16,7 @@ import static com.google.common.truth.Truth.assertThat; import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.DEFAULT_AVG_KEY_SIZE; import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.DEFAULT_AVG_VALUE_SIZE; +import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.DEFAULT_MAX_BLOAT_FACTOR; import static com.googlesource.gerrit.modules.cache.chroniclemap.ChronicleMapCacheConfig.DEFAULT_MAX_ENTRIES; import com.google.gerrit.server.config.SitePaths; @@ -131,6 +132,21 @@ } @Test + public void shouldProvideMaxDefaultBloatFactorWhenNotConfigured() { + assertThat(configUnderTest(gerritConfig).getMaxBloatFactor()) + .isEqualTo(DEFAULT_MAX_BLOAT_FACTOR); + } + + @Test + public void shouldProvideMaxBloatFactorWhenConfigured() throws Exception { + int bloatFactor = 3; + gerritConfig.setInt("cache", cacheKey, "maxBloatFactor", bloatFactor); + gerritConfig.save(); + + assertThat(configUnderTest(gerritConfig).getMaxBloatFactor()).isEqualTo(bloatFactor); + } + + @Test public void shouldProvideExpireAfterWriteWhenMaxAgeIsConfgured() throws Exception { String maxAge = "3 minutes"; gerritConfig.setString("cache", cacheKey, "maxAge", maxAge);