Embedded beans support in l2 cache - initial work

This commit is contained in:
Rob Bygrave
2014-04-30 01:49:20 +12:00
parent 68b4aab837
commit 289deb397a
11 changed files with 267 additions and 44 deletions
@@ -182,6 +182,13 @@ public final class EntityBeanIntercept implements Serializable {
public Object getEmbeddedOwner() {
return embeddedOwner;
}
/**
* Return the property index (for the parent) of this embedded bean.
*/
public int getEmbeddedOwnerIndex() {
return embeddedOwnerIndex;
}
/**
* Special case for a OneToOne, Set the parent bean (by relationship). This is
@@ -15,10 +15,20 @@ public class CachedBeanDataFromBean {
Object[] data = new Object[desc.getPropertyCount()];
boolean[] loaded = new boolean[desc.getPropertyCount()];
BeanProperty idProperty = desc.getIdProperty();
if (idProperty != null) {
int propertyIndex = idProperty.getPropertyIndex();
if (ebi.isLoadedProperty(propertyIndex)) {
// extract the id property value
data[propertyIndex] = idProperty.getCacheDataValue(bean);
loaded[propertyIndex] = true;
}
}
BeanProperty[] props = desc.propertiesNonMany();
Object naturalKey = null;
// extract all the non-many properties
for (int i = 0; i < props.length; i++) {
BeanProperty prop = props[i];
if (ebi.isLoadedProperty(prop.getPropertyIndex())) {
@@ -13,19 +13,17 @@ public class CachedBeanDataToBean {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
BeanProperty idProperty = desc.getIdProperty();
if (idProperty != null) {
// load the id property
loadProperty(bean, cacheBeanData, ebi, idProperty);
}
// load the non-many properties
BeanProperty[] props = desc.propertiesNonMany();
for (int i = 0; i < props.length; i++) {
BeanProperty prop = props[i];
int propertyIndex = prop.getPropertyIndex();
if (cacheBeanData.isLoaded(propertyIndex)) {
if (ebi.isLoadedProperty(propertyIndex)) {
// already loaded (lazy load on partially loaded bean)
} else {
Object data = cacheBeanData.getData(propertyIndex);
prop.setCacheDataValue(bean, data);
}
}
loadProperty(bean, cacheBeanData, ebi, props[i]);
}
BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
@@ -38,4 +36,17 @@ public class CachedBeanDataToBean {
return true;
}
private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop) {
int propertyIndex = prop.getPropertyIndex();
if (cacheBeanData.isLoaded(propertyIndex)) {
if (ebi.isLoadedProperty(propertyIndex)) {
// already loaded (lazy load on partially loaded bean)
} else {
Object data = cacheBeanData.getData(propertyIndex);
prop.setCacheDataValue(bean, data);
}
}
}
}
@@ -23,6 +23,7 @@ import com.avaje.ebeaninternal.api.SpiQuery;
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
/**
@@ -324,19 +325,27 @@ public class DefaultBeanLoader {
}
public void refresh(EntityBean bean) {
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN);
refreshBeanInternal(bean, SpiQuery.Mode.REFRESH_BEAN, -1);
}
public void loadBean(EntityBeanIntercept ebi) {
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN);
refreshBeanInternal(ebi.getOwner(), SpiQuery.Mode.LAZYLOAD_BEAN, -1);
}
private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode) {
private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode, int embeddedOwnerIndex) {
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();;
PersistenceContext pc = ebi.getPersistenceContext();
BeanDescriptor<?> desc = server.getBeanDescriptor(bean.getClass());
if (EntityType.EMBEDDED == desc.getEntityType()) {
// lazy loading on an embedded bean property
EntityBean embeddedOwner = (EntityBean)ebi.getEmbeddedOwner();
int ownerIndex = ebi.getEmbeddedOwnerIndex();
refreshBeanInternal(embeddedOwner, mode, ownerIndex);
}
Object id = desc.getId(bean);
if (pc == null) {
@@ -348,7 +357,7 @@ public class DefaultBeanLoader {
}
}
if (ebi != null) {
if (embeddedOwnerIndex == -1) {
if (SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
// lazy loading and the bean cache is active
if (desc.cacheBeanLoad((EntityBean)bean, ebi, id)) {
@@ -365,6 +374,11 @@ public class DefaultBeanLoader {
query.setLazyLoadProperty(ebi.getLazyLoadProperty());
}
if (embeddedOwnerIndex > -1) {
String embeddedBeanPropertyName = ebi.getProperty(embeddedOwnerIndex);
query.select("id,"+embeddedBeanPropertyName);
}
// don't collect autoFetch usage profiling information
// as we just copy the data out of these fetched beans
// and put the data into the original bean
@@ -373,12 +387,13 @@ public class DefaultBeanLoader {
query.setMode(mode);
query.setId(id);
// make sure the query doesn't use the cache
if (mode.equals(SpiQuery.Mode.REFRESH_BEAN)) {
if (embeddedOwnerIndex > -1 || mode.equals(SpiQuery.Mode.REFRESH_BEAN)) {
// make sure the query doesn't use the cache
query.setUseCache(false);
}
if (ebi != null && ebi.isReadOnly()) {
if (ebi.isReadOnly()) {
query.setReadOnly(true);
}
@@ -842,6 +842,20 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
cacheBeanPutData((EntityBean)bean);
}
/**
* Extract the raw cache data from the bean.
*/
public CachedBeanData cacheBeanExtractData(EntityBean bean) {
return cacheHelp.beanExtractData(bean);
}
/**
* Load the raw cache data into the bean.
*/
public void cacheBeanLoadData(EntityBean bean, CachedBeanData data) {
cacheHelp.beanLoadData(bean, data);
}
/**
* Put a bean into the bean cache.
*/
@@ -360,12 +360,20 @@ public final class BeanDescriptorCacheHelp<T> {
}
}
public CachedBeanData beanExtractData(EntityBean bean) {
return CachedBeanDataFromBean.extract(desc, bean);
}
public void beanLoadData(EntityBean bean, CachedBeanData data) {
CachedBeanDataToBean.load(desc, bean, data);
}
/**
* Put a bean into the bean cache.
*/
public void beanCachePut(EntityBean bean) {
CachedBeanData beanData = CachedBeanDataFromBean.extract(desc, bean);
CachedBeanData beanData = beanExtractData(bean);
Object id = desc.getId(bean);
if (beanLog.isDebugEnabled()) {
@@ -402,15 +410,15 @@ public final class BeanDescriptorCacheHelp<T> {
@SuppressWarnings("unchecked")
private T beanCacheGetInternal(Object id, Boolean readOnly) {
CachedBeanData d = (CachedBeanData) getBeanCache().get(id);
if (d == null) {
CachedBeanData data = (CachedBeanData) getBeanCache().get(id);
if (data == null) {
if (beanLog.isTraceEnabled()) {
beanLog.trace(" GET {}({}) - cache miss", cacheName, id);
}
return null;
}
if (cacheSharableBeans && !Boolean.FALSE.equals(readOnly)) {
Object bean = d.getSharableBean();
Object bean = data.getSharableBean();
if (bean != null) {
if (beanLog.isTraceEnabled()) {
beanLog.trace(" GET {}({}) - hit shared bean", cacheName, id);
@@ -425,7 +433,7 @@ public final class BeanDescriptorCacheHelp<T> {
bean._ebean_getIntercept().setReadOnly(true);
}
CachedBeanDataToBean.load(desc, bean, d);
beanLoadData(bean, data);
if (beanLog.isTraceEnabled()) {
beanLog.trace(" GET {}({}) - hit", cacheName, id);
}
@@ -14,6 +14,7 @@ import com.avaje.ebean.Transaction;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebean.bean.EntityBeanIntercept;
import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
@@ -323,15 +324,15 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
}
public Object getCacheDataValue(EntityBean bean){
if (embedded) {
throw new RuntimeException();
Object ap = getValue(bean);
if (ap == null){
return null;
}
if (embedded) {
return targetDescriptor.cacheBeanExtractData((EntityBean) ap);
} else {
Object ap = getValue(bean);
if (ap == null){
return null;
} else {
return targetDescriptor.getId((EntityBean)ap);
}
return targetDescriptor.getId((EntityBean)ap);
}
}
@@ -339,7 +340,10 @@ public class BeanPropertyAssocOne<T> extends BeanPropertyAssoc<T> {
public void setCacheDataValue(EntityBean bean, Object cacheData){
if (cacheData != null) {
if (embedded){
throw new RuntimeException();
EntityBean embeddedBean = targetDescriptor.createEntityBean();
targetDescriptor.cacheBeanLoadData(embeddedBean, (CachedBeanData) cacheData);
setValue(bean, embeddedBean);
} else {
T ref = targetDescriptor.createReference(Boolean.FALSE, cacheData);
setValue(bean, ref);