getIfPresent: fallback to fetching from store if isn't in memory

Align the implementation with what the H2 version of the cache was
doing, by always looking at the store as 2nd chance when the in-memory
cache not have the requested key when calling getIfPresent.

Bug: Issue 16496
Change-Id: I8ab5bdbaba3e3338257446623f696ce5c9748415
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 7efc8b5..4fef85e 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
@@ -26,6 +26,7 @@
 import java.sql.Timestamp;
 import java.time.Duration;
 import java.time.Instant;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
@@ -157,14 +158,19 @@
     return config;
   }
 
+  @SuppressWarnings("unchecked")
   @Override
   public V getIfPresent(Object objKey) {
-    TimedValue<V> timedValue = mem.getIfPresent(objKey);
+    K key = (K) objKey;
+
+    TimedValue<V> timedValue =
+        Optional.ofNullable(mem.getIfPresent(key)).orElse(memLoader.loadIfPresent(key));
     if (timedValue == null) {
       missCount.increment();
       return null;
     }
 
+    mem.put(key, timedValue);
     keysIndex.add(objKey, timedValue.getCreated());
     return timedValue.getValue();
   }
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 b943c07..e697662 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
@@ -87,6 +87,30 @@
   }
 
   @Test
+  public void getIfPresentShouldReturnValueWhenKeyIsPresentInMemory() throws Exception {
+    String key = "fookey";
+    String value = "foovalue";
+    ChronicleMapCacheImpl<String, String> cache = newCacheWithLoader(null);
+
+    cache.put(key, value);
+    assertThat(cache.getIfPresent(key)).isEqualTo(value);
+  }
+
+  @Test
+  public void getIfPresentShouldReturnValueWhenKeyIsPresentOnDisk() throws Exception {
+    String key = "fookey";
+    String value = "foovalue";
+
+    // Store the key-value pair and clone/release of the in-memory copy
+    ChronicleMapCacheImpl<String, String> cacheInMemory = newCacheWithLoader(null);
+    cacheInMemory.put(key, value);
+    cacheInMemory.close();
+
+    ChronicleMapCacheImpl<String, String> cache = newCacheWithLoader(null);
+    assertThat(cache.getIfPresent(key)).isEqualTo(value);
+  }
+
+  @Test
   public void getIfPresentShouldReturnNullWhenThereCacheHasADifferentVersion() throws Exception {
     gerritConfig.setString("cache", null, "directory", "cache");
     gerritConfig.save();