Merge branch 'stable-3.3'
* stable-3.3:
Use wrapper to store cache key
Change-Id: I46cd2d89b141eefa09b452e9c6229751d3775eab
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/CacheSerializers.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/CacheSerializers.java
new file mode 100644
index 0000000..8546981
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/CacheSerializers.java
@@ -0,0 +1,58 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.modules.cache.chroniclemap;
+
+import com.google.gerrit.server.cache.PersistentCacheDef;
+import com.google.gerrit.server.cache.serialize.CacheSerializer;
+import com.google.inject.Singleton;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Singleton
+public class CacheSerializers {
+ private static final Map<String, CacheSerializer<?>> keySerializers = new ConcurrentHashMap<>();
+ private static final Map<String, CacheSerializer<?>> valueSerializers = new ConcurrentHashMap<>();
+
+ static <K, V> void registerCacheDef(PersistentCacheDef<K, V> def) {
+ String cacheName = def.name();
+ registerCacheKeySerializer(cacheName, def.keySerializer());
+ registerCacheValueSerializer(cacheName, def.valueSerializer());
+ }
+
+ static <K, V> void registerCacheKeySerializer(
+ String cacheName, CacheSerializer<K> keySerializer) {
+ keySerializers.computeIfAbsent(cacheName, (name) -> keySerializer);
+ }
+
+ static <K, V> void registerCacheValueSerializer(
+ String cacheName, CacheSerializer<V> valueSerializer) {
+ valueSerializers.computeIfAbsent(cacheName, (name) -> valueSerializer);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <K> CacheSerializer<K> getKeySerializer(String name) {
+ if (keySerializers.containsKey(name)) {
+ return (CacheSerializer<K>) keySerializers.get(name);
+ }
+ throw new IllegalStateException("Could not find key serializer for " + name);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <V> CacheSerializer<V> getValueSerializer(String name) {
+ if (valueSerializers.containsKey(name)) {
+ return (CacheSerializer<V>) valueSerializers.get(name);
+ }
+ throw new IllegalStateException("Could not find value serializer for " + name);
+ }
+}
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 311445b..bde4fd1 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
@@ -39,7 +39,7 @@
private final ChronicleMapCacheConfig config;
private final CacheLoader<K, V> loader;
- private final ChronicleMap<K, TimedValue<V>> store;
+ private final ChronicleMap<KeyWrapper<K>, TimedValue<V>> store;
private final LongAdder hitCount = new LongAdder();
private final LongAdder missCount = new LongAdder();
private final LongAdder loadSuccessCount = new LongAdder();
@@ -55,6 +55,8 @@
CacheLoader<K, V> loader,
MetricMaker metricMaker)
throws IOException {
+ CacheSerializers.registerCacheDef(def);
+
this.config = config;
this.loader = loader;
this.hotEntries =
@@ -63,11 +65,11 @@
ChronicleMapStorageMetrics metrics = new ChronicleMapStorageMetrics(metricMaker);
- final Class<K> keyClass = (Class<K>) def.keyType().getRawType();
+ final Class<KeyWrapper<K>> keyWrapperClass = (Class<KeyWrapper<K>>) (Class) KeyWrapper.class;
final Class<TimedValue<V>> valueWrapperClass = (Class<TimedValue<V>>) (Class) TimedValue.class;
- final ChronicleMapBuilder<K, TimedValue<V>> mapBuilder =
- ChronicleMap.of(keyClass, valueWrapperClass).name(def.name());
+ final ChronicleMapBuilder<KeyWrapper<K>, TimedValue<V>> mapBuilder =
+ ChronicleMap.of(keyWrapperClass, valueWrapperClass).name(def.name());
// Chronicle-map does not allow to custom-serialize boxed primitives
// such as Boolean, Integer, for which size is statically determined.
@@ -75,11 +77,11 @@
// it cannot be used.
if (!mapBuilder.constantlySizedKeys()) {
mapBuilder.averageKeySize(config.getAverageKeySize());
- mapBuilder.keyMarshaller(new ChronicleMapMarshallerAdapter<>(def.keySerializer()));
+ mapBuilder.keyMarshaller(new KeyWrapperMarshaller<>(def.name()));
}
mapBuilder.averageValueSize(config.getAverageValueSize());
- mapBuilder.valueMarshaller(new TimedValueMarshaller<>(def.valueSerializer()));
+ mapBuilder.valueMarshaller(new TimedValueMarshaller<>(def.name()));
mapBuilder.entries(config.getMaxEntries());
@@ -117,7 +119,7 @@
}
<K, V> void registerCallBackMetrics(
- String name, ChronicleMap<K, TimedValue<V>> store, InMemoryLRU<K> hotEntries) {
+ String name, ChronicleMap<KeyWrapper<K>, TimedValue<V>> store, InMemoryLRU<K> hotEntries) {
String sanitizedName = metricMaker.sanitizeMetricName(name);
String PERCENTAGE_FREE_SPACE_METRIC =
"cache/chroniclemap/percentage_free_space_" + sanitizedName;
@@ -162,10 +164,12 @@
return config;
}
+ @SuppressWarnings("unchecked")
@Override
public V getIfPresent(Object objKey) {
- if (store.containsKey(objKey)) {
- TimedValue<V> vTimedValue = store.get(objKey);
+ KeyWrapper<K> keyWrapper = (KeyWrapper<K>) new KeyWrapper<>(objKey);
+ if (store.containsKey(keyWrapper)) {
+ TimedValue<V> vTimedValue = store.get(keyWrapper);
if (!expired(vTimedValue.getCreated())) {
hitCount.increment();
hotEntries.add((K) objKey);
@@ -180,8 +184,9 @@
@Override
public V get(K key) throws ExecutionException {
- if (store.containsKey(key)) {
- TimedValue<V> vTimedValue = store.get(key);
+ KeyWrapper<K> keyWrapper = new KeyWrapper<>(key);
+ if (store.containsKey(keyWrapper)) {
+ TimedValue<V> vTimedValue = store.get(keyWrapper);
if (!needsRefresh(vTimedValue.getCreated())) {
hitCount.increment();
hotEntries.add(key);
@@ -211,8 +216,9 @@
@Override
public V get(K key, Callable<? extends V> valueLoader) throws ExecutionException {
- if (store.containsKey(key)) {
- TimedValue<V> vTimedValue = store.get(key);
+ KeyWrapper<K> keyWrapper = new KeyWrapper<>(key);
+ if (store.containsKey(keyWrapper)) {
+ TimedValue<V> vTimedValue = store.get(keyWrapper);
if (!needsRefresh(vTimedValue.getCreated())) {
hitCount.increment();
return vTimedValue.getValue();
@@ -235,14 +241,16 @@
@SuppressWarnings("unchecked")
public void putUnchecked(Object key, Object value, Timestamp created) {
- TimedValue<?> wrapped = new TimedValue<>(value, created.toInstant().toEpochMilli());
- store.put((K) key, (TimedValue<V>) wrapped);
+ TimedValue<?> wrappedValue = new TimedValue<>(value, created.toInstant().toEpochMilli());
+ KeyWrapper<?> wrappedKey = new KeyWrapper<>(key);
+ store.put((KeyWrapper<K>) wrappedKey, (TimedValue<V>) wrappedValue);
}
@Override
public void put(K key, V val) {
- TimedValue<V> wrapped = new TimedValue<>(val);
- store.put(key, wrapped);
+ KeyWrapper<K> wrappedKey = new KeyWrapper<>(key);
+ TimedValue<V> wrappedValue = new TimedValue<>(val);
+ store.put(wrappedKey, wrappedValue);
hotEntries.add(key);
}
@@ -251,7 +259,7 @@
store.forEachEntry(
c -> {
if (expired(c.value().get().getCreated())) {
- hotEntries.remove(c.key().get());
+ hotEntries.remove(c.key().get().getValue());
c.context().remove(c);
}
});
@@ -282,17 +290,19 @@
private void evictColdEntries() {
store.forEachEntryWhile(
e -> {
- if (!hotEntries.contains(e.key().get())) {
+ if (!hotEntries.contains(e.key().get().getValue())) {
e.doRemove();
}
return runningOutOfFreeSpace();
});
}
+ @SuppressWarnings("unchecked")
@Override
public void invalidate(Object key) {
- store.remove(key);
- hotEntries.remove((K) key);
+ KeyWrapper<K> wrappedKey = (KeyWrapper<K>) new KeyWrapper<>(key);
+ store.remove(wrappedKey);
+ hotEntries.remove(wrappedKey.getValue());
}
@Override
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapter.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapter.java
deleted file mode 100644
index 0c60dca..0000000
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package com.googlesource.gerrit.modules.cache.chroniclemap;
-
-import com.google.gerrit.server.cache.serialize.CacheSerializer;
-import net.openhft.chronicle.bytes.Bytes;
-import net.openhft.chronicle.core.util.ReadResolvable;
-import net.openhft.chronicle.hash.serialization.BytesReader;
-import net.openhft.chronicle.hash.serialization.BytesWriter;
-
-public class ChronicleMapMarshallerAdapter<T>
- implements BytesWriter<T>, BytesReader<T>, ReadResolvable<ChronicleMapMarshallerAdapter<T>> {
-
- private final CacheSerializer<T> cacheSerializer;
-
- ChronicleMapMarshallerAdapter(CacheSerializer<T> cacheSerializer) {
- this.cacheSerializer = cacheSerializer;
- }
-
- @Override
- public ChronicleMapMarshallerAdapter<T> readResolve() {
- return new ChronicleMapMarshallerAdapter<>(cacheSerializer);
- }
-
- @Override
- public T read(Bytes in, T using) {
- int serializedLength = (int) in.readUnsignedInt();
- byte[] serialized = new byte[serializedLength];
- in.read(serialized, 0, serializedLength);
- using = cacheSerializer.deserialize(serialized);
- return using;
- }
-
- @Override
- public void write(Bytes out, T toWrite) {
- final byte[] serialized = cacheSerializer.serialize(toWrite);
- out.writeUnsignedInt(serialized.length);
- out.write(serialized);
- }
-}
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapper.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapper.java
new file mode 100644
index 0000000..cfab341
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapper.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.modules.cache.chroniclemap;
+
+import com.google.common.base.Objects;
+
+public class KeyWrapper<V> {
+
+ private final V value;
+
+ KeyWrapper(V value) {
+ this.value = value;
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof KeyWrapper)) return false;
+ KeyWrapper<?> that = (KeyWrapper<?>) o;
+ return Objects.equal(value, that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(value);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshaller.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshaller.java
new file mode 100644
index 0000000..7c7801c
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshaller.java
@@ -0,0 +1,55 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.modules.cache.chroniclemap;
+
+import net.openhft.chronicle.bytes.Bytes;
+import net.openhft.chronicle.core.util.ReadResolvable;
+import net.openhft.chronicle.hash.serialization.BytesReader;
+import net.openhft.chronicle.hash.serialization.BytesWriter;
+
+public class KeyWrapperMarshaller<V>
+ implements BytesWriter<KeyWrapper<V>>,
+ BytesReader<KeyWrapper<V>>,
+ ReadResolvable<KeyWrapperMarshaller<V>> {
+
+ private final String name;
+
+ KeyWrapperMarshaller(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public KeyWrapperMarshaller<V> readResolve() {
+ return new KeyWrapperMarshaller<>(name);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public KeyWrapper<V> read(Bytes in, KeyWrapper<V> using) {
+ int serializedLength = (int) in.readUnsignedInt();
+ byte[] serialized = new byte[serializedLength];
+ in.read(serialized, 0, serializedLength);
+ V v = (V) CacheSerializers.getKeySerializer(name).deserialize(serialized);
+ using = new KeyWrapper<>(v);
+
+ return using;
+ }
+
+ @Override
+ public void write(Bytes out, KeyWrapper<V> toWrite) {
+ final byte[] serialized = CacheSerializers.getKeySerializer(name).serialize(toWrite.getValue());
+ out.writeUnsignedInt(serialized.length);
+ out.write(serialized);
+ }
+}
diff --git a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshaller.java b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshaller.java
index 60897bf..ec30043 100644
--- a/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshaller.java
+++ b/src/main/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshaller.java
@@ -13,7 +13,6 @@
// limitations under the License.
package com.googlesource.gerrit.modules.cache.chroniclemap;
-import com.google.gerrit.server.cache.serialize.CacheSerializer;
import java.nio.ByteBuffer;
import net.openhft.chronicle.bytes.Bytes;
import net.openhft.chronicle.core.util.ReadResolvable;
@@ -25,17 +24,18 @@
BytesReader<TimedValue<V>>,
ReadResolvable<TimedValueMarshaller<V>> {
- private final CacheSerializer<V> serializer;
+ private final String name;
- TimedValueMarshaller(CacheSerializer<V> serializer) {
- this.serializer = serializer;
+ TimedValueMarshaller(String name) {
+ this.name = name;
}
@Override
public TimedValueMarshaller<V> readResolve() {
- return new TimedValueMarshaller<>(serializer);
+ return new TimedValueMarshaller<>(name);
}
+ @SuppressWarnings("unchecked")
@Override
public TimedValue<V> read(Bytes in, TimedValue<V> using) {
long initialPosition = in.readPosition();
@@ -57,7 +57,7 @@
// Deserialize object V (remaining bytes)
byte[] serializedV = new byte[vLength];
in.read(serializedV, 0, vLength);
- V v = serializer.deserialize(serializedV);
+ V v = (V) CacheSerializers.getValueSerializer(name).deserialize(serializedV);
using = new TimedValue<>(v, created);
@@ -66,7 +66,7 @@
@Override
public void write(Bytes out, TimedValue<V> toWrite) {
- byte[] serialized = serializer.serialize(toWrite.getValue());
+ byte[] serialized = CacheSerializers.getValueSerializer(name).serialize(toWrite.getValue());
// Serialize as follows:
// created | length of serialized V | serialized value V
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheIT.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheIT.java
index df6fc38..36ce53c 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheIT.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheIT.java
@@ -48,7 +48,7 @@
final int negativeDiskLimit = -1;
final Cache<String, String> cache =
persistentCacheFactory.build(
- new TestPersistentCacheDef("foo", negativeDiskLimit), CacheBackend.CAFFEINE);
+ new TestPersistentCacheDef("foo", null, negativeDiskLimit), CacheBackend.CAFFEINE);
assertThat(cache.getClass().getSimpleName()).isEqualTo("CaffeinatedGuavaCache");
}
@@ -58,7 +58,7 @@
final int positiveDiskLimit = 1024;
assertThat(
persistentCacheFactory.build(
- new TestPersistentCacheDef("foo", positiveDiskLimit), CacheBackend.CAFFEINE))
+ new TestPersistentCacheDef("foo", null, positiveDiskLimit), CacheBackend.CAFFEINE))
.isInstanceOf(ChronicleMapCacheImpl.class);
}
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheTest.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheTest.java
index e8c1f4a..5d380ff 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheTest.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapCacheTest.java
@@ -25,6 +25,7 @@
import com.google.gerrit.metrics.DisabledMetricMaker;
import com.google.gerrit.metrics.MetricMaker;
import com.google.gerrit.metrics.dropwizard.DropWizardMetricMaker;
+import com.google.gerrit.server.cache.serialize.CacheSerializer;
import com.google.gerrit.server.cache.serialize.StringCacheSerializer;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Guice;
@@ -47,6 +48,7 @@
import org.junit.rules.TemporaryFolder;
public class ChronicleMapCacheTest {
+ private static final String TEST_CACHE_NAME = "test-cache-name";
@Inject MetricMaker metricMaker;
@Inject MetricRegistry metricRegistry;
@@ -58,6 +60,8 @@
@Before
public void setUp() throws Exception {
+ CacheSerializers.registerCacheKeySerializer(TEST_CACHE_NAME, StringCacheSerializer.INSTANCE);
+ CacheSerializers.registerCacheValueSerializer(TEST_CACHE_NAME, StringCacheSerializer.INSTANCE);
sitePaths = new SitePaths(temporaryFolder.newFolder().toPath());
Files.createDirectories(sitePaths.etc_dir);
@@ -82,7 +86,7 @@
}
@Test
- public void getIfPresentShouldReturnNullWhenThereisNoCachedValue() throws Exception {
+ public void getIfPresentShouldReturnNullWhenThereIsNoCachedValue() throws Exception {
assertThat(newCacheWithLoader(null).getIfPresent("foo")).isNull();
}
@@ -237,7 +241,7 @@
@Test
public void getIfPresentShouldReturnNullWhenValueIsExpired() throws Exception {
ChronicleMapCacheImpl<String, String> cache =
- newCache(true, null, Duration.ofSeconds(1), null, 1);
+ newCache(true, TEST_CACHE_NAME, null, Duration.ofSeconds(1), null, 1);
cache.put("foo", "some-stale-value");
Thread.sleep(1010); // Allow cache entry to expire
assertThat(cache.getIfPresent("foo")).isNull();
@@ -247,7 +251,7 @@
public void getShouldRefreshValueWhenExpired() throws Exception {
String newCachedValue = UUID.randomUUID().toString();
ChronicleMapCacheImpl<String, String> cache =
- newCache(true, newCachedValue, null, Duration.ofSeconds(1), 1);
+ newCache(true, TEST_CACHE_NAME, newCachedValue, null, Duration.ofSeconds(1), 1);
cache.put("foo", "some-stale-value");
Thread.sleep(1010); // Allow cache to be flagged as needing refresh
assertThat(cache.get("foo")).isEqualTo(newCachedValue);
@@ -256,7 +260,7 @@
@Test
public void shouldPruneExpiredValues() throws Exception {
ChronicleMapCacheImpl<String, String> cache =
- newCache(true, null, Duration.ofSeconds(1), null, 1);
+ newCache(true, TEST_CACHE_NAME, null, Duration.ofSeconds(1), null, 1);
cache.put("foo1", "some-stale-value1");
cache.put("foo2", "some-stale-value1");
Thread.sleep(1010); // Allow cache entries to expire
@@ -293,10 +297,10 @@
public void shouldEvictOldestElementInCacheWhenIsNeverAccessed() throws Exception {
final String fooValue = "foo";
- gerritConfig.setInt("cache", "foo", "maxEntries", 2);
- gerritConfig.setInt("cache", "foo", "percentageHotKeys", 10);
- gerritConfig.setInt("cache", "foo", "avgKeySize", "foo1".getBytes().length);
- gerritConfig.setInt("cache", "foo", "avgValueSize", valueSize(fooValue));
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", 2);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "percentageHotKeys", 10);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgKeySize", "foo1".getBytes().length);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgValueSize", valueSize(fooValue));
gerritConfig.save();
ChronicleMapCacheImpl<String, String> cache = newCacheWithLoader(fooValue);
@@ -313,10 +317,10 @@
public void shouldEvictRecentlyInsertedElementInCacheWhenOldestElementIsAccessed()
throws Exception {
final String fooValue = "foo";
- gerritConfig.setInt("cache", "foo", "maxEntries", 2);
- gerritConfig.setInt("cache", "foo", "percentageHotKeys", 10);
- gerritConfig.setInt("cache", "foo", "avgKeySize", "foo1".getBytes().length);
- gerritConfig.setInt("cache", "foo", "avgValueSize", valueSize(fooValue));
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", 2);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "percentageHotKeys", 10);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgKeySize", "foo1".getBytes().length);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgValueSize", valueSize(fooValue));
gerritConfig.save();
ChronicleMapCacheImpl<String, String> cache = newCacheWithLoader(fooValue);
@@ -354,13 +358,13 @@
@Test
public void shouldTriggerPercentageFreeMetric() throws Exception {
String cachedValue = UUID.randomUUID().toString();
- String freeSpaceMetricName = "cache/chroniclemap/percentage_free_space_" + cachedValue;
- gerritConfig.setInt("cache", cachedValue, "maxEntries", 2);
- gerritConfig.setInt("cache", cachedValue, "avgKeySize", cachedValue.getBytes().length);
- gerritConfig.setInt("cache", cachedValue, "avgValueSize", valueSize(cachedValue));
+ String freeSpaceMetricName = "cache/chroniclemap/percentage_free_space_" + TEST_CACHE_NAME;
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", 2);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgKeySize", cachedValue.getBytes().length);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgValueSize", valueSize(cachedValue));
gerritConfig.save();
- ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(cachedValue);
+ ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(TEST_CACHE_NAME, cachedValue);
assertThat(getMetric(freeSpaceMetricName).getValue()).isEqualTo(100);
@@ -373,13 +377,13 @@
@Test
public void shouldTriggerRemainingAutoResizeMetric() throws Exception {
String cachedValue = UUID.randomUUID().toString();
- String autoResizeMetricName = "cache/chroniclemap/remaining_autoresizes_" + cachedValue;
- gerritConfig.setInt("cache", cachedValue, "maxEntries", 2);
- gerritConfig.setInt("cache", cachedValue, "avgKeySize", cachedValue.getBytes().length);
- gerritConfig.setInt("cache", cachedValue, "avgValueSize", valueSize(cachedValue));
+ String autoResizeMetricName = "cache/chroniclemap/remaining_autoresizes_" + TEST_CACHE_NAME;
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", 2);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgKeySize", cachedValue.getBytes().length);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "avgValueSize", valueSize(cachedValue));
gerritConfig.save();
- ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(cachedValue);
+ ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(TEST_CACHE_NAME, cachedValue);
assertThat(getMetric(autoResizeMetricName).getValue()).isEqualTo(1);
@@ -397,12 +401,12 @@
int percentageHotKeys = 60;
int maxEntries = 10;
int expectedCapacity = 6;
- String hotKeysCapacityMetricName = "cache/chroniclemap/hot_keys_capacity_" + cachedValue;
- gerritConfig.setInt("cache", cachedValue, "maxEntries", maxEntries);
- gerritConfig.setInt("cache", cachedValue, "percentageHotKeys", percentageHotKeys);
+ String hotKeysCapacityMetricName = "cache/chroniclemap/hot_keys_capacity_" + TEST_CACHE_NAME;
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", maxEntries);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "percentageHotKeys", percentageHotKeys);
gerritConfig.save();
- ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(cachedValue);
+ ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(TEST_CACHE_NAME, cachedValue);
assertThat(getMetric(hotKeysCapacityMetricName).getValue()).isEqualTo(expectedCapacity);
}
@@ -414,12 +418,12 @@
int maxEntries = 10;
int maxHotKeyCapacity = 3;
final Duration METRIC_TRIGGER_TIMEOUT = Duration.ofSeconds(2);
- String hotKeysSizeMetricName = "cache/chroniclemap/hot_keys_size_" + cachedValue;
- gerritConfig.setInt("cache", cachedValue, "maxEntries", maxEntries);
- gerritConfig.setInt("cache", cachedValue, "percentageHotKeys", percentageHotKeys);
+ String hotKeysSizeMetricName = "cache/chroniclemap/hot_keys_size_" + TEST_CACHE_NAME;
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", maxEntries);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "percentageHotKeys", percentageHotKeys);
gerritConfig.save();
- ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(cachedValue);
+ ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(TEST_CACHE_NAME, cachedValue);
assertThat(getMetric(hotKeysSizeMetricName).getValue()).isEqualTo(0);
@@ -448,12 +452,12 @@
int maxEntries = 10;
int maxHotKeyCapacity = 3;
final Duration METRIC_TRIGGER_TIMEOUT = Duration.ofSeconds(2);
- String hotKeysSizeMetricName = "cache/chroniclemap/hot_keys_size_" + cachedValue;
- gerritConfig.setInt("cache", cachedValue, "maxEntries", maxEntries);
- gerritConfig.setInt("cache", cachedValue, "percentageHotKeys", percentageHotKeys);
+ String hotKeysSizeMetricName = "cache/chroniclemap/hot_keys_size_" + TEST_CACHE_NAME;
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "maxEntries", maxEntries);
+ gerritConfig.setInt("cache", TEST_CACHE_NAME, "percentageHotKeys", percentageHotKeys);
gerritConfig.save();
- ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(cachedValue);
+ ChronicleMapCacheImpl<String, String> cache = newCacheWithMetrics(TEST_CACHE_NAME, cachedValue);
for (int i = 0; i < maxHotKeyCapacity; i++) {
cache.put(cachedValue + i, cachedValue);
@@ -478,7 +482,7 @@
String autoResizeMetricName = "cache/chroniclemap/remaining_autoresizes_" + sanitized;
String hotKeyCapacityMetricName = "cache/chroniclemap/hot_keys_capacity_" + sanitized;
- newCacheWithMetrics(cacheName);
+ newCacheWithMetrics(cacheName, null);
getMetric(hotKeySizeMetricName);
getMetric(percentageFreeMetricName);
@@ -487,44 +491,61 @@
}
private int valueSize(String value) {
- final TimedValueMarshaller<String> marshaller =
- new TimedValueMarshaller<>(StringCacheSerializer.INSTANCE);
+ final TimedValueMarshaller<String> marshaller = new TimedValueMarshaller<>(TEST_CACHE_NAME);
Bytes<ByteBuffer> out = Bytes.elasticByteBuffer();
marshaller.write(out, new TimedValue<>(value));
return out.toByteArray().length;
}
- private ChronicleMapCacheImpl<String, String> newCacheWithMetrics(String cachedValue)
+ private ChronicleMapCacheImpl<String, String> newCacheWithMetrics(
+ String cacheName, @Nullable String cachedValue) throws IOException {
+ return newCache(true, cacheName, cachedValue, null, null, null, null, 1, metricMaker);
+ }
+
+ private ChronicleMapCacheImpl<String, String> newCacheWithMetrics(
+ String cacheName,
+ String cachedValue,
+ CacheSerializer<String> keySerializer,
+ CacheSerializer<String> valueSerializer)
throws IOException {
- return newCache(true, cachedValue, null, null, 1, metricMaker);
+ return newCache(
+ true, cacheName, cachedValue, null, null, null, null, 1, new DisabledMetricMaker());
}
private ChronicleMapCacheImpl<String, String> newCache(
Boolean withLoader,
- @Nullable String cachedValue,
+ String cacheName,
+ @Nullable String loadedValue,
@Nullable Duration expireAfterWrite,
@Nullable Duration refreshAfterWrite,
Integer version)
throws IOException {
return newCache(
withLoader,
- cachedValue,
+ cacheName,
+ loadedValue,
expireAfterWrite,
refreshAfterWrite,
+ null,
+ null,
version,
new DisabledMetricMaker());
}
private ChronicleMapCacheImpl<String, String> newCache(
Boolean withLoader,
+ String cacheName,
@Nullable String cachedValue,
@Nullable Duration expireAfterWrite,
@Nullable Duration refreshAfterWrite,
+ @Nullable CacheSerializer<String> keySerializer,
+ @Nullable CacheSerializer<String> valueSerializer,
Integer version,
MetricMaker metricMaker)
throws IOException {
- TestPersistentCacheDef cacheDef = new TestPersistentCacheDef(cachedValue);
+ TestPersistentCacheDef cacheDef =
+ new TestPersistentCacheDef(cacheName, cachedValue, keySerializer, valueSerializer);
File persistentFile =
ChronicleMapCacheFactory.fileName(
@@ -542,21 +563,21 @@
cacheDef, config, withLoader ? cacheDef.loader() : null, metricMaker);
}
- private ChronicleMapCacheImpl<String, String> newCacheWithLoader(@Nullable String cachedValue)
+ private ChronicleMapCacheImpl<String, String> newCacheWithLoader(@Nullable String loadedValue)
throws IOException {
- return newCache(true, cachedValue, null, null, 1);
+ return newCache(true, TEST_CACHE_NAME, loadedValue, null, null, 1);
}
private ChronicleMapCacheImpl<String, String> newCacheWithLoader() throws IOException {
- return newCache(true, null, null, null, 1);
+ return newCache(true, TEST_CACHE_NAME, null, null, null, 1);
}
private ChronicleMapCacheImpl<String, String> newCacheVersion(int version) throws IOException {
- return newCache(true, null, null, null, version);
+ return newCache(true, TEST_CACHE_NAME, null, null, null, version);
}
private ChronicleMapCacheImpl<String, String> newCacheWithoutLoader() throws IOException {
- return newCache(false, null, null, null, 1);
+ return newCache(false, TEST_CACHE_NAME, null, null, null, 1);
}
private <V> Gauge<V> getMetric(String name) {
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapterTest.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapterTest.java
deleted file mode 100644
index 09f7f17..0000000
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/ChronicleMapMarshallerAdapterTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// limitations under the License.
-// See the License for the specific language governing permissions and
-package com.googlesource.gerrit.modules.cache.chroniclemap;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import net.openhft.chronicle.bytes.Bytes;
-import org.eclipse.jgit.lib.ObjectId;
-import org.junit.Test;
-
-public class ChronicleMapMarshallerAdapterTest {
-
- @Test
- public void shouldDeserializeToTheSameObject() {
- ObjectId id = ObjectId.fromString("aabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
- byte[] serializedId = ObjectIdCacheSerializer.INSTANCE.serialize(id);
- ByteBuffer serializedIdWithLen = ByteBuffer.allocate(serializedId.length + 4);
- serializedIdWithLen.order(ByteOrder.LITTLE_ENDIAN);
- serializedIdWithLen.putInt(serializedId.length);
- serializedIdWithLen.put(serializedId);
-
- ChronicleMapMarshallerAdapter<ObjectId> marshaller =
- new ChronicleMapMarshallerAdapter<>(ObjectIdCacheSerializer.INSTANCE);
- ObjectId out = marshaller.read(Bytes.allocateDirect(serializedIdWithLen.array()), null);
-
- assertThat(id).isEqualTo(out);
- }
-
- @Test
- public void shouldSerializeToTheSameObject() {
- ObjectId id = ObjectId.fromString("aabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
- ChronicleMapMarshallerAdapter<ObjectId> marshaller =
- new ChronicleMapMarshallerAdapter<>(ObjectIdCacheSerializer.INSTANCE);
-
- Bytes<ByteBuffer> out = Bytes.elasticByteBuffer();
- marshaller.write(out, id);
- assertThat(marshaller.read(out, null)).isEqualTo(id);
- }
-}
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshallerTest.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshallerTest.java
new file mode 100644
index 0000000..44a5dd6
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/KeyWrapperMarshallerTest.java
@@ -0,0 +1,45 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.googlesource.gerrit.modules.cache.chroniclemap;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.gerrit.server.cache.serialize.ObjectIdCacheSerializer;
+import java.nio.ByteBuffer;
+import net.openhft.chronicle.bytes.Bytes;
+import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Before;
+import org.junit.Test;
+
+public class KeyWrapperMarshallerTest {
+ private static final String TEST_CACHE_NAME = "key-wrapper-test";
+
+ @Before
+ public void setup() {
+ CacheSerializers.registerCacheKeySerializer(TEST_CACHE_NAME, ObjectIdCacheSerializer.INSTANCE);
+ }
+
+ @Test
+ public void shouldSerializeAndDeserializeBack() {
+ ObjectId id = ObjectId.fromString("1234567890123456789012345678901234567890");
+ KeyWrapperMarshaller<ObjectId> marshaller = new KeyWrapperMarshaller<>(TEST_CACHE_NAME);
+
+ final KeyWrapper<ObjectId> wrapped = new KeyWrapper<>(id);
+
+ Bytes<ByteBuffer> out = Bytes.elasticByteBuffer();
+ marshaller.write(out, wrapped);
+ final KeyWrapper<ObjectId> actual = marshaller.read(out, null);
+ assertThat(actual).isEqualTo(wrapped);
+ }
+}
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TestPersistentCacheDef.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TestPersistentCacheDef.java
index b81baec..0e52f1d 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TestPersistentCacheDef.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TestPersistentCacheDef.java
@@ -21,42 +21,61 @@
import com.google.gerrit.server.cache.serialize.StringCacheSerializer;
import com.google.inject.TypeLiteral;
import java.time.Duration;
+import java.util.Optional;
import java.util.UUID;
public class TestPersistentCacheDef implements PersistentCacheDef<String, String> {
private static final Integer DEFAULT_DISK_LIMIT = 1024;
+ private final String name;
private final String loadedValue;
private final Duration expireAfterWrite;
private final Duration refreshAfterWrite;
private final Integer diskLimit;
+ private final CacheSerializer<String> keySerializer;
+ private final CacheSerializer<String> valueSerializer;
public TestPersistentCacheDef(
- String loadedValue,
+ String name,
+ @Nullable String loadedValue,
@Nullable Duration expireAfterWrite,
@Nullable Duration refreshAfterWrite) {
+ this.name = name;
this.loadedValue = loadedValue;
this.expireAfterWrite = expireAfterWrite;
this.refreshAfterWrite = refreshAfterWrite;
this.diskLimit = DEFAULT_DISK_LIMIT;
+ this.keySerializer = StringCacheSerializer.INSTANCE;
+ this.valueSerializer = StringCacheSerializer.INSTANCE;
}
- public TestPersistentCacheDef(String loadedValue, Integer diskLimit) {
+ public TestPersistentCacheDef(String name, @Nullable String loadedValue, Integer diskLimit) {
+ this.name = name;
this.loadedValue = loadedValue;
this.expireAfterWrite = null;
this.refreshAfterWrite = null;
this.diskLimit = diskLimit;
+ this.keySerializer = StringCacheSerializer.INSTANCE;
+ this.valueSerializer = StringCacheSerializer.INSTANCE;
}
- public TestPersistentCacheDef(String loadedValue) {
+ public TestPersistentCacheDef(
+ String name,
+ @Nullable String loadedValue,
+ @Nullable CacheSerializer<String> keySerializer,
+ @Nullable CacheSerializer<String> valueSerializer) {
+ this.name = name;
this.loadedValue = loadedValue;
this.expireAfterWrite = Duration.ZERO;
this.refreshAfterWrite = Duration.ZERO;
this.diskLimit = DEFAULT_DISK_LIMIT;
+ this.keySerializer = Optional.ofNullable(keySerializer).orElse(StringCacheSerializer.INSTANCE);
+ this.valueSerializer =
+ Optional.ofNullable(valueSerializer).orElse(StringCacheSerializer.INSTANCE);
}
@Override
@@ -71,17 +90,17 @@
@Override
public CacheSerializer<String> keySerializer() {
- return StringCacheSerializer.INSTANCE;
+ return keySerializer;
}
@Override
public CacheSerializer<String> valueSerializer() {
- return StringCacheSerializer.INSTANCE;
+ return valueSerializer;
}
@Override
public String name() {
- return loadedValue;
+ return name;
}
@Override
diff --git a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshallerTest.java b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshallerTest.java
index 62c1d44..b630e36 100644
--- a/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshallerTest.java
+++ b/src/test/java/com/googlesource/gerrit/modules/cache/chroniclemap/TimedValueMarshallerTest.java
@@ -19,16 +19,23 @@
import java.nio.ByteBuffer;
import net.openhft.chronicle.bytes.Bytes;
import org.eclipse.jgit.lib.ObjectId;
+import org.junit.Before;
import org.junit.Test;
public class TimedValueMarshallerTest {
+ private static final String TEST_CACHE_NAME = "timed-value-cache";
+
+ @Before
+ public void setup() {
+ CacheSerializers.registerCacheValueSerializer(
+ TEST_CACHE_NAME, ObjectIdCacheSerializer.INSTANCE);
+ }
@Test
public void shouldSerializeAndDeserializeBack() {
ObjectId id = ObjectId.fromString("1234567890123456789012345678901234567890");
long timestamp = 1600329018L;
- TimedValueMarshaller<ObjectId> marshaller =
- new TimedValueMarshaller<>(ObjectIdCacheSerializer.INSTANCE);
+ TimedValueMarshaller<ObjectId> marshaller = new TimedValueMarshaller<>(TEST_CACHE_NAME);
final TimedValue<ObjectId> wrapped = new TimedValue<>(id, timestamp);