diff --git a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java index 8abaf3d131..5d9ebe25b9 100644 --- a/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java +++ b/ebean-api/src/main/java/io/ebean/config/DatabaseConfig.java @@ -441,6 +441,8 @@ public class DatabaseConfig { private int backgroundExecutorShutdownSecs = 30; private BackgroundExecutorWrapper backgroundExecutorWrapper = new MdcBackgroundExecutorWrapper(); + private boolean tenantPartitionedCache; + // defaults for the L2 bean caching private int cacheMaxSize = 10000; @@ -1470,6 +1472,21 @@ public void setBackgroundExecutorWrapper(BackgroundExecutorWrapper backgroundExe this.backgroundExecutorWrapper = backgroundExecutorWrapper; } + /** + * Returns, if the caches are partitioned by tenant. + */ + public boolean isTenantPartitionedCache() { + return tenantPartitionedCache; + } + + /** + * Sets the tenant partitioning mode for caches. This means, caches are created on demand, + * but they may not get invalidated across tenant boundaries * + */ + public void setTenantPartitionedCache(boolean tenantPartitionedCache) { + this.tenantPartitionedCache = tenantPartitionedCache; + } + /** * Return the L2 cache default max size. */ @@ -2949,6 +2966,15 @@ protected void loadSettings(PropertiesWrapper p) { ddlPlaceholders = p.get("ddl.placeholders", ddlPlaceholders); ddlHeader = p.get("ddl.header", ddlHeader); + tenantPartitionedCache = p.getBoolean("tenantPartitionedCache", tenantPartitionedCache); + + cacheMaxIdleTime = p.getInt("cacheMaxIdleTime", cacheMaxIdleTime); + cacheMaxSize = p.getInt("cacheMaxSize", cacheMaxSize); + cacheMaxTimeToLive = p.getInt("cacheMaxTimeToLive", cacheMaxTimeToLive); + queryCacheMaxIdleTime = p.getInt("queryCacheMaxIdleTime", queryCacheMaxIdleTime); + queryCacheMaxSize = p.getInt("queryCacheMaxSize", queryCacheMaxSize); + queryCacheMaxTimeToLive = p.getInt("queryCacheMaxTimeToLive", queryCacheMaxTimeToLive); + // read tenant-configuration from config: // tenant.mode = NONE | DB | SCHEMA | CATALOG | PARTITION String mode = p.get("tenant.mode"); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/CacheManagerOptions.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/CacheManagerOptions.java index ae0c10f4c1..d1ed0efdfd 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/CacheManagerOptions.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/CacheManagerOptions.java @@ -13,18 +13,20 @@ public final class CacheManagerOptions { private final ClusterManager clusterManager; - private final DatabaseConfig databaseConfig; + private final String serverName; private final boolean localL2Caching; private CurrentTenantProvider currentTenantProvider; private QueryCacheEntryValidate queryCacheEntryValidate; private ServerCacheFactory cacheFactory = new DefaultServerCacheFactory(); private ServerCacheOptions beanDefault = new ServerCacheOptions(); private ServerCacheOptions queryDefault = new ServerCacheOptions(); + private final boolean tenantPartitionedCache; CacheManagerOptions() { this.localL2Caching = true; this.clusterManager = null; - this.databaseConfig = null; + this.serverName = "db"; + this.tenantPartitionedCache = false; this.cacheFactory = new DefaultServerCacheFactory(); this.beanDefault = new ServerCacheOptions(); this.queryDefault = new ServerCacheOptions(); @@ -32,9 +34,10 @@ public final class CacheManagerOptions { public CacheManagerOptions(ClusterManager clusterManager, DatabaseConfig config, boolean localL2Caching) { this.clusterManager = clusterManager; - this.databaseConfig = config; + this.serverName = config.getName(); this.localL2Caching = localL2Caching; this.currentTenantProvider = config.getCurrentTenantProvider(); + this.tenantPartitionedCache = config.isTenantPartitionedCache(); } public CacheManagerOptions with(ServerCacheOptions beanDefault, ServerCacheOptions queryDefault) { @@ -55,7 +58,7 @@ public CacheManagerOptions with(CurrentTenantProvider currentTenantProvider) { } public String getServerName() { - return (databaseConfig == null) ? "db" : databaseConfig.getName(); + return serverName; } public boolean isLocalL2Caching() { @@ -85,4 +88,6 @@ public ClusterManager getClusterManager() { public QueryCacheEntryValidate getQueryCacheEntryValidate() { return queryCacheEntryValidate; } + + public boolean isTenantPartitionedCache() { return tenantPartitionedCache; } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java index aba5ab3638..06d322ecd1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java @@ -32,6 +32,7 @@ final class DefaultCacheHolder { private final ServerCacheOptions queryDefault; private final CurrentTenantProvider tenantProvider; private final QueryCacheEntryValidate queryCacheEntryValidate; + private final boolean tenantPartitionedCache; DefaultCacheHolder(CacheManagerOptions builder) { this.cacheFactory = builder.getCacheFactory(); @@ -39,6 +40,7 @@ final class DefaultCacheHolder { this.queryDefault = builder.getQueryDefault(); this.tenantProvider = builder.getCurrentTenantProvider(); this.queryCacheEntryValidate = builder.getQueryCacheEntryValidate(); + this.tenantPartitionedCache = builder.isTenantPartitionedCache(); } void visitMetrics(MetricVisitor visitor) { @@ -56,16 +58,42 @@ ServerCache getCache(Class beanType, String collectionProperty) { return getCacheInternal(beanType, ServerCacheType.COLLECTION_IDS, collectionProperty); } + private String key(String beanName) { + if (tenantPartitionedCache) { + StringBuilder sb = new StringBuilder(beanName.length() + 64); + sb.append(beanName); + sb.append('.'); + sb.append(tenantProvider.currentId()); + return sb.toString(); + } else { + return beanName; + } + } + private String key(String beanName, ServerCacheType type) { - return beanName + type.code(); + StringBuilder sb = new StringBuilder(beanName.length() + 64); + sb.append(beanName); + if (tenantPartitionedCache) { + sb.append('.'); + sb.append(tenantProvider.currentId()); + } + sb.append(type.code()); + return sb.toString(); } private String key(String beanName, String collectionProperty, ServerCacheType type) { + StringBuilder sb = new StringBuilder(beanName.length() + 64); + sb.append(beanName); + if (tenantPartitionedCache) { + sb.append('.'); + sb.append(tenantProvider.currentId()); + } if (collectionProperty != null) { - return beanName + "." + collectionProperty + type.code(); - } else { - return beanName + type.code(); + sb.append('.'); + sb.append(collectionProperty); } + sb.append(type.code()); + return sb.toString(); } /** @@ -82,12 +110,17 @@ private ServerCache createCache(Class beanType, ServerCacheType type, String if (type == ServerCacheType.COLLECTION_IDS) { lock.lock(); try { - collectIdCaches.computeIfAbsent(beanType.getName(), s -> new ConcurrentSkipListSet<>()).add(key); + collectIdCaches.computeIfAbsent(key(beanType.getName()), s -> new ConcurrentSkipListSet<>()).add(key); } finally { lock.unlock(); } } - return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate)); + if (tenantPartitionedCache) { + return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, null, queryCacheEntryValidate)); + } else { + return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate)); + } + } void clearAll() { @@ -103,7 +136,7 @@ public void clear(String name) { clearIfExists(key(name, ServerCacheType.QUERY)); clearIfExists(key(name, ServerCacheType.BEAN)); clearIfExists(key(name, ServerCacheType.NATURAL_KEY)); - Set keys = collectIdCaches.get(name); + Set keys = collectIdCaches.get(key(name)); if (keys != null) { for (String collectionIdKey : keys) { clearIfExists(collectionIdKey); @@ -147,4 +180,7 @@ private ServerCacheOptions getBeanOptions(Class cls) { return beanDefault.copy(nearCache); } + boolean isTenantPartitionedCache() { + return tenantPartitionedCache; + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheManager.java index 0b7264ff90..39558d19d8 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultServerCacheManager.java @@ -154,4 +154,8 @@ public ServerCache getBeanCache(Class beanType) { return cacheHolder.getCache(beanType, ServerCacheType.BEAN); } + @Override + public boolean isTenantPartitionedCache() { + return cacheHolder.isTenantPartitionedCache(); + } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/SpiCacheManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/SpiCacheManager.java index bf6d4d5a21..ebeec00f68 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/SpiCacheManager.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/SpiCacheManager.java @@ -88,4 +88,10 @@ public interface SpiCacheManager { */ void clearLocal(Class beanType); + /** + * returns true, if this chacheManager runs in tenant partitioned mode + * @return + */ + boolean isTenantPartitionedCache(); + } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java index 73bb1c126c..d138861a9f 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptor.java @@ -319,7 +319,7 @@ public BeanDescriptor(BeanDescriptorMap owner, DeployBeanDescriptor deploy) { this.idOnlyReference = isIdOnlyReference(propertiesBaseScalar); boolean noRelationships = propertiesOne.length + propertiesMany.length == 0; this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly(); - this.cacheHelp = new BeanDescriptorCacheHelp<>(this, owner.cacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported); + this.cacheHelp = BeanDescriptorCacheHelpPartitioned.create(this, owner.cacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported); this.jsonHelp = initJsonHelp(); this.draftHelp = new BeanDescriptorDraftHelp<>(this); this.docStoreAdapter = owner.createDocStoreBeanAdapter(this, deploy); diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java index 79a20ce129..ae482166d1 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelp.java @@ -25,7 +25,7 @@ * * @param The entity bean type */ -final class BeanDescriptorCacheHelp { +abstract class BeanDescriptorCacheHelp { private static final System.Logger log = CoreLog.internal; @@ -34,7 +34,7 @@ final class BeanDescriptorCacheHelp { private static final System.Logger manyLog = AppLog.getLogger("io.ebean.cache.COLL"); private static final System.Logger natLog = AppLog.getLogger("io.ebean.cache.NATKEY"); - private final BeanDescriptor desc; + final BeanDescriptor desc; private final SpiCacheManager cacheManager; private final CacheOptions cacheOptions; /** @@ -42,13 +42,10 @@ final class BeanDescriptorCacheHelp { */ private final boolean cacheSharableBeans; private final boolean invalidateQueryCache; - private final Class beanType; + final Class beanType; private final String cacheName; private final BeanPropertyAssocOne[] propertiesOneImported; private final String[] naturalKey; - private final ServerCache beanCache; - private final ServerCache naturalKeyCache; - private final ServerCache queryCache; private final boolean noCaching; private final SpiCacheControl cacheControl; private final SpiCacheRegion cacheRegion; @@ -61,6 +58,15 @@ final class BeanDescriptorCacheHelp { */ private boolean cacheNotifyOnDelete; + static BeanDescriptorCacheHelp create(BeanDescriptor desc, SpiCacheManager cacheManager, CacheOptions cacheOptions, + boolean cacheSharableBeans, BeanPropertyAssocOne[] propertiesOneImported) { + if ((cacheOptions.isEnableQueryCache() || cacheOptions.isEnableBeanCache()) && cacheManager.isTenantPartitionedCache()) { + return new BeanDescriptorCacheHelpPartitioned<>(desc, cacheManager, cacheOptions, cacheSharableBeans, propertiesOneImported); + } else { + return new BeanDescriptorCacheHelpFixed<>(desc, cacheManager, cacheOptions, cacheSharableBeans, propertiesOneImported); + } + } + BeanDescriptorCacheHelp(BeanDescriptor desc, SpiCacheManager cacheManager, CacheOptions cacheOptions, boolean cacheSharableBeans, BeanPropertyAssocOne[] propertiesOneImported) { this.desc = desc; @@ -72,38 +78,38 @@ final class BeanDescriptorCacheHelp { this.cacheSharableBeans = cacheSharableBeans; this.propertiesOneImported = propertiesOneImported; this.naturalKey = cacheOptions.getNaturalKey(); - if (!cacheOptions.isEnableQueryCache()) { - this.queryCache = null; - } else { - this.queryCache = cacheManager.getQueryCache(beanType); - } - if (cacheOptions.isEnableBeanCache()) { - this.beanCache = cacheManager.getBeanCache(beanType); - if (cacheOptions.getNaturalKey() != null) { - this.naturalKeyCache = cacheManager.getNaturalKeyCache(beanType); - } else { - this.naturalKeyCache = null; - } - } else { - this.beanCache = null; - this.naturalKeyCache = null; - } - this.noCaching = (beanCache == null && queryCache == null); + this.noCaching = !cacheOptions.isEnableQueryCache() && !cacheOptions.isEnableBeanCache(); if (noCaching) { this.cacheControl = DCacheControlNone.INSTANCE; this.cacheRegion = (invalidateQueryCache) ? cacheManager.getRegion(cacheOptions.getRegion()) : DCacheRegionNone.INSTANCE; } else { this.cacheRegion = cacheManager.getRegion(cacheOptions.getRegion()); - this.cacheControl = new DCacheControl(cacheRegion, (beanCache != null), (naturalKeyCache != null), (queryCache != null)); + this.cacheControl = new DCacheControl(cacheRegion, + cacheOptions.isEnableBeanCache(), + cacheOptions.isEnableBeanCache() && cacheOptions.getNaturalKey() != null, + cacheOptions.isEnableQueryCache()); } } + abstract boolean hasBeanCache(); + + abstract boolean hasQueryCache(); + + abstract ServerCache getQueryCache(); + + abstract ServerCache getNaturalKeyCache(); + + abstract ServerCache getBeanCache(); + + /** * Derive the cache notify flags. */ void deriveNotifyFlags() { - cacheNotifyOnAll = (invalidateQueryCache || beanCache != null || queryCache != null); + cacheNotifyOnAll = (invalidateQueryCache + || hasBeanCache() + || hasQueryCache()); cacheNotifyOnDelete = !cacheNotifyOnAll && isNotifyOnDeletes(); if (log.isLoggable(DEBUG)) { if (cacheNotifyOnAll || cacheNotifyOnDelete) { @@ -178,11 +184,11 @@ CacheOptions getCacheOptions() { * Clear the query cache. */ void queryCacheClear() { - if (queryCache != null) { + if (hasQueryCache()) { if (queryLog.isLoggable(DEBUG)) { queryLog.log(DEBUG, " CLEAR {0}", cacheName); } - queryCache.clear(); + getQueryCache().clear(); } } @@ -190,7 +196,7 @@ void queryCacheClear() { * Add query cache clear to the changeSet. */ private void queryCacheClear(CacheChangeSet changeSet) { - if (queryCache != null) { + if (hasQueryCache()) { changeSet.addClearQuery(desc); } } @@ -199,10 +205,10 @@ private void queryCacheClear(CacheChangeSet changeSet) { * Get a query result from the query cache. */ Object queryCacheGet(Object id) { - if (queryCache == null) { + if (!hasQueryCache()) { throw new IllegalStateException("No query cache enabled on " + desc + ". Need explicit @Cache(enableQueryCache=true)"); } - Object queryResult = queryCache.get(id); + Object queryResult = getQueryCache().get(id); if (queryLog.isLoggable(DEBUG)) { if (queryResult == null) { queryLog.log(DEBUG, " GET {0}({1}) - cache miss", cacheName, id); @@ -217,13 +223,13 @@ Object queryCacheGet(Object id) { * Put a query result into the query cache. */ void queryCachePut(Object id, QueryCacheEntry entry) { - if (queryCache == null) { + if (!hasQueryCache()) { throw new IllegalStateException("No query cache enabled on " + desc + ". Need explicit @Cache(enableQueryCache=true)"); } if (queryLog.isLoggable(DEBUG)) { queryLog.log(DEBUG, " PUT {0}({1})", cacheName, id); } - queryCache.put(id, entry); + getQueryCache().put(id, entry); } void manyPropRemove(String propertyName, String parentKey) { @@ -294,7 +300,7 @@ boolean manyPropLoad(BeanPropertyAssocMany many, BeanCollection bc, String */ void manyPropPut(BeanPropertyAssocMany many, Object details, String parentKey) { if (many.isElementCollection()) { - CachedBeanData data = (CachedBeanData) beanCache.get(parentKey); + CachedBeanData data = (CachedBeanData) getBeanCache().get(parentKey); if (data != null) { try { // add as JSON to bean cache @@ -306,7 +312,7 @@ void manyPropPut(BeanPropertyAssocMany many, Object details, String parentKey if (beanLog.isLoggable(DEBUG)) { beanLog.log(DEBUG, " UPDATE {0}({1}) changes:{2}", cacheName, parentKey, changes); } - beanCache.put(parentKey, newData); + getBeanCache().put(parentKey, newData); } catch (IOException e) { log.log(ERROR, "Error updating L2 cache", e); } @@ -352,7 +358,7 @@ BeanCacheResult cacheIdLookup(PersistenceContext context, Collection ids) if (ids.isEmpty()) { return new BeanCacheResult<>(); } - Map beanDataMap = beanCache.getAll(keys); + Map beanDataMap = getBeanCache().getAll(keys); if (beanLog.isLoggable(TRACE)) { beanLog.log(TRACE, " MGET {0}({1}) - hits:{2}", cacheName, ids, beanDataMap.keySet()); } @@ -374,7 +380,7 @@ BeanCacheResult naturalKeyLookup(PersistenceContext context, Set keys } // naturalKey -> Id map - Map naturalKeyMap = naturalKeyCache.getAll(keys); + Map naturalKeyMap = getNaturalKeyCache().getAll(keys); if (natLog.isLoggable(TRACE)) { natLog.log(TRACE, " MLOOKUP {0}({1}) - hits:{2}", cacheName, keys, naturalKeyMap); } @@ -391,7 +397,7 @@ BeanCacheResult naturalKeyLookup(PersistenceContext context, Set keys } Set ids = new HashSet<>(naturalKeyMap.values()); - Map beanDataMap = beanCache.getAll(ids); + Map beanDataMap = getBeanCache().getAll(ids); if (beanLog.isLoggable(TRACE)) { beanLog.log(TRACE, " MGET {0}({1}) - hits:{2}", cacheName, ids, beanDataMap.keySet()); } @@ -422,25 +428,16 @@ private void setupContext(Object bean, PersistenceContext context) { desc.contextPut(context, id, bean); } - /** - * Return the beanCache creating it if necessary. - */ - private ServerCache getBeanCache() { - if (beanCache == null) { - throw new IllegalStateException("No bean cache enabled for " + desc + ". Add the @Cache annotation."); - } - return beanCache; - } /** * Clear the bean cache. */ void beanCacheClear() { - if (beanCache != null) { + if (hasBeanCache()) { if (beanLog.isLoggable(DEBUG)) { beanLog.log(DEBUG, " CLEAR {0}", cacheName); } - beanCache.clear(); + getBeanCache().clear(); } } @@ -516,7 +513,7 @@ void beanCachePutAllDirect(Collection beans) { if (natLog.isLoggable(DEBUG)) { natLog.log(DEBUG, " MPUT {0}({1}, {2})", cacheName, naturalKey, natKeys.keySet()); } - naturalKeyCache.putAll(natKeys); + getNaturalKeyCache().putAll(natKeys); } } @@ -536,7 +533,7 @@ void beanCachePutDirect(EntityBean bean) { if (natLog.isLoggable(DEBUG)) { natLog.log(DEBUG, " PUT {0}({1}, {2})", cacheName, naturalKey, key); } - naturalKeyCache.put(naturalKey, key); + getNaturalKeyCache().put(naturalKey, key); } } } @@ -679,11 +676,11 @@ EntityBean embeddedBeanLoadDirect(CachedBeanData data, PersistenceContext contex * Remove a bean from the cache given its Id. */ void beanCacheApplyInvalidate(Collection keys) { - if (beanCache != null) { + if (hasBeanCache()) { if (beanLog.isLoggable(DEBUG)) { beanLog.log(DEBUG, " MREMOVE {0}({1})", cacheName, keys); } - beanCache.removeAll(new HashSet<>(keys)); + getBeanCache().removeAll(new HashSet<>(keys)); } for (BeanPropertyAssocOne imported : propertiesOneImported) { imported.cacheClear(); @@ -767,7 +764,7 @@ void persistDeleteIds(Collection ids, CacheChangeSet changeSet) { changeSet.addInvalidate(desc); } else { queryCacheClear(changeSet); - if (beanCache != null) { + if (hasBeanCache()) { changeSet.addBeanRemoveMany(desc, ids); } cacheDeleteImported(true, null, changeSet); @@ -782,7 +779,7 @@ void persistDelete(Object id, PersistRequestBean deleteRequest, CacheChangeSe changeSet.addInvalidate(desc); } else { queryCacheClear(changeSet); - if (beanCache != null) { + if (hasBeanCache()) { changeSet.addBeanRemove(desc, id); } cacheDeleteImported(true, deleteRequest.entityBean(), changeSet); @@ -817,7 +814,7 @@ void persistUpdate(Object id, PersistRequestBean updateRequest, CacheChangeSe } else { queryCacheClear(changeSet); - if (beanCache == null) { + if (!hasBeanCache()) { // query caching only return; } @@ -860,7 +857,7 @@ void persistTableIUD(TableIUD tableIUD, CacheChangeSet changeSet) { void cacheNaturalKeyPut(String key, String newKey) { if (newKey != null) { - naturalKeyCache.put(newKey, key); + getNaturalKeyCache().put(newKey, key); } } @@ -893,7 +890,7 @@ void cacheBeanUpdate(String key, Map changes, boolean updateNatu if (natLog.isLoggable(DEBUG)) { natLog.log(DEBUG, ".. update {0} REMOVE({1}) - old key for ({2})", cacheName, oldKey, key); } - naturalKeyCache.remove(oldKey); + getNaturalKeyCache().remove(oldKey); } } } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpFixed.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpFixed.java new file mode 100644 index 0000000000..448f661cce --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpFixed.java @@ -0,0 +1,72 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.cache.ServerCache; +import io.ebeaninternal.server.cache.SpiCacheManager; +import io.ebeaninternal.server.core.CacheOptions; + + +/** + * Helper for BeanDescriptor that manages the bean, query and collection caches. + * + * @param The entity bean type + */ +final class BeanDescriptorCacheHelpFixed extends BeanDescriptorCacheHelp { + private final ServerCache beanCache; + private final ServerCache naturalKeyCache; + private final ServerCache queryCache; + + + BeanDescriptorCacheHelpFixed(BeanDescriptor desc, SpiCacheManager cacheManager, CacheOptions cacheOptions, + boolean cacheSharableBeans, BeanPropertyAssocOne[] propertiesOneImported) { + super(desc, cacheManager, cacheOptions, cacheSharableBeans, propertiesOneImported); + if (!cacheOptions.isEnableQueryCache()) { + this.queryCache = null; + } else { + this.queryCache = cacheManager.getQueryCache(beanType); + } + + if (cacheOptions.isEnableBeanCache()) { + this.beanCache = cacheManager.getBeanCache(beanType); + if (cacheOptions.getNaturalKey() != null) { + this.naturalKeyCache = cacheManager.getNaturalKeyCache(beanType); + } else { + this.naturalKeyCache = null; + } + } else { + this.beanCache = null; + this.naturalKeyCache = null; + } + } + + @Override + boolean hasBeanCache() { + return beanCache != null; + } + + @Override + boolean hasQueryCache() { + return queryCache != null; + } + + + @Override + ServerCache getQueryCache() { + return queryCache; + } + + @Override + ServerCache getNaturalKeyCache() { + return naturalKeyCache; + } + + /** + * Return the beanCache creating it if necessary. + */ + @Override + ServerCache getBeanCache() { + if (beanCache == null) { + throw new IllegalStateException("No bean cache enabled for " + desc + ". Add the @Cache annotation."); + } + return beanCache; + } +} diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpPartitioned.java b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpPartitioned.java new file mode 100644 index 0000000000..0e6ccd537f --- /dev/null +++ b/ebean-core/src/main/java/io/ebeaninternal/server/deploy/BeanDescriptorCacheHelpPartitioned.java @@ -0,0 +1,74 @@ +package io.ebeaninternal.server.deploy; + +import io.ebean.cache.ServerCache; +import io.ebeaninternal.server.cache.SpiCacheManager; +import io.ebeaninternal.server.core.CacheOptions; + +import java.util.function.Supplier; + +/** + * Helper for BeanDescriptor that manages the bean, query and collection caches. + * + * @param The entity bean type + */ +final class BeanDescriptorCacheHelpPartitioned extends BeanDescriptorCacheHelp { + private final Supplier beanCacheSupplier; + private final Supplier naturalKeyCacheSupplier; + private final Supplier queryCacheSupplier; + + + BeanDescriptorCacheHelpPartitioned(BeanDescriptor desc, SpiCacheManager cacheManager, CacheOptions cacheOptions, + boolean cacheSharableBeans, BeanPropertyAssocOne[] propertiesOneImported) { + super(desc, cacheManager, cacheOptions, cacheSharableBeans, propertiesOneImported); + if (!cacheOptions.isEnableQueryCache()) { + this.queryCacheSupplier = null; + } else { + this.queryCacheSupplier = () -> cacheManager.getQueryCache(beanType); + } + + if (cacheOptions.isEnableBeanCache()) { + this.beanCacheSupplier = () -> cacheManager.getBeanCache(beanType); + if (cacheOptions.getNaturalKey() != null) { + this.naturalKeyCacheSupplier = () -> cacheManager.getNaturalKeyCache(beanType); + } else { + this.naturalKeyCacheSupplier = null; + } + } else { + this.beanCacheSupplier = null; + this.naturalKeyCacheSupplier = null; + } + } + + @Override + boolean hasBeanCache() { + return beanCacheSupplier != null; + } + + @Override + boolean hasQueryCache() { + return queryCacheSupplier != null; + } + + + @Override + ServerCache getQueryCache() { + return queryCacheSupplier.get(); + } + + @Override + ServerCache getNaturalKeyCache() { + return naturalKeyCacheSupplier.get(); + } + + /** + * Return the beanCache creating it if necessary. + */ + @Override + ServerCache getBeanCache() { + if (beanCacheSupplier != null) { + return beanCacheSupplier.get(); + } else { + throw new IllegalStateException("No bean cache enabled for " + desc + ". Add the @Cache annotation."); + } + } +}