mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
WIP update/refactoring on caching
This commit is contained in:
@@ -94,7 +94,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
}
|
||||
|
||||
private void initWithoutTouchedFlag() {
|
||||
private void initAsUntouched() {
|
||||
init(false);
|
||||
}
|
||||
|
||||
@@ -102,12 +102,12 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
init(true);
|
||||
}
|
||||
|
||||
private void init(boolean setFlag) {
|
||||
private void init(boolean setTouched) {
|
||||
synchronized (this) {
|
||||
if (set == null) {
|
||||
lazyLoadCollection(true);
|
||||
}
|
||||
touched(setFlag);
|
||||
touched(setTouched);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +232,7 @@ public final class BeanSet<E> extends AbstractBeanCollection<E> implements Set<E
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
initWithoutTouchedFlag();
|
||||
initAsUntouched();
|
||||
return set.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,61 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
/**
|
||||
* Data held in the bean cache for cached beans.
|
||||
*/
|
||||
public class CachedBeanData {
|
||||
|
||||
private final Object sharableBean;
|
||||
private final boolean[] loaded;
|
||||
private final Object[] data;
|
||||
private final int naturalKeyUpdate;
|
||||
|
||||
private final boolean naturalKeyUpdate;
|
||||
private final Object naturalKey;
|
||||
private final Object oldNaturalKey;
|
||||
|
||||
public CachedBeanData(Object sharableBean, boolean[] loaded, Object[] data, int naturalKeyUpdate) {
|
||||
public CachedBeanData(Object sharableBean, boolean[] loaded, Object[] data, Object naturalKey, Object oldNaturalKey) {
|
||||
this.sharableBean = sharableBean;
|
||||
this.loaded = loaded;
|
||||
this.data = data;
|
||||
this.naturalKeyUpdate = naturalKeyUpdate;
|
||||
this.naturalKeyUpdate = naturalKey != null;
|
||||
this.naturalKey = (naturalKey != null) ? naturalKey : oldNaturalKey;
|
||||
this.oldNaturalKey = oldNaturalKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the property data.
|
||||
*/
|
||||
public Object[] copyData() {
|
||||
Object[] dest = new Object[data.length];
|
||||
System.arraycopy(data, 0, dest, 0, data.length);
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the loaded status for the properties.
|
||||
*/
|
||||
public boolean[] copyLoaded() {
|
||||
boolean[] dest = new boolean[data.length];
|
||||
for (int i = 0; i < dest.length; i++) {
|
||||
dest[i] = loaded[i];
|
||||
}
|
||||
return dest;
|
||||
}
|
||||
|
||||
public Object getSharableBean() {
|
||||
return sharableBean;
|
||||
}
|
||||
|
||||
public boolean isNaturalKeyUpdate() {
|
||||
return naturalKeyUpdate > -1;
|
||||
return naturalKeyUpdate;
|
||||
}
|
||||
|
||||
public Object getNaturalKey() {
|
||||
return data[naturalKeyUpdate];
|
||||
return naturalKey;
|
||||
}
|
||||
|
||||
public Object getOldNaturalKey() {
|
||||
return oldNaturalKey;
|
||||
}
|
||||
|
||||
public boolean containsProperty(int propIndex) {
|
||||
@@ -38,12 +70,6 @@ public class CachedBeanData {
|
||||
return data[i];
|
||||
}
|
||||
|
||||
public Object[] copyData() {
|
||||
Object[] dest = new Object[data.length];
|
||||
System.arraycopy(data, 0, dest, 0, data.length);
|
||||
return dest;
|
||||
}
|
||||
|
||||
public boolean isLoaded(int i) {
|
||||
return loaded[i];
|
||||
}
|
||||
|
||||
+15
-27
@@ -7,50 +7,41 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
public class CachedBeanDataFromBean {
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
private final EntityBean bean;
|
||||
private final EntityBeanIntercept ebi;
|
||||
|
||||
public static CachedBeanData extract(BeanDescriptor<?> desc, EntityBean bean) {
|
||||
return new CachedBeanDataFromBean(desc, bean, bean._ebean_getIntercept()).extract();
|
||||
}
|
||||
|
||||
private CachedBeanDataFromBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept ebi) {
|
||||
this.desc = desc;
|
||||
this.bean = bean;
|
||||
this.ebi = ebi;
|
||||
}
|
||||
|
||||
private CachedBeanData extract() {
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
|
||||
Object[] data = new Object[desc.getPropertyCount()];
|
||||
boolean[] loaded = new boolean[desc.getPropertyCount()];
|
||||
|
||||
BeanProperty[] props = desc.propertiesNonMany();
|
||||
|
||||
int naturalKeyUpdate = -1;
|
||||
Object naturalKey = null;
|
||||
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
BeanProperty prop = props[i];
|
||||
if (isLoaded(prop)) {
|
||||
if (ebi.isLoadedProperty(prop.getPropertyIndex())) {
|
||||
int propertyIndex = prop.getPropertyIndex();
|
||||
data[propertyIndex] = prop.getCacheDataValue(bean);
|
||||
loaded[propertyIndex] = true;
|
||||
if (prop.isNaturalKey()) {
|
||||
naturalKeyUpdate = propertyIndex;
|
||||
naturalKey = prop.getValue(bean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityBean sharableBean = createSharableBean();
|
||||
EntityBean sharableBean = createSharableBean(desc, bean, ebi);
|
||||
|
||||
return new CachedBeanData(sharableBean, loaded, data, naturalKeyUpdate);
|
||||
return new CachedBeanData(sharableBean, loaded, data, naturalKey, null);
|
||||
}
|
||||
|
||||
private EntityBean createSharableBean() {
|
||||
if (!desc.isCacheSharableBeans() || !ebi.isFullyLoadedBean()) {
|
||||
private static EntityBean createSharableBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept beanEbi) {
|
||||
|
||||
if (!desc.isCacheSharableBeans() || !beanEbi.isFullyLoadedBean()) {
|
||||
return null;
|
||||
}
|
||||
if (ebi.isReadOnly()) {
|
||||
if (beanEbi.isReadOnly()) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@@ -66,14 +57,11 @@ public class CachedBeanDataFromBean {
|
||||
Object v = propertiesNonTransient[i].getValue(bean);
|
||||
propertiesNonTransient[i].setValue(sharableBean, v);
|
||||
}
|
||||
EntityBeanIntercept ebi = ((EntityBean) sharableBean)._ebean_intercept();
|
||||
ebi.setReadOnly(true);
|
||||
ebi.setLoaded();
|
||||
EntityBeanIntercept intercept = sharableBean._ebean_intercept();
|
||||
intercept.setReadOnly(true);
|
||||
intercept.setLoaded();
|
||||
return sharableBean;
|
||||
}
|
||||
|
||||
private boolean isLoaded(BeanProperty prop) {
|
||||
return ebi.isLoadedProperty(prop.getPropertyIndex());
|
||||
}
|
||||
|
||||
}
|
||||
+3
-18
@@ -8,25 +8,10 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
|
||||
public class CachedBeanDataToBean {
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
private final EntityBean bean;
|
||||
private final EntityBeanIntercept ebi;
|
||||
private final CachedBeanData cacheBeanData;
|
||||
//private final boolean readOnly;
|
||||
|
||||
public static boolean load(BeanDescriptor<?> desc, EntityBean bean, CachedBeanData cacheBeandata) {
|
||||
return new CachedBeanDataToBean(desc, bean, ((EntityBean) bean)._ebean_getIntercept(), cacheBeandata).load();
|
||||
}
|
||||
|
||||
private CachedBeanDataToBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept ebi, CachedBeanData cacheBeandata) {
|
||||
this.desc = desc;
|
||||
this.bean = bean;
|
||||
this.ebi = ebi;
|
||||
this.cacheBeanData = cacheBeandata;
|
||||
//this.readOnly = ebi.isReadOnly();
|
||||
}
|
||||
|
||||
private boolean load() {
|
||||
public static boolean load(BeanDescriptor<?> desc, EntityBean bean, CachedBeanData cacheBeanData) {
|
||||
|
||||
EntityBeanIntercept ebi = bean._ebean_getIntercept();
|
||||
|
||||
BeanProperty[] props = desc.propertiesNonMany();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
|
||||
+33
-39
@@ -1,50 +1,44 @@
|
||||
package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
|
||||
/**
|
||||
* Create a new CachedBeanData based on the existing CachedBeanData and the updated bean.
|
||||
*/
|
||||
public class CachedBeanDataUpdate {
|
||||
|
||||
public static CachedBeanData update(BeanDescriptor<?> desc, CachedBeanData data, PersistRequestBean<?> updateRequest){
|
||||
/**
|
||||
* Create a new CachedBeanData based on the existing CachedBeanData and the updated bean.
|
||||
*/
|
||||
public static CachedBeanData update(BeanDescriptor<?> desc, CachedBeanData existingData, EntityBean updateBean) {
|
||||
|
||||
//
|
||||
// Set<String> loadedProperties = data.getLoadedProperties();
|
||||
// Object[] copyOfData = data.copyData();
|
||||
//
|
||||
// Object updateBean = updateRequest.getBean();
|
||||
// Set<String> updatedProperties = updateRequest.getUpdatedProperties();
|
||||
//
|
||||
// int naturalKeyUpdate = -1;
|
||||
// boolean mergeProperties = false;
|
||||
// BeanProperty[] props = desc.propertiesNonMany();
|
||||
// for (int i = 0; i < props.length; i++) {
|
||||
// if (updatedProperties.contains(props[i].getName())){
|
||||
// if (props[i].isNaturalKey()){
|
||||
// naturalKeyUpdate = i;
|
||||
// }
|
||||
// copyOfData[i] = props[i].getCacheDataValue(updateBean);
|
||||
// if (loadedProperties != null && !mergeProperties && !loadedProperties.contains(props[i].getName())){
|
||||
// mergeProperties = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (mergeProperties){
|
||||
// HashSet<String> mergeProps = new HashSet<String>();
|
||||
// mergeProps.addAll(loadedProperties);
|
||||
// mergeProps.addAll(updatedProperties);
|
||||
// loadedProperties = mergeProps;
|
||||
// }
|
||||
//
|
||||
// return new CachedBeanData(null, loadedProperties, copyOfData, naturalKeyUpdate);
|
||||
|
||||
return null;
|
||||
// take a copy of the raw data and loaded status
|
||||
boolean[] copyLoaded = existingData.copyLoaded();
|
||||
Object[] copyData = existingData.copyData();
|
||||
|
||||
EntityBeanIntercept ebi = updateBean._ebean_getIntercept();
|
||||
|
||||
Object newNaturalKey = null;
|
||||
Object oldNaturalKey = existingData.getNaturalKey();
|
||||
|
||||
BeanProperty[] props = desc.propertiesNonMany();
|
||||
for (int i = 0; i < props.length; i++) {
|
||||
// check if the properties was in the update
|
||||
int propertyIndex = props[i].getPropertyIndex();
|
||||
if (ebi.isLoadedProperty(propertyIndex)) {
|
||||
if (props[i].isNaturalKey()) {
|
||||
newNaturalKey = updateBean._ebean_getField(i);
|
||||
}
|
||||
// set the cache safe value for the property and mark it as loaded
|
||||
copyData[propertyIndex] = props[i].getCacheDataValue(updateBean);
|
||||
copyLoaded[propertyIndex] = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return new CachedBeanData(null, copyLoaded, copyData, newNaturalKey, oldNaturalKey);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,16 +2,22 @@ package com.avaje.ebeaninternal.server.cache;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The cached data for O2M and M2M relationships.
|
||||
* <p>
|
||||
* This is effectively just the Id values for each of the beans in the collection.
|
||||
* </p>
|
||||
*/
|
||||
public class CachedManyIds {
|
||||
|
||||
private final List<Object> idList;
|
||||
|
||||
public CachedManyIds(List<Object> idList) {
|
||||
this.idList = idList;
|
||||
}
|
||||
private final List<Object> idList;
|
||||
|
||||
public List<Object> getIdList() {
|
||||
return idList;
|
||||
}
|
||||
public CachedManyIds(List<Object> idList) {
|
||||
this.idList = idList;
|
||||
}
|
||||
|
||||
public List<Object> getIdList() {
|
||||
return idList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ public class DefaultBeanLoader {
|
||||
}
|
||||
} else if (loadRequest.isLoadCache()) {
|
||||
Object parentId = desc.getId(bc.getOwnerBean());
|
||||
desc.cachePutMany(many, bc, parentId);
|
||||
desc.cacheManyPropPut(many, bc, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,13 +179,13 @@ public class DefaultBeanLoader {
|
||||
pc.put(parentId, parentBean);
|
||||
}
|
||||
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.cacheIsUseManyId();
|
||||
boolean useManyIdCache = beanCollection != null && parentDesc.isManyPropCaching();
|
||||
if (useManyIdCache) {
|
||||
Boolean readOnly = null;
|
||||
if (ebi != null && ebi.isReadOnly()) {
|
||||
readOnly = Boolean.TRUE;
|
||||
}
|
||||
if (parentDesc.cacheLoadMany(many, beanCollection, parentId, readOnly)) {
|
||||
if (parentDesc.cacheManyPropLoad(many, beanCollection, parentId, readOnly)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public class DefaultBeanLoader {
|
||||
logger.debug("BeanCollection after load was empty. Owner:" + beanCollection.getOwnerBean());
|
||||
}
|
||||
} else if (useManyIdCache) {
|
||||
parentDesc.cachePutMany(many, beanCollection, parentId);
|
||||
parentDesc.cacheManyPropPut(many, beanCollection, parentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,7 +312,7 @@ public class DefaultBeanLoader {
|
||||
|
||||
if (loadRequest.isLoadCache()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
desc.cachePutBeanData((EntityBean)list.get(i));
|
||||
desc.cacheBeanPutData((EntityBean)list.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ public class DefaultBeanLoader {
|
||||
if (ebi != null) {
|
||||
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
|
||||
// lazy loading and the bean cache is active
|
||||
if (desc.loadFromCache((EntityBean)bean, ebi, id)) {
|
||||
if (desc.cacheBeanLoad((EntityBean)bean, ebi, id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1180,7 +1180,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
}
|
||||
|
||||
// Hit the L2 bean cache
|
||||
Object cachedBean = beanDescriptor.cacheGetBean(query.getId(), query.isReadOnly());
|
||||
Object cachedBean = beanDescriptor.cacheBeanGet(query.getId(), query.isReadOnly());
|
||||
if (cachedBean != null) {
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
@@ -1249,7 +1249,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
// check if it is a find by unique id
|
||||
NaturalKeyBindParam keyBindParam = q.getNaturalKeyBindParam();
|
||||
if (keyBindParam != null && desc.cacheIsNaturalKey(keyBindParam.getName())) {
|
||||
Object id2 = desc.cacheGetNaturalKeyId(keyBindParam.getValue());
|
||||
Object id2 = desc.cacheNaturalKeyLookup(keyBindParam.getValue());
|
||||
if (id2 != null) {
|
||||
SpiQuery<T> copy = q.copy();
|
||||
copy.convertWhereNaturalKeyToId(id2);
|
||||
|
||||
@@ -151,10 +151,10 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
if (notifyCache) {
|
||||
switch (type) {
|
||||
case INSERT:
|
||||
beanDescriptor.cacheInsert(idValue, this);
|
||||
beanDescriptor.cacheHandleInsert(idValue, this);
|
||||
break;
|
||||
case UPDATE:
|
||||
beanDescriptor.cacheUpdate(idValue, this);
|
||||
beanDescriptor.cacheHandleUpdate(idValue, this);
|
||||
break;
|
||||
case DELETE:
|
||||
// Bean deleted from cache early via postDelete()
|
||||
@@ -436,7 +436,7 @@ public class PersistRequestBean<T> extends PersistRequest implements BeanPersist
|
||||
// Delete the bean from the PersistenceContent
|
||||
transaction.getPersistenceContext().clear(beanDescriptor.getBeanType(), idValue);
|
||||
// Delete from cache early even if transaction fails
|
||||
beanDescriptor.cacheDelete(idValue, this);
|
||||
beanDescriptor.cacheHandleDelete(idValue, this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.avaje.ebeaninternal.server.deploy;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@@ -16,7 +15,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.Query;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.SqlUpdate;
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.annotation.ConcurrencyMode;
|
||||
@@ -24,8 +25,6 @@ import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.dbplatform.IdGenerator;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
@@ -43,9 +42,6 @@ import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiUpdatePlan;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataFromBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataToBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataUpdate;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedManyIds;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
|
||||
@@ -76,9 +72,6 @@ import com.avaje.ebeaninternal.util.SortByClause;
|
||||
import com.avaje.ebeaninternal.util.SortByClause.Property;
|
||||
import com.avaje.ebeaninternal.util.SortByClauseParser;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Describes Beans including their deployment information.
|
||||
*/
|
||||
@@ -130,11 +123,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
private final boolean autoFetchTunable;
|
||||
|
||||
/**
|
||||
* Flag indicating this bean has no relationships.
|
||||
*/
|
||||
private final boolean cacheSharableBeans;
|
||||
|
||||
private final String lazyFetchIncludes;
|
||||
|
||||
/**
|
||||
@@ -227,8 +215,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
private final BeanProperty versionProperty;
|
||||
private final int versionPropertyIndex;
|
||||
|
||||
private final BeanProperty propertiesNaturalKey;
|
||||
|
||||
/**
|
||||
* Properties local to this type (not from a super type).
|
||||
*/
|
||||
@@ -330,29 +316,23 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
*/
|
||||
private final boolean updateChangesOnly;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final CacheOptions cacheOptions;
|
||||
private final boolean cacheSharableBeans;
|
||||
|
||||
private final BeanDescriptorCacheHelp<T> cacheHelp;
|
||||
|
||||
private final String defaultSelectClause;
|
||||
private final Set<String> defaultSelectClauseSet;
|
||||
|
||||
private final String descriptorId;
|
||||
|
||||
|
||||
private SpiEbeanServer ebeanServer;
|
||||
|
||||
private ServerCache beanCache;
|
||||
private ServerCache naturalKeyCache;
|
||||
private ServerCache queryCache;
|
||||
|
||||
/**
|
||||
* Construct the BeanDescriptor.
|
||||
*/
|
||||
public BeanDescriptor(BeanDescriptorMap owner, TypeManager typeManager, DeployBeanDescriptor<T> deploy, String descriptorId) {
|
||||
|
||||
this.owner = owner;
|
||||
this.cacheManager = owner.getCacheManager();
|
||||
this.serverName = owner.getServerName();
|
||||
this.entityType = deploy.getEntityType();
|
||||
this.properties = deploy.getProperties();
|
||||
@@ -373,7 +353,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.persistController = deploy.getPersistController();
|
||||
this.persistListener = deploy.getPersistListener();
|
||||
this.queryAdapter = deploy.getQueryAdapter();
|
||||
this.cacheOptions = deploy.getCacheOptions();
|
||||
|
||||
this.defaultSelectClause = deploy.getDefaultSelectClause();
|
||||
this.defaultSelectClauseSet = deploy.parseDefaultSelectClause(defaultSelectClause);
|
||||
@@ -408,7 +387,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.propertiesNonTransient = listHelper.getNonTransients();
|
||||
this.propertiesBaseScalar = listHelper.getBaseScalar();
|
||||
this.propertiesBaseCompound = listHelper.getBaseCompound();
|
||||
this.propertiesNaturalKey = listHelper.getNaturalKey();
|
||||
this.propertiesEmbedded = listHelper.getEmbedded();
|
||||
this.propertiesLocal = listHelper.getLocal();
|
||||
this.unidirectional = listHelper.getUnidirectional();
|
||||
@@ -425,14 +403,18 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
this.propertiesManySave = listHelper.getManySave();
|
||||
this.propertiesManyDelete = listHelper.getManyDelete();
|
||||
this.propertiesManyToMany = listHelper.getManyToMany();
|
||||
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
|
||||
this.cacheSharableBeans = noRelationships && cacheOptions.isReadOnly();
|
||||
|
||||
this.namesOfManyProps = deriveManyPropNames();
|
||||
this.namesOfManyPropsHash = namesOfManyProps.hashCode();
|
||||
|
||||
this.derivedTableJoins = listHelper.getTableJoin();
|
||||
|
||||
boolean noRelationships = propertiesOne.length + propertiesMany.length == 0;
|
||||
|
||||
this.cacheSharableBeans = noRelationships && deploy.getCacheOptions().isReadOnly();
|
||||
this.cacheHelp = new BeanDescriptorCacheHelp<T>(this, owner.getCacheManager(), deploy.getCacheOptions(), cacheSharableBeans, propertiesOneImported);
|
||||
|
||||
|
||||
// Check if there are no cascade save associated beans ( subject to change
|
||||
// in initialiseOther()). Note that if we are in an inheritance hierarchy
|
||||
// then we also need to check every BeanDescriptors in the InheritInfo as
|
||||
@@ -615,7 +597,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
namedUpdate.initialise(parser);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void initInheritInfo() {
|
||||
@@ -634,12 +615,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Initialise the cache once the server has started.
|
||||
*/
|
||||
public void cacheInitialise() {
|
||||
if (cacheOptions.isUseNaturalKeyCache()) {
|
||||
this.naturalKeyCache = cacheManager.getNaturalKeyCache(beanType);
|
||||
}
|
||||
if (cacheOptions.isUseCache()) {
|
||||
this.beanCache = cacheManager.getBeanCache(beanType);
|
||||
}
|
||||
cacheHelp.initialise();
|
||||
}
|
||||
|
||||
protected boolean hasInheritance() {
|
||||
@@ -713,7 +689,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Return the cache options.
|
||||
*/
|
||||
public CacheOptions getCacheOptions() {
|
||||
return cacheOptions;
|
||||
return cacheHelp.getCacheOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -734,21 +710,7 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Execute the warming cache query (if defined) and load the cache.
|
||||
*/
|
||||
public void runCacheWarming() {
|
||||
if (cacheOptions == null) {
|
||||
return;
|
||||
}
|
||||
String warmingQuery = cacheOptions.getWarmingQuery();
|
||||
if (warmingQuery != null && warmingQuery.trim().length() > 0) {
|
||||
Query<T> query = ebeanServer.createQuery(beanType, warmingQuery);
|
||||
query.setUseCache(true);
|
||||
query.setReadOnly(true);
|
||||
query.setLoadBeanCache(true);
|
||||
List<T> list = query.findList();
|
||||
if (logger.isInfoEnabled()) {
|
||||
String msg = "Loaded " + beanType + " cache with [" + list.size() + "] beans";
|
||||
logger.info(msg);
|
||||
}
|
||||
}
|
||||
cacheHelp.runCacheWarming(ebeanServer);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -785,17 +747,17 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
public boolean isQueryCaching() {
|
||||
return queryCache != null;
|
||||
return cacheHelp.isQueryCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently bean caching for this type of bean.
|
||||
*/
|
||||
public boolean isBeanCaching() {
|
||||
return beanCache != null;
|
||||
return cacheHelp.isBeanCaching();
|
||||
}
|
||||
|
||||
public boolean cacheIsUseManyId() {
|
||||
public boolean isManyPropCaching() {
|
||||
return isBeanCaching();
|
||||
}
|
||||
|
||||
@@ -803,271 +765,145 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Return true if the persist request needs to notify the cache.
|
||||
*/
|
||||
public boolean isCacheNotify() {
|
||||
|
||||
if (isBeanCaching() || isQueryCaching()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
if (propertiesOneImported[i].getTargetDescriptor().isBeanCaching()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is L2 bean caching for this bean type.
|
||||
*/
|
||||
public boolean isUsingL2Cache() {
|
||||
return isBeanCaching();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate parts of cache due to SqlUpdate or external modification etc.
|
||||
*/
|
||||
public void cacheNotify(TableIUD tableIUD) {
|
||||
// inserts don't invalidate the bean cache
|
||||
if (tableIUD.isUpdateOrDelete()) {
|
||||
cacheClear();
|
||||
}
|
||||
// any change invalidates the query cache
|
||||
queryCacheClear();
|
||||
return cacheHelp.isCacheNotify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the query cache.
|
||||
*/
|
||||
public void queryCacheClear() {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
cacheHelp.queryCacheClear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a query result from the query cache.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollection<T> queryCacheGet(Object id) {
|
||||
if (queryCache == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (BeanCollection<T>) queryCache.get(id);
|
||||
}
|
||||
return cacheHelp.queryCacheGet(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a query result into the query cache.
|
||||
*/
|
||||
public void queryCachePut(Object id, BeanCollection<T> query) {
|
||||
if (queryCache == null) {
|
||||
queryCache = cacheManager.getQueryCache(beanType);
|
||||
}
|
||||
queryCache.put(id, query);
|
||||
cacheHelp.queryCachePut(id, query);
|
||||
}
|
||||
|
||||
private ServerCache getBeanCache() {
|
||||
if (beanCache == null) {
|
||||
beanCache = cacheManager.getBeanCache(beanType);
|
||||
}
|
||||
return beanCache;
|
||||
|
||||
|
||||
/**
|
||||
* Try to load the beanCollection from cache return true if successful.
|
||||
*/
|
||||
public boolean cacheManyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
|
||||
return cacheHelp.manyPropLoad(many, bc, parentId, readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the beanCollection into the cache.
|
||||
*/
|
||||
public void cacheManyPropPut(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId) {
|
||||
cacheHelp.manyPropPut(many, bc, parentId);
|
||||
}
|
||||
|
||||
public void cacheManyPropRemove(Object parentId, String propertyName) {
|
||||
cacheHelp.manyPropRemove(parentId, propertyName);
|
||||
}
|
||||
|
||||
public void cacheManyPropClear(String propertyName) {
|
||||
cacheHelp.manyPropClear(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CachedManyIds for a given bean and property. Returns null if not in the cache.
|
||||
*/
|
||||
public CachedManyIds cacheManyPropGet(Object parentId, String propertyName) {
|
||||
return cacheHelp.manyPropGet(parentId, propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the CachedManyIds into the cache.
|
||||
*/
|
||||
public void cacheManyPropPutEntry(Object parentId, String propertyName, CachedManyIds ids) {
|
||||
cacheHelp.manyPropPutEntry(parentId, propertyName, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the bean cache.
|
||||
*/
|
||||
public void cacheClear() {
|
||||
if (beanCache != null) {
|
||||
beanCache.clear();
|
||||
}
|
||||
public void cacheBeanClear() {
|
||||
cacheHelp.beanCacheClear();
|
||||
}
|
||||
|
||||
public void cachePutBean(T bean) {
|
||||
cachePutBeanData((EntityBean)bean);
|
||||
public void cacheBeanPut(T bean) {
|
||||
cacheBeanPutData((EntityBean)bean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a bean into the bean cache.
|
||||
*/
|
||||
public void cachePutBeanData(EntityBean bean) {
|
||||
|
||||
CachedBeanData beanData = CachedBeanDataFromBean.extract(this, bean);
|
||||
|
||||
Object id = getId(bean);
|
||||
getBeanCache().put(id, beanData);
|
||||
if (beanData.isNaturalKeyUpdate() && naturalKeyCache != null) {
|
||||
Object naturalKey = beanData.getNaturalKey();
|
||||
if (naturalKey != null) {
|
||||
naturalKeyCache.put(naturalKey, id);
|
||||
}
|
||||
}
|
||||
public void cacheBeanPutData(EntityBean bean) {
|
||||
cacheHelp.beanCachePut(bean);
|
||||
}
|
||||
|
||||
public boolean cacheLoadMany(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
|
||||
|
||||
CachedManyIds ids = cacheGetCachedManyIds(parentId, many.getName());
|
||||
if (ids == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
EntityBeanIntercept ebi = ((EntityBean) ownerBean)._ebean_getIntercept();
|
||||
PersistenceContext persistenceContext = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
|
||||
|
||||
List<Object> idList = ids.getIdList();
|
||||
bc.checkEmptyLazyLoad();
|
||||
for (int i = 0; i < idList.size(); i++) {
|
||||
Object id = idList.get(i);
|
||||
Object refBean = targetDescriptor.createReference(readOnly, id);
|
||||
EntityBeanIntercept refEbi = ((EntityBean) refBean)._ebean_getIntercept();
|
||||
|
||||
many.add(bc, (EntityBean)refBean);
|
||||
persistenceContext.put(id, refBean);
|
||||
refEbi.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void cachePutMany(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId) {
|
||||
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
|
||||
ArrayList<Object> idList = new ArrayList<Object>();
|
||||
|
||||
// get the underlying collection of beans (in the List, Set or Map)
|
||||
Collection<?> actualDetails = bc.getActualDetails();
|
||||
for (Object bean : actualDetails) {
|
||||
// Collect the id values
|
||||
idList.add(targetDescriptor.getId((EntityBean)bean));
|
||||
}
|
||||
CachedManyIds ids = new CachedManyIds(idList);
|
||||
cachePutCachedManyIds(parentId, many.getName(), ids);
|
||||
}
|
||||
|
||||
public void cacheRemoveCachedManyIds(Object parentId, String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.remove(parentId);
|
||||
}
|
||||
|
||||
public void cacheClearCachedManyIds(String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.clear();
|
||||
}
|
||||
|
||||
public CachedManyIds cacheGetCachedManyIds(Object parentId, String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
return (CachedManyIds) collectionIdsCache.get(parentId);
|
||||
}
|
||||
|
||||
public void cachePutCachedManyIds(Object parentId, String propertyName, CachedManyIds ids) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.put(parentId, ids);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a bean from the bean cache.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T cacheGetBean(Object id, Boolean readOnly) {
|
||||
|
||||
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
Object bean = d.getSharableBean();
|
||||
if (bean != null) {
|
||||
return (T) bean;
|
||||
}
|
||||
}
|
||||
|
||||
EntityBean bean = createBean();
|
||||
convertSetId(id, bean);
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
bean._ebean_getIntercept().setReadOnly(true);
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(this, bean, d);
|
||||
return (T)bean;
|
||||
public T cacheBeanGet(Object id, Boolean readOnly) {
|
||||
return cacheHelp.beanCacheGet(id, readOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bean from the cache given its Id.
|
||||
*/
|
||||
public void cacheBeanRemove(Object id) {
|
||||
cacheHelp.beanCacheRemove(id);
|
||||
}
|
||||
|
||||
public boolean cacheBeanLoad(EntityBean bean, EntityBeanIntercept ebi, Object id) {
|
||||
return cacheHelp.beanCacheLoad(bean, ebi, id);
|
||||
}
|
||||
|
||||
public boolean cacheBeanLoad(EntityBeanIntercept ebi) {
|
||||
EntityBean bean = ebi.getOwner();
|
||||
Object id = getId(bean);
|
||||
|
||||
return cacheBeanLoad(bean, ebi, id);
|
||||
}
|
||||
|
||||
|
||||
public boolean cacheIsNaturalKey(String propName) {
|
||||
return propName != null && propName.equals(cacheOptions.getNaturalKey());
|
||||
return cacheHelp.isNaturalKey(propName);
|
||||
}
|
||||
|
||||
public Object cacheGetNaturalKeyId(Object uniqueKeyValue) {
|
||||
if (naturalKeyCache != null) {
|
||||
return naturalKeyCache.get(uniqueKeyValue);
|
||||
}
|
||||
return null;
|
||||
public Object cacheNaturalKeyLookup(Object uniqueKeyValue) {
|
||||
return cacheHelp.naturalKeyLookup(uniqueKeyValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate parts of cache due to SqlUpdate or external modification etc.
|
||||
*/
|
||||
public void cacheHandleBulkUpdate(TableIUD tableIUD) {
|
||||
cacheHelp.handleBulkUpdate(tableIUD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bean from the cache given its Id.
|
||||
*/
|
||||
public void cacheRemove(Object id) {
|
||||
if (beanCache != null) {
|
||||
beanCache.remove(id);
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
propertiesOneImported[i].cacheClear();
|
||||
}
|
||||
public void cacheHandleDelete(Object id, PersistRequestBean<T> deleteRequest) {
|
||||
cacheHelp.handleDelete(id, deleteRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bean from the cache given its Id.
|
||||
*/
|
||||
public void cacheDelete(Object id, PersistRequestBean<T> deleteRequest) {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
if (beanCache != null) {
|
||||
beanCache.remove(id);
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
BeanPropertyAssocMany<?> many = propertiesOneImported[i].getRelationshipProperty();
|
||||
if (many != null) {
|
||||
propertiesOneImported[i].cacheDelete(true, deleteRequest.getEntityBean());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void cacheInsert(Object id, PersistRequestBean<T> insertRequest) {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
propertiesOneImported[i].cacheDelete(false, insertRequest.getEntityBean());
|
||||
}
|
||||
public void cacheHandleInsert(Object id, PersistRequestBean<T> insertRequest) {
|
||||
cacheHelp.handleInsert(id, insertRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the cached bean data.
|
||||
*/
|
||||
public void cacheUpdate(Object id, PersistRequestBean<T> updateRequest) {
|
||||
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
|
||||
ServerCache cache = getBeanCache();
|
||||
CachedBeanData cd = (CachedBeanData) cache.get(id);
|
||||
if (cd != null) {
|
||||
CachedBeanData newCd = CachedBeanDataUpdate.update(this, cd, updateRequest);
|
||||
cache.put(id, newCd);
|
||||
if (newCd.isNaturalKeyUpdate() && naturalKeyCache != null) {
|
||||
//FIXME: natural key invalidate old value
|
||||
//Object oldKey = propertiesNaturalKey.getValue(updateRequest.getOldValues());
|
||||
Object newKey = propertiesNaturalKey.getValue(updateRequest.getEntityBean());
|
||||
//if (oldKey != null) {
|
||||
// naturalKeyCache.remove(oldKey);
|
||||
//}
|
||||
if (newKey != null) {
|
||||
naturalKeyCache.put(newKey, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void cacheHandleUpdate(Object id, PersistRequestBean<T> updateRequest) {
|
||||
cacheHelp.handleUpdate(id, updateRequest);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the base table alias. This is always the first letter of the bean
|
||||
* name.
|
||||
@@ -1076,28 +912,6 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
return baseTableAlias;
|
||||
}
|
||||
|
||||
public boolean loadFromCache(EntityBeanIntercept ebi) {
|
||||
EntityBean bean = ebi.getOwner();
|
||||
Object id = getId(bean);
|
||||
|
||||
return loadFromCache(bean, ebi, id);
|
||||
}
|
||||
|
||||
public boolean loadFromCache(EntityBean bean, EntityBeanIntercept ebi, Object id) {
|
||||
|
||||
CachedBeanData cacheData = (CachedBeanData) getBeanCache().get(id);
|
||||
if (cacheData == null) {
|
||||
return false;
|
||||
}
|
||||
int lazyLoadProperty = ebi.getLazyLoadPropertyIndex();
|
||||
if (lazyLoadProperty > -1 && !cacheData.containsProperty(lazyLoadProperty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(this, bean, cacheData);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void preAllocateIds(int batchSize) {
|
||||
if (idGenerator != null) {
|
||||
idGenerator.preAllocateIds(batchSize);
|
||||
@@ -1327,10 +1141,10 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
* Create a reference bean based on the id.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T createReference(Boolean readOnly, Object id) {//, Object parent) {
|
||||
public T createReference(Boolean readOnly, Object id) {
|
||||
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
|
||||
CachedBeanData d = (CachedBeanData) cacheHelp.beanCacheGetData(id);
|
||||
if (d != null) {
|
||||
Object shareableBean = d.getSharableBean();
|
||||
if (shareableBean != null) {
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.Query;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.cache.ServerCache;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataFromBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataToBean;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedBeanDataUpdate;
|
||||
import com.avaje.ebeaninternal.server.cache.CachedManyIds;
|
||||
import com.avaje.ebeaninternal.server.core.CacheOptions;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
|
||||
/**
|
||||
* Helper for BeanDescriptor that manages the bean, query and collection caches.
|
||||
*
|
||||
* @param <T> The entity bean type
|
||||
*/
|
||||
public final class BeanDescriptorCacheHelp<T> {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(BeanDescriptorCacheHelp.class);
|
||||
|
||||
private final BeanDescriptor<T> desc;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final CacheOptions cacheOptions;
|
||||
|
||||
/**
|
||||
* Flag indicating this bean has no relationships.
|
||||
*/
|
||||
private final boolean cacheSharableBeans;
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
private final BeanPropertyAssocOne<?>[] propertiesOneImported;
|
||||
|
||||
private ServerCache beanCache;
|
||||
private ServerCache naturalKeyCache;
|
||||
private ServerCache queryCache;
|
||||
|
||||
public BeanDescriptorCacheHelp(BeanDescriptor<T> desc, ServerCacheManager cacheManager, CacheOptions cacheOptions,
|
||||
boolean cacheSharableBeans, BeanPropertyAssocOne<?>[] propertiesOneImported) {
|
||||
|
||||
this.desc = desc;
|
||||
this.beanType = desc.getBeanType();
|
||||
this.cacheManager = cacheManager;
|
||||
this.cacheOptions = cacheOptions;
|
||||
this.cacheSharableBeans = cacheSharableBeans;
|
||||
this.propertiesOneImported = propertiesOneImported;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the cache once the server has started.
|
||||
*/
|
||||
public void initialise() {
|
||||
if (cacheOptions.isUseNaturalKeyCache()) {
|
||||
this.naturalKeyCache = cacheManager.getNaturalKeyCache(beanType);
|
||||
}
|
||||
if (cacheOptions.isUseCache()) {
|
||||
this.beanCache = cacheManager.getBeanCache(beanType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the warming cache query (if defined) and load the cache.
|
||||
*/
|
||||
public void runCacheWarming(EbeanServer ebeanServer) {
|
||||
if (cacheOptions == null) {
|
||||
return;
|
||||
}
|
||||
String warmingQuery = cacheOptions.getWarmingQuery();
|
||||
if (warmingQuery != null && warmingQuery.trim().length() > 0) {
|
||||
Query<?> query = ebeanServer.createQuery(beanType, warmingQuery);
|
||||
query.setUseCache(true);
|
||||
query.setReadOnly(true);
|
||||
query.setLoadBeanCache(true);
|
||||
List<?> list = query.findList();
|
||||
if (logger.isInfoEnabled()) {
|
||||
String msg = "Loaded " + beanType + " cache with [" + list.size() + "] beans";
|
||||
logger.info(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently query caching for this type of bean.
|
||||
*/
|
||||
public boolean isQueryCaching() {
|
||||
return queryCache != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is currently bean caching for this type of bean.
|
||||
*/
|
||||
public boolean isBeanCaching() {
|
||||
return beanCache != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the persist request needs to notify the cache.
|
||||
*/
|
||||
public boolean isCacheNotify() {
|
||||
|
||||
if (isBeanCaching() || isQueryCaching()) {
|
||||
return true;
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
if (propertiesOneImported[i].getTargetDescriptor().isBeanCaching()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public CacheOptions getCacheOptions() {
|
||||
return cacheOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the query cache.
|
||||
*/
|
||||
public void queryCacheClear() {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a query result from the query cache.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public BeanCollection<T> queryCacheGet(Object id) {
|
||||
if (queryCache == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (BeanCollection<T>) queryCache.get(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a query result into the query cache.
|
||||
*/
|
||||
public void queryCachePut(Object id, BeanCollection<T> query) {
|
||||
if (queryCache == null) {
|
||||
queryCache = cacheManager.getQueryCache(beanType);
|
||||
}
|
||||
queryCache.put(id, query);
|
||||
}
|
||||
|
||||
|
||||
public void manyPropRemove(Object parentId, String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.remove(parentId);
|
||||
}
|
||||
|
||||
public void manyPropClear(String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CachedManyIds for a given bean many property. Returns null if not in the cache.
|
||||
*/
|
||||
public CachedManyIds manyPropGet(Object parentId, String propertyName) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
return (CachedManyIds) collectionIdsCache.get(parentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the CachedManyIds into the cache.
|
||||
*/
|
||||
public void manyPropPutEntry(Object parentId, String propertyName, CachedManyIds ids) {
|
||||
ServerCache collectionIdsCache = cacheManager.getCollectionIdsCache(beanType, propertyName);
|
||||
collectionIdsCache.put(parentId, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to load the bean collection from cache return true if successful.
|
||||
*/
|
||||
public boolean manyPropLoad(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId, Boolean readOnly) {
|
||||
|
||||
CachedManyIds ids = manyPropGet(parentId, many.getName());
|
||||
if (ids == null) {
|
||||
// not in cache so return unsuccessful
|
||||
return false;
|
||||
}
|
||||
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
EntityBeanIntercept ebi = ((EntityBean) ownerBean)._ebean_getIntercept();
|
||||
PersistenceContext persistenceContext = ebi.getPersistenceContext();
|
||||
|
||||
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
|
||||
|
||||
List<Object> idList = ids.getIdList();
|
||||
bc.checkEmptyLazyLoad();
|
||||
for (int i = 0; i < idList.size(); i++) {
|
||||
Object id = idList.get(i);
|
||||
Object refBean = targetDescriptor.createReference(readOnly, id);
|
||||
EntityBeanIntercept refEbi = ((EntityBean) refBean)._ebean_getIntercept();
|
||||
|
||||
many.add(bc, (EntityBean) refBean);
|
||||
persistenceContext.put(id, refBean);
|
||||
refEbi.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the beanCollection into the cache.
|
||||
*/
|
||||
public void manyPropPut(BeanPropertyAssocMany<?> many, BeanCollection<?> bc, Object parentId) {
|
||||
|
||||
BeanDescriptor<?> targetDescriptor = many.getTargetDescriptor();
|
||||
ArrayList<Object> idList = new ArrayList<Object>();
|
||||
|
||||
// get the underlying collection of beans (in the List, Set or Map)
|
||||
Collection<?> actualDetails = bc.getActualDetails();
|
||||
for (Object bean : actualDetails) {
|
||||
// Collect the id values
|
||||
idList.add(targetDescriptor.getId((EntityBean) bean));
|
||||
}
|
||||
CachedManyIds ids = new CachedManyIds(idList);
|
||||
manyPropPutEntry(parentId, many.getName(), ids);
|
||||
}
|
||||
|
||||
|
||||
public boolean isNaturalKey(String propName) {
|
||||
return propName != null && propName.equals(cacheOptions.getNaturalKey());
|
||||
}
|
||||
|
||||
public Object naturalKeyLookup(Object uniqueKeyValue) {
|
||||
if (naturalKeyCache != null) {
|
||||
return naturalKeyCache.get(uniqueKeyValue);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ServerCache getBeanCache() {
|
||||
if (beanCache == null) {
|
||||
beanCache = cacheManager.getBeanCache(beanType);
|
||||
}
|
||||
return beanCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the bean cache.
|
||||
*/
|
||||
public void beanCacheClear() {
|
||||
if (beanCache != null) {
|
||||
beanCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a bean into the bean cache.
|
||||
*/
|
||||
public void beanCachePut(EntityBean bean) {
|
||||
|
||||
CachedBeanData beanData = CachedBeanDataFromBean.extract(desc, bean);
|
||||
|
||||
Object id = desc.getId(bean);
|
||||
getBeanCache().put(id, beanData);
|
||||
if (beanData.isNaturalKeyUpdate() && naturalKeyCache != null) {
|
||||
Object naturalKey = beanData.getNaturalKey();
|
||||
if (naturalKey != null) {
|
||||
naturalKeyCache.put(naturalKey, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CachedBeanData beanCacheGetData(Object id) {
|
||||
return (CachedBeanData) getBeanCache().get(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bean from the bean cache.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T beanCacheGet(Object id, Boolean readOnly) {
|
||||
|
||||
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
|
||||
if (d == null) {
|
||||
return null;
|
||||
}
|
||||
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
|
||||
Object bean = d.getSharableBean();
|
||||
if (bean != null) {
|
||||
return (T) bean;
|
||||
}
|
||||
}
|
||||
|
||||
EntityBean bean = desc.createBean();
|
||||
desc.convertSetId(id, bean);
|
||||
if (Boolean.TRUE.equals(readOnly)) {
|
||||
bean._ebean_getIntercept().setReadOnly(true);
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(desc, bean, d);
|
||||
return (T) bean;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a bean from the cache given its Id.
|
||||
*/
|
||||
public void beanCacheRemove(Object id) {
|
||||
if (beanCache != null) {
|
||||
beanCache.remove(id);
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
propertiesOneImported[i].cacheClear();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean beanCacheLoad(EntityBean bean, EntityBeanIntercept ebi, Object id) {
|
||||
|
||||
CachedBeanData cacheData = (CachedBeanData) getBeanCache().get(id);
|
||||
if (cacheData == null) {
|
||||
return false;
|
||||
}
|
||||
int lazyLoadProperty = ebi.getLazyLoadPropertyIndex();
|
||||
if (lazyLoadProperty > -1 && !cacheData.containsProperty(lazyLoadProperty)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CachedBeanDataToBean.load(desc, bean, cacheData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a bean from the cache given its Id.
|
||||
*/
|
||||
public void handleDelete(Object id, PersistRequestBean<T> deleteRequest) {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
if (beanCache != null) {
|
||||
beanCache.remove(id);
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
BeanPropertyAssocMany<?> many = propertiesOneImported[i].getRelationshipProperty();
|
||||
if (many != null) {
|
||||
propertiesOneImported[i].cacheDelete(true, deleteRequest.getEntityBean());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleInsert(Object id, PersistRequestBean<T> insertRequest) {
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
for (int i = 0; i < propertiesOneImported.length; i++) {
|
||||
propertiesOneImported[i].cacheDelete(false, insertRequest.getEntityBean());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the cached bean data.
|
||||
*/
|
||||
public void handleUpdate(Object id, PersistRequestBean<T> updateRequest) {
|
||||
|
||||
if (queryCache != null) {
|
||||
queryCache.clear();
|
||||
}
|
||||
|
||||
ServerCache cache = getBeanCache();
|
||||
CachedBeanData existingData = (CachedBeanData) cache.get(id);
|
||||
if (existingData != null) {
|
||||
CachedBeanData newData = CachedBeanDataUpdate.update(desc, existingData, updateRequest.getEntityBean());
|
||||
cache.put(id, newData);
|
||||
if (newData.isNaturalKeyUpdate() && naturalKeyCache != null) {
|
||||
|
||||
Object oldKey = newData.getOldNaturalKey();
|
||||
Object newKey = newData.getNaturalKey();
|
||||
if (oldKey != null) {
|
||||
naturalKeyCache.remove(oldKey);
|
||||
}
|
||||
if (newKey != null) {
|
||||
naturalKeyCache.put(newKey, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate parts of cache due to SqlUpdate or external modification etc.
|
||||
*/
|
||||
public void handleBulkUpdate(TableIUD tableIUD) {
|
||||
// inserts don't invalidate the bean cache
|
||||
if (tableIUD.isUpdateOrDelete()) {
|
||||
beanCacheClear();
|
||||
}
|
||||
// any change invalidates the query cache
|
||||
queryCacheClear();
|
||||
}
|
||||
}
|
||||
@@ -281,7 +281,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
List<BeanDescriptor<?>> list = getBeanDescriptors(tableIUD.getTableName());
|
||||
if (list != null) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
list.get(i).cacheNotify(tableIUD);
|
||||
list.get(i).cacheHandleBulkUpdate(tableIUD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
|
||||
public void cacheClear() {
|
||||
if (targetDescriptor.isBeanCaching() && relationshipProperty != null) {
|
||||
targetDescriptor.cacheClearCachedManyIds(relationshipProperty.getName());
|
||||
targetDescriptor.cacheManyPropClear(relationshipProperty.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,12 +128,12 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
|
||||
if (assocBean != null) {
|
||||
Object parentId = targetDescriptor.getId((EntityBean)assocBean);
|
||||
if (parentId != null) {
|
||||
targetDescriptor.cacheRemoveCachedManyIds(parentId, relationshipProperty.getName());
|
||||
targetDescriptor.cacheManyPropRemove(parentId, relationshipProperty.getName());
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (clearOnNull) {
|
||||
targetDescriptor.cacheClearCachedManyIds(relationshipProperty.getName());
|
||||
targetDescriptor.cacheManyPropClear(relationshipProperty.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-8
@@ -36,6 +36,7 @@ public class DeployBeanPropertyLists {
|
||||
private final ArrayList<BeanProperty> local = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> manys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> nonManys = new ArrayList<BeanProperty>();
|
||||
|
||||
private final ArrayList<BeanProperty> ones = new ArrayList<BeanProperty>();
|
||||
@@ -177,14 +178,6 @@ public class DeployBeanPropertyLists {
|
||||
return (BeanPropertyCompound[]) baseCompound.toArray(new BeanPropertyCompound[baseCompound.size()]);
|
||||
}
|
||||
|
||||
public BeanProperty getNaturalKey() {
|
||||
String naturalKey = desc.getCacheOptions().getNaturalKey();
|
||||
if (naturalKey != null) {
|
||||
return propertyMap.get(naturalKey);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public BeanProperty getId() {
|
||||
if (ids.size() > 1) {
|
||||
String msg = "Ebean does not support multiple @Id properties. You need to convert to using an @EmbeddedId."
|
||||
|
||||
@@ -156,7 +156,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.hitCache && context.desc.loadFromCache(ebi)) {
|
||||
if (context.hitCache && context.desc.cacheBeanLoad(ebi)) {
|
||||
// successfully hit the L2 cache so don't invoke DB lazy loading
|
||||
list.remove(ebi);
|
||||
return;
|
||||
@@ -167,7 +167,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
Iterator<EntityBeanIntercept> iterator = list.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
EntityBeanIntercept bean = iterator.next();
|
||||
if (context.desc.loadFromCache(bean)) {
|
||||
if (context.desc.cacheBeanLoad(bean)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
EntityBean ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<? extends Object> parentDesc = context.desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheLoadMany(context.property, bc, parentId, context.parent.isReadOnly())) {
|
||||
if (parentDesc.cacheManyPropLoad(context.property, bc, parentId, context.parent.isReadOnly())) {
|
||||
// we loaded the bean from cache
|
||||
list.remove(bc);
|
||||
return;
|
||||
|
||||
@@ -412,7 +412,7 @@ public final class DefaultPersister implements Persister {
|
||||
BeanPropertyAssocOne<?>[] expOnes = descriptor.propertiesOneExportedDelete();
|
||||
for (int i = 0; i < expOnes.length; i++) {
|
||||
BeanDescriptor<?> targetDesc = expOnes[i].getTargetDescriptor();
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isUsingL2Cache()) {
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isBeanCaching()) {
|
||||
SqlUpdate sqlDelete = expOnes[i].deleteByParentId(id, idList);
|
||||
executeSqlUpdate(sqlDelete, t);
|
||||
} else {
|
||||
@@ -425,7 +425,7 @@ public final class DefaultPersister implements Persister {
|
||||
BeanPropertyAssocMany<?>[] manys = descriptor.propertiesManyDelete();
|
||||
for (int i = 0; i < manys.length; i++) {
|
||||
BeanDescriptor<?> targetDesc = manys[i].getTargetDescriptor();
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isUsingL2Cache()) {
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isBeanCaching()) {
|
||||
// we can just delete children with a single statement
|
||||
SqlUpdate sqlDelete = manys[i].deleteByParentId(id, idList);
|
||||
executeSqlUpdate(sqlDelete, t);
|
||||
@@ -1053,7 +1053,7 @@ public final class DefaultPersister implements Persister {
|
||||
if (many.getCascadeInfo().isDelete()) {
|
||||
// cascade delete the beans in the collection
|
||||
BeanDescriptor<?> targetDesc = many.getTargetDescriptor();
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isUsingL2Cache()) {
|
||||
if (targetDesc.isDeleteRecurseSkippable() && !targetDesc.isBeanCaching()) {
|
||||
// Just delete all the children with one statement
|
||||
IntersectionRow intRow = many.buildManyDeleteChildren(parentBean, excludeDetailIds);
|
||||
SqlUpdate sqlDelete = intRow.createDelete(server);
|
||||
|
||||
@@ -83,7 +83,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
BeanDescriptor<T> descriptor = request.getBeanDescriptor();
|
||||
Collection<T> c = result.getActualDetails();
|
||||
for (T bean : c) {
|
||||
descriptor.cachePutBeanData((EntityBean)bean);
|
||||
descriptor.cacheBeanPutData((EntityBean)bean);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
}
|
||||
|
||||
if (result != null && request.isUseBeanCache()){
|
||||
request.getBeanDescriptor().cachePutBeanData((EntityBean)result);
|
||||
request.getBeanDescriptor().cacheBeanPutData((EntityBean)result);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -264,7 +264,7 @@ public class BeanPersistIds implements Serializable {
|
||||
Serializable id = updateIds.get(i);
|
||||
|
||||
// remove from cache
|
||||
beanDescriptor.cacheRemove(id);
|
||||
beanDescriptor.cacheBeanRemove(id);
|
||||
if (listener != null) {
|
||||
// notify listener
|
||||
listener.remoteInsert(id);
|
||||
@@ -276,7 +276,7 @@ public class BeanPersistIds implements Serializable {
|
||||
Serializable id = deleteIds.get(i);
|
||||
|
||||
// remove from cache
|
||||
beanDescriptor.cacheRemove(id);
|
||||
beanDescriptor.cacheBeanRemove(id);
|
||||
if (listener != null) {
|
||||
// notify listener
|
||||
listener.remoteInsert(id);
|
||||
|
||||
@@ -27,7 +27,7 @@ public final class DeleteByIdMap {
|
||||
if (idValues != null){
|
||||
d.queryCacheClear();
|
||||
for (int i = 0; i < idValues.size(); i++) {
|
||||
d.cacheRemove(idValues.get(i));
|
||||
d.cacheBeanRemove(idValues.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user