mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Fix for #131 - Memory issue (Hard refs) when using findIterate
This commit is contained in:
@@ -29,6 +29,7 @@ import com.avaje.ebeaninternal.server.deploy.DeployPropertyParserMap;
|
||||
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryPlan;
|
||||
import com.avaje.ebeaninternal.server.query.CancelableQuery;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
/**
|
||||
* Wraps the objects involved in executing a Query.
|
||||
@@ -43,12 +44,12 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
|
||||
private final BeanFinder<T> finder;
|
||||
|
||||
private final LoadContext graphContext;
|
||||
|
||||
private final Boolean readOnly;
|
||||
|
||||
private final RawSql rawSql;
|
||||
|
||||
private LoadContext loadContext;
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private HashQuery cacheKey;
|
||||
@@ -68,13 +69,10 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
this.queryEngine = queryEngine;
|
||||
this.query = query;
|
||||
this.readOnly = query.isReadOnly();
|
||||
|
||||
this.graphContext = new DLoadContext(ebeanServer, beanDescriptor, readOnly, query);
|
||||
graphContext.registerSecondaryQueries(query);
|
||||
}
|
||||
|
||||
public void executeSecondaryQueries(int defaultQueryBatch) {
|
||||
graphContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
loadContext.executeSecondaryQueries(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +84,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* </p>
|
||||
*/
|
||||
public int getSecondaryQueriesMinBatchSize(int defaultQueryBatch) {
|
||||
return graphContext.getSecondaryQueriesMinBatchSize(this, defaultQueryBatch);
|
||||
return loadContext.getSecondaryQueriesMinBatchSize(this, defaultQueryBatch);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,7 +105,7 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
* Return the graph context for this query.
|
||||
*/
|
||||
public LoadContext getGraphContext() {
|
||||
return graphContext;
|
||||
return loadContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,10 +163,20 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
// initialise the persistenceContext and loadContext
|
||||
this.persistenceContext = getPersistenceContext(query, transaction);
|
||||
this.graphContext.setPersistenceContext(persistenceContext);
|
||||
this.loadContext = new DLoadContext(this);
|
||||
this.loadContext.registerSecondaryQueries(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* For iterate queries reset the persistenceContext and loadContext.
|
||||
*/
|
||||
public void flushPersistenceContextOnIterate() {
|
||||
persistenceContext = new DefaultPersistenceContext();
|
||||
loadContext.setPersistenceContext(persistenceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TransactionContext either explicitly set on the query or
|
||||
* transaction scoped.
|
||||
@@ -359,10 +367,6 @@ public final class OrmQueryRequest<T> extends BeanRequest implements BeanQueryRe
|
||||
}
|
||||
}
|
||||
|
||||
public void flushPersistenceContextOnIterate() {
|
||||
beanDescriptor.flushPersistenceContextOnIterate(persistenceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the request wants to log the secondary queries (test purpose).
|
||||
*/
|
||||
|
||||
@@ -2254,12 +2254,5 @@ public class BeanDescriptor<T> implements MetaBeanInfo {
|
||||
|
||||
return ctx.popBeanState();
|
||||
}
|
||||
|
||||
public void flushPersistenceContextOnIterate(PersistenceContext persistenceContext) {
|
||||
persistenceContext.clear(beanType);
|
||||
for (int i = 0; i < propertiesMany.length; i++) {
|
||||
persistenceContext.clear(propertiesMany[i].getBeanDescriptor().getBeanType());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ 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;
|
||||
import com.avaje.ebeaninternal.server.loadcontext.DLoadContext;
|
||||
import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext;
|
||||
|
||||
@@ -328,14 +327,15 @@ public final class BeanDescriptorCacheHelp<T> {
|
||||
if (context == null) {
|
||||
context = new DefaultPersistenceContext();
|
||||
}
|
||||
context.put(query.getId(), bean);
|
||||
|
||||
DLoadContext loadContext = new DLoadContext(desc.getEbeanServer(), desc, query.isReadOnly(), query);
|
||||
loadContext.setPersistenceContext(context);
|
||||
|
||||
EntityBeanIntercept ebi = ((EntityBean) bean)._ebean_getIntercept();
|
||||
// Not using a loadContext for beans coming out of L2 cache
|
||||
// so that means no batch lazy loading for these beans
|
||||
EntityBean entityBean = (EntityBean)bean;
|
||||
EntityBeanIntercept ebi = entityBean._ebean_getIntercept();
|
||||
ebi.setPersistenceContext(context);
|
||||
loadContext.register(null, ebi);
|
||||
Object id = desc.getId(entityBean);
|
||||
context.put(id, bean);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -29,7 +29,8 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
|
||||
super(parent, desc, path, defaultBatchSize, queryProps);
|
||||
|
||||
this.bufferList = new ArrayList<DLoadBeanContext.LoadBuffer>();
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadBeanContext.LoadBuffer>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
}
|
||||
|
||||
@@ -52,11 +53,11 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
|
||||
protected void register(EntityBeanIntercept ebi){
|
||||
|
||||
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
|
||||
if (currentBuffer.add(ebi)) {
|
||||
// the currentBuffer is full so create another one
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
currentBuffer.add(ebi);
|
||||
ebi.setBeanLoader(0, currentBuffer, getPersistenceContext());
|
||||
}
|
||||
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
@@ -99,23 +100,33 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
*/
|
||||
public static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
|
||||
private final PersistenceContext persistenceContext;
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
|
||||
public LoadBuffer(DLoadBeanContext context, int batchSize) {
|
||||
this.context = context;
|
||||
// set the persistence context as at this moment in
|
||||
// case it changes as part of a findIterate etc
|
||||
this.persistenceContext = context.getPersistenceContext();
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<EntityBeanIntercept>(batchSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean add(EntityBeanIntercept ebi) {
|
||||
list.add(ebi);
|
||||
public boolean isFull() {
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public void add(EntityBeanIntercept ebi) {
|
||||
list.add(ebi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EntityBeanIntercept> getBatch() {
|
||||
@@ -139,7 +150,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return context.getPersistenceContext();
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -49,15 +49,18 @@ public class DLoadContext implements LoadContext {
|
||||
private final Map<String,ObjectGraphNode> nodePathMap = new HashMap<String, ObjectGraphNode>();
|
||||
|
||||
private PersistenceContext persistenceContext;
|
||||
|
||||
private List<OrmQueryProperties> secQuery;
|
||||
|
||||
public DLoadContext(OrmQueryRequest<?> request) {
|
||||
|
||||
public DLoadContext(SpiEbeanServer ebeanServer, BeanDescriptor<?> rootDescriptor, Boolean readOnly, SpiQuery<?> query) {
|
||||
|
||||
this.ebeanServer = ebeanServer;
|
||||
this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize();
|
||||
this.rootDescriptor = rootDescriptor;
|
||||
this.readOnly = readOnly;
|
||||
this.persistenceContext = request.getPersistenceContext();
|
||||
this.ebeanServer = request.getServer();
|
||||
this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize();
|
||||
this.rootDescriptor = request.getBeanDescriptor();
|
||||
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.readOnly = query.isReadOnly();
|
||||
this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache());
|
||||
this.useAutofetchManager = query.getAutoFetchManager() != null;
|
||||
|
||||
@@ -72,7 +75,7 @@ public class DLoadContext implements LoadContext {
|
||||
|
||||
// initialise rootBeanContext after origin and relativePath have been set
|
||||
this.rootBeanContext = new DLoadBeanContext(this, rootDescriptor, null, defaultBatchSize, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isExcludeBeanCache() {
|
||||
return excludeBeanCache;
|
||||
|
||||
@@ -31,14 +31,16 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps);
|
||||
|
||||
this.property = property;
|
||||
this.bufferList = new ArrayList<DLoadManyContext.LoadBuffer>();
|
||||
// bufferList only required when using query joins (queryFetch)
|
||||
this.bufferList = (!queryFetch) ? null : new ArrayList<DLoadManyContext.LoadBuffer>();
|
||||
this.currentBuffer = createBuffer(firstBatchSize);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private LoadBuffer createBuffer(int size) {
|
||||
LoadBuffer buffer = new LoadBuffer(this, size);
|
||||
bufferList.add(buffer);
|
||||
if (bufferList != null) {
|
||||
bufferList.add(buffer);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -74,11 +76,11 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
|
||||
public void register(BeanCollection<?> bc){
|
||||
|
||||
bc.setLoader(0, currentBuffer);
|
||||
if (currentBuffer.add(bc)) {
|
||||
// the currentBuffer is full so create another one
|
||||
if (currentBuffer.isFull()) {
|
||||
currentBuffer = createBuffer(secondaryBatchSize);
|
||||
}
|
||||
}
|
||||
currentBuffer.add(bc);
|
||||
bc.setLoader(0, currentBuffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,22 +114,32 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
*/
|
||||
public static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final PersistenceContext persistenceContext;
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
private final List<BeanCollection<?>> list;
|
||||
|
||||
public LoadBuffer(DLoadManyContext context, int batchSize) {
|
||||
this.context = context;
|
||||
// set the persistence context as at this moment in
|
||||
// case it changes as part of a findIterate etc
|
||||
this.persistenceContext = context.getPersistenceContext();
|
||||
this.batchSize = batchSize;
|
||||
this.list = new ArrayList<BeanCollection<?>>(batchSize);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public boolean add(BeanCollection<?> bc) {
|
||||
public boolean isFull() {
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the buffer is full.
|
||||
*/
|
||||
public void add(BeanCollection<?> bc) {
|
||||
list.add(bc);
|
||||
return batchSize == list.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -162,7 +174,7 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex
|
||||
|
||||
@Override
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return context.getPersistenceContext();
|
||||
return persistenceContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -188,8 +188,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private final int maxRowsLimit;
|
||||
|
||||
private final PersistenceContext persistenceContext;
|
||||
|
||||
private DataReader dataReader;
|
||||
|
||||
/**
|
||||
@@ -266,7 +264,6 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
this.logWhereSql = queryPlan.getLogWhereSql();
|
||||
this.desc = request.getBeanDescriptor();
|
||||
this.predicates = predicates;
|
||||
this.persistenceContext = request.getPersistenceContext();
|
||||
this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT;
|
||||
this.help = createHelp(request);
|
||||
this.collection = (BeanCollection<T>) (help != null ? help.createEmpty(false) : null);
|
||||
@@ -420,7 +417,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
* Return the persistence context.
|
||||
*/
|
||||
public PersistenceContext getPersistenceContext() {
|
||||
return persistenceContext;
|
||||
return request.getPersistenceContext();
|
||||
}
|
||||
|
||||
public void setLoadedBean(EntityBean bean, Object id, Object lazyLoadParentId) {
|
||||
@@ -443,7 +440,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
if (lazyLoadParentId != null) {
|
||||
if (!lazyLoadParentId.equals(this.lazyLoadParentId)) {
|
||||
// get the appropriate parent bean from the persistence context
|
||||
this.lazyLoadParentBean = (EntityBean)persistenceContext.get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentBean = (EntityBean)getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId);
|
||||
this.lazyLoadParentId = lazyLoadParentId;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user