Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements SpiOrmQuery
private SpiQuerySecondary secondaryQueries;
private List<T> cacheBeans;
private boolean inlineCountDistinct;
private Set<String> dependentTables;
private SpiQueryManyJoin manyJoin;

public OrmQueryRequest(SpiEbeanServer server, OrmQueryEngine queryEngine, SpiQuery<T> query, SpiTransaction t) {
Expand Down Expand Up @@ -667,7 +666,11 @@ private boolean readAuditQueryType() {
}

public void putToQueryCache(Object result) {
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, dependentTables, transaction.startTime()));
CQueryPlan plan = queryPlan();
if (plan != null) {
// only cache when we have the plan's dependent tables
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, plan.dependentTables(), transaction.startTime()));
}
}

/**
Expand Down Expand Up @@ -737,15 +740,6 @@ public boolean isInlineCountDistinct() {
return inlineCountDistinct;
}

public void addDependentTables(Set<String> tables) {
if (tables != null && !tables.isEmpty()) {
if (dependentTables == null) {
dependentTables = new LinkedHashSet<>();
}
dependentTables.addAll(tables);
}
}

/**
* Return true if no MaxRows or use LIMIT in SQL update.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -768,8 +768,4 @@ PreparedStatement pstmt() {
public void handleLoadError(String fullName, Exception e) {
query.handleLoadError(fullName, e);
}

public Set<String> dependentTables() {
return queryPlan.dependentTables();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ private <A extends Collection<?>> A findAttributeCollection(OrmQueryRequest<?> r
request.transaction().logSummary(rcQuery.summary());
}
if (request.isQueryCachePut()) {
request.addDependentTables(rcQuery.dependentTables());
if (collection instanceof List) {
collection = (A) Collections.unmodifiableList((List<?>) collection);
request.putToQueryCache(collection);
Expand Down Expand Up @@ -163,7 +162,6 @@ public <T> int findCount(OrmQueryRequest<T> request) {
request.transaction().logSummary(rcQuery.summary());
}
if (request.isQueryCachePut()) {
request.addDependentTables(rcQuery.dependentTables());
request.putToQueryCache(count);
}
return count;
Expand Down Expand Up @@ -355,9 +353,6 @@ <T> BeanCollection<T> findMany(OrmQueryRequest<T> request) {
}
request.executeSecondaryQueries(false);
request.populateFromImmutableCache();
if (request.isQueryCachePut()) {
request.addDependentTables(cquery.dependentTables());
}
request.unmodifiableFreeze(beanCollection);
return beanCollection;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

import static java.lang.System.Logger.Level.ERROR;
Expand Down Expand Up @@ -168,10 +167,6 @@ public void profile() {
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
}

Set<String> dependentTables() {
return queryPlan.dependentTables();
}

@Override
public void cancel() {
lock.lock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public final class CQueryPlanStats {
CQueryPlanStats(CQueryPlan queryPlan) {
this.queryPlan = queryPlan;
this.timedMetric = queryPlan.createTimedMetric();
// treat newly built plan as recently used to avoid trim
this.lastQueryTime = System.currentTimeMillis();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
Expand Down Expand Up @@ -140,10 +139,6 @@ public void profile() {
.addQueryEvent(query.profileEventId(), profileOffset, desc.name(), rowCount, query.profileId(), queryPlan.hash(), query.getGeneratedSql());
}

Set<String> dependentTables() {
return queryPlan.dependentTables();
}

@Override
public void cancel() {
lock.lock();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.tests.cache;

import io.ebean.xtest.BaseTestCase;
import io.ebean.CacheMode;
import io.ebean.DB;
import io.ebean.Query;
import io.ebean.cache.ServerCache;
import io.ebean.test.LoggedSql;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.Address;
Expand Down Expand Up @@ -191,4 +193,98 @@ public void testCache_withEnabeldQueryCache() throws InterruptedException {
DB.delete(child);
DB.delete(root);
}

/**
* findSingleAttributeList caches with dependent tables sourced from the query plan.
* A change to the joined (dependent) table must invalidate the query cache entry.
*/
@Test
public void testFindSingleAttributeOnDependent() throws InterruptedException {
Address addr = new Address();
addr.setCity("qcache-sa-city");
DB.save(addr);

Customer cust = new Customer();
cust.setName("qcache-sa-cust");
cust.setBillingAddress(addr);
DB.save(cust);

DB.cacheManager().queryCache(Customer.class).clear();
Thread.sleep(10);

LoggedSql.start();
List<String> first = namesByBillingCity("qcache-sa-city");
assertThat(LoggedSql.stop()).as("first call executes SQL").hasSize(1);
assertThat(first).containsExactly("qcache-sa-cust");

LoggedSql.start();
List<String> second = namesByBillingCity("qcache-sa-city");
assertThat(LoggedSql.stop()).as("second call is a query cache hit").isEmpty();
assertThat(second).isEqualTo(first);

// modify the joined (dependent) o_address table -> evict the Customer query cache
addr.setCity("qcache-sa-city2");
DB.save(addr);

LoggedSql.start();
List<String> third = namesByBillingCity("qcache-sa-city");
assertThat(LoggedSql.stop()).as("cache invalidated after dependent table change").hasSize(1);
assertThat(third).isEmpty();

DB.delete(cust);
}

/**
* findList (unmodifiable query cache) caches with dependent tables sourced from the
* query plan. A change to the joined (dependent) table must invalidate the entry.
*/
@Test
public void testFindListOnDependent() throws InterruptedException {
Address addr = new Address();
addr.setCity("qcache-list-city");
DB.save(addr);

Customer cust = new Customer();
cust.setName("qcache-list-cust");
cust.setBillingAddress(addr);
DB.save(cust);

DB.cacheManager().queryCache(Customer.class).clear();
Thread.sleep(10);

LoggedSql.start();
List<Customer> first = customersByBillingCity("qcache-list-city");
assertThat(LoggedSql.stop()).as("first call executes SQL").hasSize(1);
assertThat(first).hasSize(1);

LoggedSql.start();
List<Customer> second = customersByBillingCity("qcache-list-city");
assertThat(LoggedSql.stop()).as("second call is a query cache hit").isEmpty();
assertThat(second).isSameAs(first);

// modify the joined (dependent) o_address table -> evict the Customer query cache
addr.setCity("qcache-list-city2");
DB.save(addr);

LoggedSql.start();
List<Customer> third = customersByBillingCity("qcache-list-city");
assertThat(LoggedSql.stop()).as("cache invalidated after dependent table change").hasSize(1);
assertThat(third).isEmpty();

DB.delete(cust);
}

private List<String> namesByBillingCity(String city) {
return DB.find(Customer.class).setUseQueryCache(CacheMode.ON)
.select("name")
.where().eq("billingAddress.city", city)
.orderBy("name")
.findSingleAttributeList();
}

private List<Customer> customersByBillingCity(String city) {
return DB.find(Customer.class).setUseQueryCache(CacheMode.ON)
.where().eq("billingAddress.city", city)
.findList();
}
}
Loading