Skip to content
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

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

rPraml
Copy link
Contributor

@rPraml rPraml commented Jan 19, 2023

In this PR I'll try to improve the cache-handling in ebean.

Some important notes about Caches (maybe worth to add to documentation)

  • While BeanCaches store objects in serialized form as "Key/value" pairs, QueryCaches are real object-caches, that means, you get references to an existing object. No deserializion is needed
  • if you modify such a object, you modify the object in the cache and the next query will give you that object
  • There is some code to do "shallow copies" on read/write queries on lists, but not for beans in that list
  • it may be a good idea to use "setUseQueryCache" always with "setUseReadOnly"
  • The "DefaultServerCache" (used for bean & query-cache) implementation has some logic to remove old entries, but it uses internally SoftReferences, so that the GC can remove every entry at any time if it comes to a low memory situation (in other words, there is no guarantee that entries will remain in the cache for the specified TTL times etc.)

@rPraml rPraml changed the title [In progress] Optimized dependent table handling (RPr) [In progress] Optimized cache handling (RPr) Jan 19, 2023
Copy link
Contributor Author

@rPraml rPraml left a 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()));
Copy link
Contributor Author

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;
Copy link
Contributor Author

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();
Copy link
Contributor Author

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();
Copy link
Contributor Author

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;
Copy link
Contributor Author

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) {
Copy link
Contributor Author

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);
Copy link
Contributor Author

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();
Copy link
Contributor Author

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)

@rPraml rPraml changed the title [In progress] Optimized cache handling (RPr) Optimized cache handling (QueryCache for findId, use QueryCache before BeanCache) Jan 19, 2023
rPraml added a commit to FOCONIS/ebean that referenced this pull request Aug 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant