-
-
Notifications
You must be signed in to change notification settings - Fork 263
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimized cache handling (QueryCache for findId, use QueryCache before BeanCache) #2937
base: master
Are you sure you want to change the base?
Conversation
fd67fc5
to
afc789d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @rbygrave
I'm finished with this change. I tried to separate this PR in easily reviewable commits.
Can you review this as one PR or should I create one PR after the other.
What do you think about the change of first hitting the (faster) QueryCache and then the (slower) BeanCache?
@@ -687,7 +722,7 @@ private boolean readAuditQueryType() { | |||
} | |||
|
|||
public void putToQueryCache(Object result) { | |||
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, dependentTables, transaction.getStartNanoTime())); | |||
beanDescriptor.queryCachePut(cacheKey, new QueryCacheEntry(result, queryPlan.dependentTables(), transaction.getStartNanoTime())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
During an ormQueryRequest, the current queryPlan should be always present, so it should be safe, to use it here. I did not see any code, that calls "addDependetTables" multiple times.
if (o != null) { | ||
if (o.isDeleted()) { | ||
// Bean was previously deleted in the same transaction / persistence context | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
returning "null" here, means that we will not find anything, even if we hit the DB again (see failing test)
} | ||
BeanDescriptor<T> desc = spiQuery.getBeanDescriptor(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is mainly the inlined findIdCheckPersistenceContextAndCache.
I did not find an easy way to split it into separate methods. What do you think, can we keep this so or should I try to reduce complexity of that method
@@ -1093,15 +1103,18 @@ private <T> T extractUnique(List<T> list) { | |||
public <T> Set<T> findSet(Query<T> query, Transaction transaction) { | |||
SpiOrmQueryRequest request = buildQueryRequest(Type.SET, query, transaction); | |||
request.resetBeanCacheAutoMode(false); | |||
if (request.isQueryCacheActive()) { | |||
request.prepareQuery(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think, the queryCache should be checked BEFORE the bean cache.
@@ -68,6 +70,7 @@ public boolean isDeleteByStatement() { | |||
} else { | |||
// delete by ids due to cascading delete needs | |||
queryPlanKey = query.setDeleteByIdsPlan(); | |||
queryPlan = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when the queryPlanKey changes, we must throw away also the cached queryPlan
beanDescriptor.prepareQuery(query); | ||
adapterPreQuery(); | ||
queryPlanKey = query.prepare(this); | ||
if (!prepared) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prepareQuery is only executed once now
@@ -469,7 +486,10 @@ public BeanPropertyAssocMany<?> manyPropertyForOrderBy() { | |||
* query plan for this query exists. | |||
*/ | |||
public CQueryPlan queryPlan() { | |||
return beanDescriptor.queryPlan(queryPlanKey); | |||
if (queryPlan == null) { | |||
queryPlan = beanDescriptor.queryPlan(queryPlanKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here we cache the current query plan, that made the "dependentTables" refactoring possible
c0Back = DB.find(Customer.class, c0.getId()); | ||
c1Back = DB.find(Customer.class, "" + c1.getId()); | ||
assertThat(LoggedSql.stop()).isEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not hit the DB (but it currently does on master branch)
…use QueryCache before BeanCache)
791e85a
to
d79867f
Compare
In this PR I'll try to improve the cache-handling in ebean.
Some important notes about Caches (maybe worth to add to documentation)