#1427 - QueryCache should be cleared, if one of a dependent bean is updated

Initial work, does not include propagation across cluster.
This commit is contained in:
rob bygrave
2018-06-15 17:36:23 +12:00
parent 59537227b6
commit 96cc8d7605
51 changed files with 952 additions and 283 deletions
@@ -38,6 +38,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* An object that represents a SqlSelect statement.
@@ -811,4 +812,8 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
PreparedStatement getPstmt() {
return pstmt;
}
public Set<String> getDependentTables() {
return queryPlan.getDependentTables();
}
}
@@ -25,6 +25,8 @@ import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -111,6 +113,15 @@ public class CQueryEngine {
if (request.isLogSummary()) {
request.getTransaction().logSummary(rcQuery.getSummary());
}
if (request.isQueryCachePut() && !list.isEmpty()) {
request.addDependentTables(rcQuery.getDependentTables());
list = Collections.unmodifiableList(list);
request.putToQueryCache(list);
if (Boolean.FALSE.equals(request.getQuery().isReadOnly())) {
list = new ArrayList<>(list);
}
}
return list;
} catch (SQLException e) {
@@ -173,6 +184,11 @@ public class CQueryEngine {
request.getTransaction().end();
}
if (request.isQueryCachePut()) {
request.addDependentTables(rcQuery.getDependentTables());
request.putToQueryCache(count);
}
return count;
} catch (SQLException e) {
@@ -385,6 +401,9 @@ public class CQueryEngine {
}
request.executeSecondaryQueries(false);
if (request.isQueryCachePut()) {
request.addDependentTables(cquery.getDependentTables());
}
return beanCollection;
@@ -17,6 +17,7 @@ import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* Base compiled query request for single attribute queries.
@@ -188,4 +189,8 @@ class CQueryFetchSingleAttribute implements SpiProfileTransactionEvent {
.profileStream()
.addQueryEvent(query.profileEventId(), profileOffset, desc.getProfileId(), rowCount, query.getProfileId());
}
Set<String> getDependentTables() {
return queryPlan.getDependentTables();
}
}
@@ -24,6 +24,8 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Set;
/**
* Represents a query for a given SQL statement.
@@ -88,6 +90,8 @@ public class CQueryPlan {
*/
private volatile String auditQueryHash;
private final Set<String> dependentTables;
/**
* Create a query plan based on a OrmQueryRequest.
*/
@@ -110,6 +114,7 @@ public class CQueryPlan {
this.logWhereSql = logWhereSql;
this.encryptedProps = sqlTree.getEncryptedProps();
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.dependentTables = sqlTree.dependentTables();
}
/**
@@ -134,6 +139,7 @@ public class CQueryPlan {
this.logWhereSql = logWhereSql;
this.encryptedProps = sqlTree.getEncryptedProps();
this.stats = new CQueryPlanStats(this, server.isCollectQueryOrigins());
this.dependentTables = (rawSql) ? Collections.emptySet() : sqlTree.dependentTables();
}
private String location() {
@@ -154,6 +160,10 @@ public class CQueryPlan {
return beanType;
}
public Set<String> getDependentTables() {
return dependentTables;
}
public ProfileLocation getProfileLocation() {
return profileLocation;
}
@@ -12,6 +12,7 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Set;
/**
* Executes the select row count query.
@@ -154,4 +155,8 @@ class CQueryRowCount implements SpiProfileTransactionEvent {
.profileStream()
.addQueryEvent(query.profileEventId(), profileOffset, desc.getProfileId(), rowCount, query.getProfileId());
}
Set<String> getDependentTables() {
return queryPlan.getDependentTables();
}
}
@@ -88,41 +88,20 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
public <T> int findCount(OrmQueryRequest<T> request) {
flushJdbcBatchOnQuery(request);
int result = queryEngine.findCount(request);
if (request.getQuery().getUseQueryCache().isPut()) {
request.putToQueryCache(result);
}
return result;
return queryEngine.findCount(request);
}
@Override
public <A> List<A> findIds(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(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;
return queryEngine.findIds(request);
}
@Override
public <A> List<A> findSingleAttributeList(OrmQueryRequest<?> request) {
flushJdbcBatchOnQuery(request);
List<A> result = queryEngine.findSingleAttributeList(request);
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;
return queryEngine.findSingleAttributeList(request);
}
@Override
@@ -3,6 +3,7 @@ package io.ebeaninternal.server.query;
import io.ebeaninternal.api.SpiQuery;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -163,4 +164,13 @@ class SqlTree {
boolean isSingleProperty() {
return rootNode.isSingleProperty();
}
/**
* Return the tables that are joined in this query.
*/
Set<String> dependentTables() {
Set<String> tables = new LinkedHashSet<>();
rootNode.dependentTables(tables);
return tables;
}
}
@@ -9,6 +9,7 @@ import io.ebeaninternal.server.type.ScalarType;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
interface SqlTreeNode {
@@ -87,4 +88,9 @@ interface SqlTreeNode {
* Return true if the query is known to only have a single property selected.
*/
boolean isSingleProperty();
/**
* Add dependent tables to the given set.
*/
void dependentTables(Set<String> tables);
}
@@ -21,6 +21,7 @@ import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Normal bean included in the query.
@@ -578,6 +579,14 @@ class SqlTreeNodeBean implements SqlTreeNode {
}
}
@Override
public void dependentTables(Set<String> tables) {
tables.add(nodeBeanProp.target().getBaseTable(temporalMode));
for (SqlTreeNode child : children) {
child.dependentTables(tables);
}
}
/**
* Join to base table for this node. This includes a join to the intersection
* table if this is a ManyToMany node.
@@ -11,6 +11,7 @@ import io.ebeaninternal.server.type.ScalarType;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* The purpose is to add an extra join to the query.
@@ -100,6 +101,16 @@ class SqlTreeNodeExtraJoin implements SqlTreeNode {
children.add(child);
}
@Override
public void dependentTables(Set<String> tables) {
tables.add(assocBeanProperty.target().getBaseTable(SpiQuery.TemporalMode.CURRENT));
if (children != null) {
for (SqlTreeNode child : children) {
child.dependentTables(tables);
}
}
}
@Override
public void appendFrom(DbSqlContext ctx, SqlJoinType joinType) {
@@ -7,6 +7,7 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
final class SqlTreeNodeManyRoot extends SqlTreeNodeBean {
@@ -10,6 +10,7 @@ import io.ebeaninternal.server.deploy.TableJoin;
import io.ebeaninternal.server.type.ScalarType;
import java.util.List;
import java.util.Set;
/**
* Join to Many (or child of a many) to support where clause predicates on many properties.
@@ -109,6 +110,11 @@ class SqlTreeNodeManyWhereJoin implements SqlTreeNode {
}
}
@Override
public void dependentTables(Set<String> tables) {
tables.add(nodeBeanProp.target().getBaseTable(SpiQuery.TemporalMode.CURRENT));
}
@Override
public void buildRawSqlSelectChain(List<String> selectChain) {
// nothing to add
@@ -5,6 +5,7 @@ import io.ebeaninternal.server.deploy.DbSqlContext;
import io.ebeaninternal.server.deploy.TableJoin;
import java.util.List;
import java.util.Set;
/**
* Represents the root node of the Sql Tree.
@@ -77,4 +78,10 @@ final class SqlTreeNodeRoot extends SqlTreeNodeBean {
return joinType;
}
@Override
public void dependentTables(Set<String> tables) {
for (SqlTreeNode child : children) {
child.dependentTables(tables);
}
}
}