From c2a30f786f6b329f6e3eecba6b4d117f44ffba96 Mon Sep 17 00:00:00 2001 From: rob bygrave Date: Sun, 17 Nov 2019 17:06:38 +1300 Subject: [PATCH] #1864 - L2 cache miss for natural key property of type UUID --- .../io/ebeaninternal/api/NaturalKeyEntry.java | 2 +- .../api/NaturalKeyEntryBasic.java | 6 +- .../api/NaturalKeyEntrySimple.java | 12 +-- .../server/deploy/BeanNaturalKey.java | 6 +- .../model/basic/cache/OCachedNkeyUid.java | 28 +++++++ .../model/basic/cache/TestNatKeyUid.java | 82 +++++++++++++++++++ 6 files changed, 122 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/tests/model/basic/cache/OCachedNkeyUid.java create mode 100644 src/test/java/org/tests/model/basic/cache/TestNatKeyUid.java diff --git a/src/main/java/io/ebeaninternal/api/NaturalKeyEntry.java b/src/main/java/io/ebeaninternal/api/NaturalKeyEntry.java index ffee04f37..f53e6a56b 100644 --- a/src/main/java/io/ebeaninternal/api/NaturalKeyEntry.java +++ b/src/main/java/io/ebeaninternal/api/NaturalKeyEntry.java @@ -8,7 +8,7 @@ public interface NaturalKeyEntry { /** * Return the natural cache key (String concatenation of values). */ - Object key(); + String key(); /** * Return the inValue (used to remove from IN clause of original query). diff --git a/src/main/java/io/ebeaninternal/api/NaturalKeyEntryBasic.java b/src/main/java/io/ebeaninternal/api/NaturalKeyEntryBasic.java index e4e4d9acb..aff59771b 100644 --- a/src/main/java/io/ebeaninternal/api/NaturalKeyEntryBasic.java +++ b/src/main/java/io/ebeaninternal/api/NaturalKeyEntryBasic.java @@ -14,7 +14,7 @@ import java.util.Map; class NaturalKeyEntryBasic implements NaturalKeyEntry { private final Map map = new HashMap<>(); - private final Object key; + private final String key; private Object inValue; /** @@ -57,12 +57,12 @@ class NaturalKeyEntryBasic implements NaturalKeyEntry { } } - private Object calculateKey(BeanNaturalKey naturalKey) { + private String calculateKey(BeanNaturalKey naturalKey) { return naturalKey.calculateKey(map); } @Override - public Object key() { + public String key() { return key; } diff --git a/src/main/java/io/ebeaninternal/api/NaturalKeyEntrySimple.java b/src/main/java/io/ebeaninternal/api/NaturalKeyEntrySimple.java index b3daf0a59..0fa7bef62 100644 --- a/src/main/java/io/ebeaninternal/api/NaturalKeyEntrySimple.java +++ b/src/main/java/io/ebeaninternal/api/NaturalKeyEntrySimple.java @@ -2,19 +2,21 @@ package io.ebeaninternal.api; class NaturalKeyEntrySimple implements NaturalKeyEntry { - private final Object key; + private final String key; + private final Object val; - NaturalKeyEntrySimple(Object key) { - this.key = key; + NaturalKeyEntrySimple(Object val) { + this.key = val.toString(); + this.val = val; } @Override - public Object key() { + public String key() { return key; } @Override public Object getInValue() { - return key; + return val; } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanNaturalKey.java b/src/main/java/io/ebeaninternal/server/deploy/BeanNaturalKey.java index 2318aac11..57f6c2512 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanNaturalKey.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanNaturalKey.java @@ -66,11 +66,7 @@ public class BeanNaturalKey { * * @param map The bind values for the properties. */ - public Object calculateKey(Map map) { - if (naturalKey.length == 1) { - return map.get(naturalKey[0]); - } - + public String calculateKey(Map map) { StringBuilder sb = new StringBuilder(); for (BeanProperty prop : props) { sb.append(prop.naturalKeyVal(map)).append(";"); diff --git a/src/test/java/org/tests/model/basic/cache/OCachedNkeyUid.java b/src/test/java/org/tests/model/basic/cache/OCachedNkeyUid.java new file mode 100644 index 000000000..692f2c0aa --- /dev/null +++ b/src/test/java/org/tests/model/basic/cache/OCachedNkeyUid.java @@ -0,0 +1,28 @@ +package org.tests.model.basic.cache; + +import io.ebean.annotation.Cache; + +import javax.persistence.Entity; +import java.util.UUID; + +@Cache(naturalKey = "uid") +@Entity +public class OCachedNkeyUid extends OCacheBase { + + private UUID uid; + + private String other; + + public OCachedNkeyUid(UUID uid, String other) { + this.uid = uid; + this.other = other; + } + + public UUID getUid() { + return uid; + } + + public String getOther() { + return other; + } +} diff --git a/src/test/java/org/tests/model/basic/cache/TestNatKeyUid.java b/src/test/java/org/tests/model/basic/cache/TestNatKeyUid.java new file mode 100644 index 000000000..573d643fb --- /dev/null +++ b/src/test/java/org/tests/model/basic/cache/TestNatKeyUid.java @@ -0,0 +1,82 @@ +package org.tests.model.basic.cache; + +import io.ebean.BaseTestCase; +import io.ebean.DB; +import io.ebean.cache.ServerCacheStatistics; +import org.ebeantest.LoggedSqlCollector; +import org.junit.Test; + +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNotNull; + +public class TestNatKeyUid extends BaseTestCase { + + private static boolean seededData; + private static UUID one = UUID.randomUUID(); + private static UUID two = UUID.randomUUID(); + + private ServerCacheStatistics appStats() { + return getBeanCacheStats(OCachedNkeyUid.class, true); + } + + @Test + public void test_findOne() { + + setupData(); + clearAllL2Cache(); + + OCachedNkeyUid found1 = findOne(); + assertNotNull(found1); + assertThat(appStats().getHitCount()).isEqualTo(0); + + found1 = findOne(); + assertNotNull(found1); + assertThat(appStats().getHitCount()).isEqualTo(1); + } + + private OCachedNkeyUid findOne() { + + return DB.find(OCachedNkeyUid.class) + .where() + .eq("uid", one) + .findOne(); + } + + @Test + public void test_findMany() { + + setupData(); + clearAllL2Cache(); + + List result = findMany(); + assertThat(result).hasSize(2); + assertThat(appStats().getHitCount()).isEqualTo(0); + + LoggedSqlCollector.start(); + result = findMany(); + assertThat(result).hasSize(2); + assertThat(appStats().getHitCount()).isEqualTo(2); + + final List sql = LoggedSqlCollector.stop(); + assertThat(sql).as("Expected hit cache, no sql").isEmpty(); + } + + private List findMany() { + return DB.find(OCachedNkeyUid.class) + .setUseCache(true) + .where() + .in("uid", one, two) + .findList(); + } + + private void setupData() { + if (!seededData) { + seededData = true; + new OCachedNkeyUid(one, "o1").save(); + new OCachedNkeyUid(two, "o2").save(); + } + } +}