mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Refactor internals of batch lazy loading and query fetches
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.loadcontext;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
@@ -8,55 +9,45 @@ import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyContext;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyBuffer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties;
|
||||
|
||||
public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
protected final String fullPath;
|
||||
|
||||
private final BeanDescriptor<?> desc;
|
||||
public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
|
||||
private final BeanPropertyAssocMany<?> property;
|
||||
|
||||
private final String path;
|
||||
protected final BeanPropertyAssocMany<?> property;
|
||||
|
||||
private List<LoadBuffer> bufferList;
|
||||
|
||||
private LoadBuffer currentBuffer;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> property,
|
||||
String path, int defaultBatchSize, OrmQueryProperties queryProps) {
|
||||
|
||||
private final int batchSize;
|
||||
|
||||
private final OrmQueryProperties queryProps;
|
||||
|
||||
private final DLoadList<BeanCollection<?>> weakList;
|
||||
|
||||
public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany<?> p,
|
||||
String path, int batchSize, OrmQueryProperties queryProps, DLoadList<BeanCollection<?>> weakList) {
|
||||
|
||||
this.parent = parent;
|
||||
this.property = p;
|
||||
this.desc = p.getBeanDescriptor();
|
||||
this.path = path;
|
||||
this.batchSize = batchSize;
|
||||
this.queryProps = queryProps;
|
||||
this.weakList = weakList;//new DLoadWeakList<BeanCollection<?>>();
|
||||
|
||||
if (parent.getRelativePath() == null){
|
||||
this.fullPath = path;
|
||||
} else {
|
||||
this.fullPath = parent.getRelativePath()+"."+path;
|
||||
}
|
||||
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
|
||||
|
||||
this.property = property;
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
this.bufferList = queryFetch ? new ArrayList<DLoadManyContext.LoadBuffer>() : null;
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
|
||||
// propagate the readOnly state
|
||||
if (parent.isReadOnly() != null){
|
||||
query.setReadOnly(parent.isReadOnly());
|
||||
}
|
||||
if (parent.isReadOnly() != null){
|
||||
query.setReadOnly(parent.isReadOnly());
|
||||
}
|
||||
query.setParentNode(getObjectGraphNode());
|
||||
|
||||
if (queryProps != null){
|
||||
@@ -82,18 +73,6 @@ public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public String getFullPath() {
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return parent.getPersistenceContext();
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return batchSize;
|
||||
}
|
||||
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return property;
|
||||
}
|
||||
@@ -102,60 +81,130 @@ public class DLoadManyContext implements LoadManyContext, BeanCollectionLoader {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return parent.getEbeanServer().getName();
|
||||
}
|
||||
|
||||
public void register(BeanCollection<?> bc){
|
||||
int pos = weakList.add(bc);
|
||||
bc.setLoader(pos, this);
|
||||
|
||||
bc.setLoader(0, currentBuffer);
|
||||
if (currentBuffer.add(bc)) {
|
||||
// the currentBuffer is full so create another one
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
int position = bc.getLoaderIndex();
|
||||
|
||||
LoadManyRequest req;
|
||||
synchronized (weakList) {
|
||||
boolean hitCache = desc.isBeanCaching() && !onlyIds && !parent.isExcludeBeanCache();
|
||||
if (hitCache){
|
||||
Object ownerBean = bc.getOwnerBean();
|
||||
BeanDescriptor<? extends Object> parentDesc = desc.getBeanDescriptor(ownerBean.getClass());
|
||||
Object parentId = parentDesc.getId(ownerBean);
|
||||
if (parentDesc.cacheLoadMany(property, bc, parentId, parent.isReadOnly())) {
|
||||
// we loaded the bean from cache
|
||||
weakList.removeEntry(position);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<BeanCollection<?>> loadBatch = weakList.getLoadBatch(position, batchSize);
|
||||
req = new LoadManyRequest(this, loadBatch, null, batchSize, true, onlyIds, hitCache);
|
||||
}
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
}
|
||||
|
||||
public void loadSecondaryQuery(OrmQueryRequest<?> parentRequest, int requestedBatchSize, boolean all){
|
||||
|
||||
do {
|
||||
LoadManyRequest req;
|
||||
synchronized (weakList) {
|
||||
List<BeanCollection<?>> batch = weakList.getNextBatch(requestedBatchSize);
|
||||
if (batch.size() == 0){
|
||||
return;
|
||||
}
|
||||
req = new LoadManyRequest(this, batch, parentRequest.getTransaction(), requestedBatchSize, false, false, false);
|
||||
}
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!all){
|
||||
// queryFirst(batch)
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
if (!queryFetch) {
|
||||
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
|
||||
}
|
||||
synchronized (this) {
|
||||
if (bufferList != null) {
|
||||
for (LoadBuffer loadBuffer : bufferList) {
|
||||
if (!loadBuffer.list.isEmpty()) {
|
||||
LoadManyRequest req = new LoadManyRequest(loadBuffer, parentRequest.getTransaction(), requestedBatchSize, false, false, false);
|
||||
parent.getEbeanServer().loadMany(req);
|
||||
if (!queryProps.isQueryFetchAll()) {
|
||||
// Stop - only fetch the first batch ... the rest will be lazy loaded
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is only run once - secondary query is a one shot deal
|
||||
this.bufferList = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A buffer for batch loading bean collections on a given path.
|
||||
* Supports batch lazy loading and secondary query loading.
|
||||
*/
|
||||
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
private final List<BeanCollection<?>> list;
|
||||
|
||||
public LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
this.context = context;
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<BeanCollection<?>>(batchSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean add(BeanCollection<?> bc) {
|
||||
list.add(bc);
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BeanCollection<?>> getBatch() {
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanPropertyAssocMany<?> getBeanProperty() {
|
||||
return context.property;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectGraphNode getObjectGraphNode() {
|
||||
return context.getObjectGraphNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureQuery(SpiQuery<?> query){
|
||||
context.configureQuery(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return context.serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BeanDescriptor<?> getBeanDescriptor() {
|
||||
return context.desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return context.getPersistenceContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullPath() {
|
||||
return context.fullPath;
|
||||
}
|
||||
|
||||
public void loadMany(BeanCollection<?> bc, boolean onlyIds) {
|
||||
|
||||
synchronized (this) {
|
||||
boolean useCache = context.hitCache && !onlyIds;
|
||||
if (useCache) {
|
||||
Object 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())) {
|
||||
// we loaded the bean from cache
|
||||
list.remove(bc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Should reduce the list by checking each beanCollection in the L2 first before executing the query
|
||||
|
||||
LoadManyRequest req = new LoadManyRequest(this, null, batchSize, true, onlyIds, useCache);
|
||||
context.parent.getEbeanServer().loadMany(req);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user