Merge pull request #2927 from FOCONIS/findset-beancache

NEW: BeanCache for findSet
This commit is contained in:
Rob Bygrave
2023-01-09 10:29:15 +13:00
committed by GitHub
4 changed files with 98 additions and 3 deletions
@@ -1091,7 +1091,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
public <T> Set<T> findSet(Query<T> query, Transaction transaction) {
SpiOrmQueryRequest request = createQueryRequest(Type.SET, query, transaction);
SpiOrmQueryRequest request = buildQueryRequest(Type.SET, query, transaction);
request.resetBeanCacheAutoMode(false);
if ((transaction == null || !transaction.isSkipCache()) && request.getFromBeanCache()) {
// hit bean cache and got all results from cache
return request.beanCacheHitsAsSet();
}
request.prepareQuery();
Object result = request.getFromQueryCache();
if (result != null) {
return (Set<T>) result;
@@ -515,12 +515,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
if (query.getType() == Type.MAP) {
mergeCacheHitsToMap(result);
} else {
mergeCacheHitsToList(result);
mergeCacheHitsToCollection(result);
}
}
}
private void mergeCacheHitsToList(BeanCollection<T> result) {
private void mergeCacheHitsToCollection(BeanCollection<T> result) {
for (T hit : cacheBeans) {
result.internalAdd(hit);
}
@@ -579,6 +579,15 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
return property;
}
@Override
public Set<T> beanCacheHitsAsSet() {
OrderBy<T> orderBy = query.getOrderBy();
if (orderBy != null && !orderBy.isEmpty()) {
beanDescriptor.sort(cacheBeans, orderBy.toStringFormat());
}
return new LinkedHashSet<>(cacheBeans);
}
@Override
public boolean getFromBeanCache() {
if (!query.isBeanCacheGet()) {
@@ -153,6 +153,11 @@ public interface SpiOrmQueryRequest<T> extends BeanQueryRequest<T>, DocQueryRequ
*/
<K> Map<K,T> beanCacheHitsAsMap();
/**
* Return the bean cache hits for findMap (when all hits / no misses).
*/
Set<T> beanCacheHitsAsSet();
/**
* Reset Bean cache mode AUTO - require explicit setting for bean cache use with findList().
*/
@@ -16,6 +16,7 @@ import org.tests.model.basic.OCachedBean;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
@@ -187,6 +188,80 @@ public class TestBeanCache extends BaseTestCase {
}
}
@Test
public void testFindSet() {
List<OCachedBean> beans = createBeans(Arrays.asList("z0", "z1", "z2"));
List<Long> ids = beans.stream().map(OCachedBean::getId).collect(Collectors.toList());
beanCache.clear();
beanCache.statistics(true);
LoggedSql.start();
log.info("All misses (0 of 3) ...");
Set<OCachedBean> set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertThat(set).hasSize(3);
assertBeanCacheHitMiss(0, 3);
List<String> sql = LoggedSql.collect();
assertThat(sql).hasSize(1);
if (isH2()) {
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?,?,?,?,?)");
}
log.info("All hits (3 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(3, 0);
assertThat(set).hasSize(3);
sql = LoggedSql.collect();
assertThat(sql).hasSize(0); // no misses
// remove a bean so that we get a "partial" hit (2 out of 3 in cache)
beanCache.remove(beans.get(0).getId().toString());
log.info("Partial hits (2 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(2, 1);
assertThat(set).hasSize(3);
sql = LoggedSql.collect();
assertThat(sql).hasSize(1);
if (isH2()) {
// fetch the miss from DB
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?)");
}
// remove beans so that we get a "partial" hit (1 out of 3 in cache)
beanCache.remove(beans.get(1).getId().toString());
beanCache.remove(beans.get(2).getId().toString());
log.info("Partial hits (1 of 3) ...");
set = DB.find(OCachedBean.class)
.where().idIn(ids)
.setUseCache(true)
.findSet();
assertBeanCacheHitMiss(1, 2);
assertThat(set).hasSize(3);
sql = LoggedSql.stop();
assertThat(sql).hasSize(1);
if (isH2()) {
// fetch the misses from DB
assertSql(sql.get(0)).contains("from o_cached_bean t0 where t0.id in (?,?,?,?,?)");
}
}
private void assertBeanCacheHitMiss(int hitCount, int missCount) {
ServerCacheStatistics statistics = beanCache.statistics(true);
assertThat(statistics.getHitCount()).isEqualTo(hitCount);