diff --git a/src/main/java/io/ebean/cache/ServerCache.java b/src/main/java/io/ebean/cache/ServerCache.java index 243632d3d..438817f4b 100644 --- a/src/main/java/io/ebean/cache/ServerCache.java +++ b/src/main/java/io/ebean/cache/ServerCache.java @@ -17,9 +17,9 @@ import java.util.Set; */ public interface ServerCache { - default Map getAll(Set keys){ + default Map getAll(Set keys) { - Map map = new LinkedHashMap<>(); + Map map = new LinkedHashMap<>(); for (Object key : keys) { Object value = get(key); if (value != null) { @@ -34,15 +34,29 @@ public interface ServerCache { */ Object get(Object id); + /** + * Put all the values in the cache. + */ + default void putAll(Map keyValues) { + keyValues.forEach(this::put); + } + /** * Put the value in the cache with a given id. */ - Object put(Object id, Object value); + void put(Object id, Object value); + + /** + * Remove the entries from the cache given the id values. + */ + default void removeAll(Set keys) { + keys.forEach(this::remove); + } /** * Remove a entry from the cache given its id. */ - Object remove(Object id); + void remove(Object id); /** * Clear all entries from the cache. diff --git a/src/main/java/io/ebeaninternal/api/LoadBeanRequest.java b/src/main/java/io/ebeaninternal/api/LoadBeanRequest.java index 88b3881bd..3642daecd 100644 --- a/src/main/java/io/ebeaninternal/api/LoadBeanRequest.java +++ b/src/main/java/io/ebeaninternal/api/LoadBeanRequest.java @@ -157,9 +157,9 @@ public class LoadBeanRequest extends LoadRequest { for (Object aList : list) { EntityBean loadedBean = (EntityBean) aList; loadedIds.add(desc.getId(loadedBean)); - if (isLoadCache()) { - desc.cacheBeanPut(loadedBean); - } + } + if (isLoadCache()) { + desc.cacheBeanPutAll(list); } if (lazyLoadProperty != null) { diff --git a/src/main/java/io/ebeaninternal/server/cache/CacheChangeSet.java b/src/main/java/io/ebeaninternal/server/cache/CacheChangeSet.java index ba0e4ab49..f0c09f6cb 100644 --- a/src/main/java/io/ebeaninternal/server/cache/CacheChangeSet.java +++ b/src/main/java/io/ebeaninternal/server/cache/CacheChangeSet.java @@ -122,8 +122,7 @@ public class CacheChangeSet { */ private ManyChange many(BeanDescriptor desc, String manyProperty) { ManyKey key = new ManyKey(desc, manyProperty); - ManyChange manyChange = manyChangeMap.computeIfAbsent(key, ManyChange::new); - return manyChange; + return manyChangeMap.computeIfAbsent(key, ManyChange::new); } /** diff --git a/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java b/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java index 060e27701..b8bee5cc4 100644 --- a/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java +++ b/src/main/java/io/ebeaninternal/server/cache/DefaultServerCache.java @@ -6,15 +6,14 @@ import io.ebean.cache.ServerCacheOptions; import io.ebean.cache.ServerCacheStatistics; import io.ebean.cache.TenantAwareKey; import io.ebean.config.CurrentTenantProvider; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; -import java.util.List; import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -217,20 +216,23 @@ public class DefaultServerCache implements ServerCache { } } + @Override + public void putAll(Map keyValues) { + keyValues.forEach(this::put); + } + /** * Put a value into the cache. */ @Override - public Object put(Object id, Object value) { + public void put(Object id, Object value) { Object key = key(id); CacheEntry entry = map.put(key, new CacheEntry(key, value)); if (entry == null) { insertCount.increment(); - return null; } else { updateCount.increment(); - return entry.getValue(); } } @@ -238,14 +240,11 @@ public class DefaultServerCache implements ServerCache { * Remove an entry from the cache. */ @Override - public Object remove(Object id) { + public void remove(Object id) { CacheEntry entry = map.remove(key(id)); - if (entry == null) { - return null; - } else { + if (entry != null) { removeCount.increment(); - return entry.getValue(); } } @@ -359,10 +358,8 @@ public class DefaultServerCache implements ServerCache { private static final long serialVersionUID = 1L; @Override - public int compare(CacheEntry entry1, CacheEntry entry2) { - long x = entry1.getLastAccessTime(); - long y = entry2.getLastAccessTime(); - return (x < y) ? -1 : ((x == y) ? 0 : 1); + public int compare(CacheEntry e1, CacheEntry e2) { + return Long.compare(e1.getLastAccessTime(), e2.getLastAccessTime()); } } diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 450b60cf8..b979463d1 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -33,6 +33,8 @@ import io.ebean.plugin.BeanDocType; import io.ebean.plugin.BeanType; import io.ebean.plugin.ExpressionPath; import io.ebean.plugin.Property; +import io.ebean.util.SplitName; +import io.ebeaninternal.api.BeanCacheResult; import io.ebeaninternal.api.CQueryPlanKey; import io.ebeaninternal.api.ConcurrencyMode; import io.ebeaninternal.api.LoadContext; @@ -62,8 +64,6 @@ import io.ebeaninternal.server.el.ElPropertyValue; import io.ebeaninternal.server.persist.DmlUtil; import io.ebeaninternal.server.query.CQueryPlan; import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot; -import io.ebean.util.SplitName; -import io.ebeaninternal.api.BeanCacheResult; import io.ebeaninternal.server.querydefn.OrmQueryDetail; import io.ebeaninternal.server.rawsql.SpiRawSql; import io.ebeaninternal.server.text.json.ReadJson; @@ -1348,6 +1348,17 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType { cacheHelp.beanCachePut(bean); } + @SuppressWarnings("unchecked") + public void cacheBeanPutAll(Collection beans) { + if (!beans.isEmpty()) { + cacheHelp.beanPutAll((Collection)beans); + } + } + + void cacheBeanPutAllDirect(Collection beans) { + cacheHelp.beanCachePutAllDirect(beans); + } + /** * Put a bean into the cache as the correct type. */ diff --git a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java index b0dd83748..97883d3d5 100644 --- a/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java +++ b/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java @@ -418,6 +418,22 @@ final class BeanDescriptorCacheHelp { return CachedBeanDataFromBean.extract(targetDesc, bean); } + void beanPutAll(Collection beans) { + if (desc.inheritInfo != null) { + Class aClass = theClassOf(beans); + desc.descOf(aClass).cacheBeanPutAllDirect(beans); + } else { + beanCachePutAllDirect(beans); + } + } + + private Class theClassOf(Collection beans) { + if (beans instanceof List) { + return ((List)beans).get(0).getClass(); + } + return beans.iterator().next().getClass(); + } + /** * Put a bean into the bean cache. */ @@ -430,9 +446,41 @@ final class BeanDescriptorCacheHelp { } } + void beanCachePutAllDirect(Collection beans) { + + Map natKeys = null; + if (naturalKey != null) { + natKeys = new LinkedHashMap<>(); + } + + Map map = new LinkedHashMap<>(); + for (EntityBean bean : beans) { + CachedBeanData beanData = beanExtractData(desc, bean); + Object id = desc.getId(bean); + map.put(id, beanData); + if (naturalKey != null) { + Object naturalKey = calculateNaturalKey(beanData); + if (naturalKey != null) { + natKeys.put(naturalKey, id); + } + } + } + if (beanLog.isDebugEnabled()) { + beanLog.debug(" PUT ALL {}({})", cacheName, map.keySet()); + } + getBeanCache().putAll(map); + + if (natKeys != null && !natKeys.isEmpty()) { + if (natLog.isDebugEnabled()) { + natLog.debug(" PUT ALL {}({}, {})", cacheName, naturalKey, natKeys.keySet()); + } + naturalKeyCache.putAll(natKeys); + } + } + /** - * Put the bean into the bean cache. - */ + * Put the bean into the bean cache. + */ void beanCachePutDirect(EntityBean bean) { CachedBeanData beanData = beanExtractData(desc, bean); @@ -494,6 +542,9 @@ final class BeanDescriptorCacheHelp { } return null; } + if (beanLog.isTraceEnabled()) { + beanLog.trace(" GET {}({}) - hit", cacheName, id); + } return convertToBean(id, readOnly, context, data); } @@ -558,9 +609,6 @@ final class BeanDescriptorCacheHelp { ebi.setPersistenceContext(context); desc.contextPut(context, id, bean); - if (beanLog.isTraceEnabled()) { - beanLog.trace(" GET {}({}) - hit", cacheName, id); - } if (desc.isReadAuditing()) { desc.readAuditBean("l2", "", bean); } diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java index c1efc43f1..f4764b63f 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultOrmQueryEngine.java @@ -155,9 +155,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine { // load the individual beans into the bean cache BeanDescriptor descriptor = request.getBeanDescriptor(); Collection c = result.getActualDetails(); - for (T bean : c) { - descriptor.cacheBeanPut((EntityBean) bean); - } + descriptor.cacheBeanPutAll(c); } request.mergeCacheHits(result);