Feature/cache improvements 2 (#1067)

* New Mode to control queryCache behavior

* Collections form the cache have to be read only

* findCount not queried in query cache

* return modifiable collections from the cache

* FIX: Compile errors

* No effective code change: reformat code / javadoc
This commit is contained in:
Roland Praml
2017-09-12 23:40:18 +12:00
committed by Rob Bygrave
parent b8e1dffca2
commit a6e4e181bf
18 changed files with 587 additions and 38 deletions
@@ -1,5 +1,6 @@
package io.ebeaninternal.api;
import io.ebean.CacheMode;
import io.ebean.EbeanServer;
import io.ebean.ExpressionList;
import io.ebean.OrderBy;
@@ -583,9 +584,9 @@ public interface SpiQuery<T> extends Query<T> {
boolean isUseBeanCache();
/**
* Return true if this query should use/check the query cache.
* Return the cache mode if this query should use/check the query cache.
*/
boolean isUseQueryCache();
CacheMode getUseQueryCache();
/**
* Return true if the beans from this query should be loaded into the bean
@@ -35,6 +35,7 @@ import io.ebean.bean.ObjectGraphNode;
import io.ebean.bean.PersistenceContext;
import io.ebean.bean.PersistenceContext.WithOption;
import io.ebean.cache.ServerCacheManager;
import io.ebean.common.CopyOnFirstWriteList;
import io.ebean.config.CurrentTenantProvider;
import io.ebean.config.EncryptKeyManager;
import io.ebean.config.ServerConfig;
@@ -99,6 +100,7 @@ import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
@@ -1332,10 +1334,19 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return findIdsWithCopy(((SpiQuery<T>) query).copy(), t);
}
@SuppressWarnings("unchecked")
@Override
public <A, T> List<A> findIdsWithCopy(Query<T> query, Transaction t) {
SpiOrmQueryRequest<?> request = createQueryRequest(Type.ID_LIST, query, t);
Object result = request.getFromQueryCache();
if (result != null) {
if (Boolean.FALSE.equals(request.getQuery().isReadOnly())) {
return new CopyOnFirstWriteList<>((List<A>) result);
} else {
return (List<A>) result;
}
}
try {
request.initTransIfRequired();
return request.findIds();
@@ -1,11 +1,13 @@
package io.ebeaninternal.server.core;
import io.ebean.CacheMode;
import io.ebean.PersistenceContextScope;
import io.ebean.QueryIterator;
import io.ebean.Version;
import io.ebean.bean.BeanCollection;
import io.ebean.bean.EntityBean;
import io.ebean.bean.PersistenceContext;
import io.ebean.common.CopyOnFirstWriteList;
import io.ebean.event.BeanFindController;
import io.ebean.event.BeanQueryAdapter;
import io.ebean.event.BeanQueryRequest;
@@ -32,6 +34,8 @@ import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -471,12 +475,16 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
@SuppressWarnings("unchecked")
public Object getFromQueryCache() {
if (!query.isUseQueryCache()) {
if (query.getUseQueryCache() == CacheMode.OFF) {
return null;
} else {
cacheKey = query.queryHash();
}
if (!query.getUseQueryCache().isGet()) {
return null;
}
cacheKey = query.queryHash();
Object cached = beanDescriptor.queryCacheGet(cacheKey);
if (cached != null && isAuditReads() && readAuditQueryType()) {
@@ -491,6 +499,18 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
}
}
if (Boolean.FALSE.equals(query.isReadOnly())) {
// return shallow copies if readonly is explicitly set to false
if (cached instanceof BeanCollection) {
cached = ((BeanCollection<?>)cached).getShallowCopy();
} else if (cached instanceof List) {
cached = new CopyOnFirstWriteList<>((List)cached);
} else if (cached instanceof Set) {
cached = new LinkedHashSet<>((Set)cached);
} else if (cached instanceof Map) {
cached = new LinkedHashMap<>((Map)cached);
}
}
return cached;
}
@@ -463,7 +463,7 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
}
@Override
public Query<T> setUseQueryCache(boolean useCache) {
public Query<T> setUseQueryCache(CacheMode useCache) {
return query.setUseQueryCache(useCache);
}
@@ -742,7 +742,7 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
}
@Override
public Query<T> setUseQueryCache(boolean useCache) {
public Query<T> setUseQueryCache(CacheMode useCache) {
return exprList.setUseQueryCache(useCache);
}
@@ -13,7 +13,9 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import javax.persistence.PersistenceException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
@@ -71,7 +73,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
flushJdbcBatchOnQuery(request);
int result = queryEngine.findCount(request);
if (request.getQuery().isUseQueryCache()) {
if (request.getQuery().getUseQueryCache().isPut()) {
request.putToQueryCache(result);
}
return result;
@@ -81,16 +83,28 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
public <A> List<A> findIds(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
return queryEngine.findIds(request);
List<A> result = queryEngine.findIds(request);
if (request.getQuery().getUseQueryCache().isPut()) {
result = Collections.unmodifiableList(result);
request.putToQueryCache(result);
if (Boolean.FALSE.equals(request.getQuery().isReadOnly())) {
result = new ArrayList<>(result);
}
}
return result;
}
@Override
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
List<A> result = queryEngine.findSingleAttributeList(request);
if (!result.isEmpty() && request.getQuery().isUseQueryCache()) {
if (!result.isEmpty() && request.getQuery().getUseQueryCache().isPut()) {
// load the query result into the query cache
result = Collections.unmodifiableList(result);
request.putToQueryCache(result);
if (Boolean.FALSE.equals(request.getQuery().isReadOnly())) {
result = new ArrayList<>(result);
}
}
return result;
}
@@ -137,9 +151,13 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
}
}
if (!result.isEmpty() && query.isUseQueryCache()) {
if (!result.isEmpty() && query.getUseQueryCache().isPut()) {
// load the query result into the query cache
result.setReadOnly(true);
request.putToQueryCache(result);
if (Boolean.FALSE.equals(query.isReadOnly())) {
result = result.getShallowCopy();
}
}
return result;
@@ -1,5 +1,6 @@
package io.ebeaninternal.server.querydefn;
import io.ebean.CacheMode;
import io.ebean.EbeanServer;
import io.ebean.Expression;
import io.ebean.ExpressionFactory;
@@ -195,7 +196,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
private boolean excludeBeanCache;
private Boolean useQueryCache;
private CacheMode useQueryCache = CacheMode.OFF;
private Boolean readOnly;
@@ -1094,9 +1095,13 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@Override
public boolean isUseQueryCache() {
public CacheMode getUseQueryCache() {
// not using L2 cache for asDraft() query
return !isAsDraft() && Boolean.TRUE.equals(useQueryCache);
if (isAsDraft()) {
return CacheMode.OFF;
} else {
return useQueryCache;
}
}
@Override
@@ -1106,7 +1111,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
}
@Override
public DefaultOrmQuery<T> setUseQueryCache(boolean useQueryCache) {
public DefaultOrmQuery<T> setUseQueryCache(CacheMode useQueryCache) {
this.useQueryCache = useQueryCache;
return this;
}