From f91789886cb8f4535603cb5aea95440a59cbf895 Mon Sep 17 00:00:00 2001 From: Rob Bygrave Date: Wed, 28 May 2014 00:21:57 +1200 Subject: [PATCH] Backport of fix to 3.x for #131 - Memory issue (Hard refs) when using findIterate --- pom.xml | 2 +- .../java/com/avaje/ebean/ExpressionList.java | 17 -- src/main/java/com/avaje/ebean/Query.java | 37 ----- .../com/avaje/ebeaninternal/api/SpiQuery.java | 20 --- .../server/core/DefaultServer.java | 18 +-- .../server/core/OrmQueryRequest.java | 21 ++- .../server/deploy/BeanDescriptor.java | 8 - .../server/expression/JunctionExpression.java | 10 -- .../server/loadcontext/DLoadBeanContext.java | 24 ++- .../server/loadcontext/DLoadContext.java | 10 +- .../server/loadcontext/DLoadManyContext.java | 147 ++++++++++-------- .../ebeaninternal/server/query/CQuery.java | 41 +---- .../server/query/CQueryFetchIds.java | 5 - .../server/querydefn/DefaultOrmQuery.java | 55 ------- .../util/DefaultExpressionList.java | 10 -- .../util/FilterExpressionList.java | 12 +- .../tests/basic/TestBackgroundFetchAfter.java | 63 -------- 17 files changed, 125 insertions(+), 375 deletions(-) delete mode 100644 src/test/java/com/avaje/tests/basic/TestBackgroundFetchAfter.java diff --git a/pom.xml b/pom.xml index 40f87490b..fa3b00616 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.avaje.ebeanorm avaje-ebeanorm - 3.3.5-SNAPSHOT + 3.4.1-SNAPSHOT jar avaje-ebeanorm diff --git a/src/main/java/com/avaje/ebean/ExpressionList.java b/src/main/java/com/avaje/ebean/ExpressionList.java index 98d912e48..bd0ae473b 100644 --- a/src/main/java/com/avaje/ebean/ExpressionList.java +++ b/src/main/java/com/avaje/ebean/ExpressionList.java @@ -244,14 +244,6 @@ public interface ExpressionList extends Serializable { */ public Query setMaxRows(int maxRows); - /** - * Set the number of rows after which the fetching should continue in a - * background thread. - * - * @see Query#setBackgroundFetchAfter(int) - */ - public Query setBackgroundFetchAfter(int backgroundFetchAfter); - /** * Set the name of the property which values become the key of a map. * @@ -259,15 +251,6 @@ public interface ExpressionList extends Serializable { */ public Query setMapKey(String mapKey); - /** - * Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)}. - * Set a QueryListener for bean by bean processing. - * - * @see Query#setListener(QueryListener) - * @deprecated Migrate to {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)} - */ - public Query setListener(QueryListener queryListener); - /** * Set to true to use the query for executing this query. * diff --git a/src/main/java/com/avaje/ebean/Query.java b/src/main/java/com/avaje/ebean/Query.java index fa7df252b..57a86f241 100644 --- a/src/main/java/com/avaje/ebean/Query.java +++ b/src/main/java/com/avaje/ebean/Query.java @@ -663,36 +663,6 @@ public interface Query extends Serializable { */ public Query setParameter(int position, Object value); - /** - * Please migrate to using {@link #findIterate()} or {@link #findVisit(QueryResultVisitor)} - *

- * Set a listener to process the query on a row by row basis. - *

- *

- * Use this when you want to process a large query and do not want to hold the - * entire query result in memory. - *

- *

- * It this case the rows are not loaded into the persistence context and - * instead are processed by the query listener. - *

- * - *
-   * QueryListener<Order> listener = ...;
-   *   
-   * Query<Order> query  = Ebean.createQuery(Order.class);
-   *   
-   * // set the listener that will process each order one at a time
-   * query.setListener(listener);
-   *   
-   * // execute the query. Note that the returned
-   * // list (emptyList) will be empty ...
-   * List<Order> emtyList = query.findList();
-   * 
- * @deprecated Deprecated in favor of {@link #findIterate()} and {@link #findVisit(QueryResultVisitor)} - */ - public Query setListener(QueryListener queryListener); - /** * Set the Id value to query. This is used with findUnique(). *

@@ -966,13 +936,6 @@ public interface Query extends Serializable { */ public Query setMaxRows(int maxRows); - /** - * Set the rows after which fetching should continue in a background thread. - * - * @param backgroundFetchAfter - */ - public Query setBackgroundFetchAfter(int backgroundFetchAfter); - /** * Set the property to use as keys for a map. *

diff --git a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java index 792e80beb..586818857 100644 --- a/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/api/SpiQuery.java @@ -6,7 +6,6 @@ import java.util.List; import com.avaje.ebean.ExpressionList; import com.avaje.ebean.OrderBy; import com.avaje.ebean.Query; -import com.avaje.ebean.QueryListener; import com.avaje.ebean.bean.BeanCollectionTouched; import com.avaje.ebean.bean.CallStack; import com.avaje.ebean.bean.EntityBean; @@ -509,12 +508,6 @@ public interface SpiQuery extends Query { */ public String getMapKey(); - /** - * Return the number of rows after which fetching should occur in a - * background thread. - */ - public int getBackgroundFetchAfter(); - /** * Return the maximum number of rows to return in the query. */ @@ -545,19 +538,6 @@ public interface SpiQuery extends Query { */ public Object getId(); - /** - * Return the queryListener. - */ - public QueryListener getListener(); - - /** - * Return true if this query should use its own transaction. - *

- * This is true for background fetching and when using QueryListener. - *

- */ - public boolean createOwnTransaction(); - /** * Set the generated sql for debug purposes. * diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java index 63fdfafc0..a6b1d6917 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java @@ -90,7 +90,6 @@ import com.avaje.ebeaninternal.server.deploy.InheritInfo; import com.avaje.ebeaninternal.server.el.ElFilter; import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch; import com.avaje.ebeaninternal.server.lib.ShutdownManager; -import com.avaje.ebeaninternal.server.loadcontext.DLoadContext; import com.avaje.ebeaninternal.server.query.CQuery; import com.avaje.ebeaninternal.server.query.CQueryEngine; import com.avaje.ebeaninternal.server.query.CallableQueryIds; @@ -1133,7 +1132,7 @@ public final class DefaultServer implements SpiEbeanServer { if (Mode.LAZYLOAD_MANY.equals(query.getMode())) { allowOneManyFetch = false; - } else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect() && query.getBackgroundFetchAfter() == 0) { + } else if (query.hasMaxRowsOrFirstRow() && !query.isRawSql() && !query.isSqlSelect()) { // convert ALL fetch joins to Many's to be query joins // so that limit offset type SQL clauses work allowOneManyFetch = false; @@ -1194,16 +1193,15 @@ public final class DefaultServer implements SpiEbeanServer { if (cachedBean != null) { if (context == null) { context = new DefaultPersistenceContext(); - } - context.put(query.getId(), cachedBean); - - DLoadContext loadContext = new DLoadContext(this, beanDescriptor, query.isReadOnly(), query); - loadContext.setPersistenceContext(context); - - EntityBeanIntercept ebi = ((EntityBean) cachedBean)._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) cachedBean; + EntityBeanIntercept ebi = entityBean._ebean_getIntercept(); ebi.setPersistenceContext(context); - loadContext.register(null, ebi); + Object id = beanDescriptor.getId(entityBean); + context.put(id, entityBean); } return (T) cachedBean; diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java index e01896b93..c6a83f4f6 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java +++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java @@ -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,7 +44,7 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe private final BeanFinder finder; - private final LoadContext graphContext; + private LoadContext graphContext; private final Boolean readOnly; @@ -75,9 +76,6 @@ public final class OrmQueryRequest 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) { @@ -163,12 +161,7 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe @Override public void initTransIfRequired() { // first check if the query requires its own transaction - if (query.createOwnTransaction()) { - // using background fetch or query listener etc - transaction = ebeanServer.createQueryTransaction(); - createdTransaction = true; - - } else if (transaction == null) { + if (transaction == null) { // maybe a current one transaction = ebeanServer.getCurrentServerTransaction(); if (transaction == null) { @@ -177,8 +170,11 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe createdTransaction = true; } } + this.persistenceContext = getPersistenceContext(query, transaction); - this.graphContext.setPersistenceContext(persistenceContext); + + this.graphContext = new DLoadContext(this); + this.graphContext.registerSecondaryQueries(query); } /** @@ -381,7 +377,8 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe } public void flushPersistenceContextOnIterate() { - beanDescriptor.flushPersistenceContextOnIterate(persistenceContext); + persistenceContext = new DefaultPersistenceContext(); + graphContext.setPersistenceContext(persistenceContext); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java index 7e0ce4b6a..08578ed59 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java +++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java @@ -2444,13 +2444,5 @@ public class BeanDescriptor implements MetaBeanInfo { return false; } - - public void flushPersistenceContextOnIterate(PersistenceContext persistenceContext) { - persistenceContext.clear(beanType); - for (int i = 0; i < propertiesMany.length; i++) { - persistenceContext.clear(propertiesMany[i].getBeanDescriptor().getBeanType()); - } - - } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java index 068053ccd..c3062bac5 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java +++ b/src/main/java/com/avaje/ebeaninternal/server/expression/JunctionExpression.java @@ -14,7 +14,6 @@ import com.avaje.ebean.Junction; import com.avaje.ebean.OrderBy; import com.avaje.ebean.PagingList; import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryListener; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; @@ -375,19 +374,10 @@ abstract class JunctionExpression implements Junction, SpiExpression, Expr return exprList.select(properties); } - public com.avaje.ebean.Query setBackgroundFetchAfter(int backgroundFetchAfter) { - return exprList.setBackgroundFetchAfter(backgroundFetchAfter); - } - public com.avaje.ebean.Query setFirstRow(int firstRow) { return exprList.setFirstRow(firstRow); } - @Deprecated - public com.avaje.ebean.Query setListener(QueryListener queryListener) { - return exprList.setListener(queryListener); - } - public com.avaje.ebean.Query setMapKey(String mapKey) { return exprList.setMapKey(mapKey); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java index 347f1a251..fc2f66bbd 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java @@ -28,8 +28,9 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex super(parent, desc, path, defaultBatchSize, queryProps); - this.currentBuffer = createBuffer(firstBatchSize); - this.bufferList = queryFetch ? new ArrayList() : null; + // bufferList only required when using query joins (queryFetch) + this.bufferList = (!queryFetch) ? null : new ArrayList(); + this.currentBuffer = createBuffer(firstBatchSize); } protected void configureQuery(SpiQuery query, String lazyLoadProperty) { @@ -51,11 +52,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 + if (currentBuffer.isFull()) { currentBuffer = createBuffer(secondaryBatchSize); } + currentBuffer.add(ebi); + ebi.setBeanLoader(0, currentBuffer, getPersistenceContext()); } private LoadBuffer createBuffer(int size) { @@ -98,22 +99,29 @@ 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 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(batchSize); } + public boolean isFull() { + return batchSize == list.size(); + } + /** * Return true if the buffer is full. */ - public boolean add(EntityBeanIntercept ebi) { + public void add(EntityBeanIntercept ebi) { list.add(ebi); - return batchSize == list.size(); } @Override @@ -138,7 +146,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex @Override public PersistenceContext getPersistenceContext() { - return context.getPersistenceContext(); + return persistenceContext; } @Override diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java index 31aec954f..bc8e9cb2c 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadContext.java @@ -52,12 +52,14 @@ public class DLoadContext implements LoadContext { private List secQuery; - public DLoadContext(SpiEbeanServer ebeanServer, BeanDescriptor rootDescriptor, Boolean readOnly, SpiQuery query) { + public DLoadContext(OrmQueryRequest request) { - this.ebeanServer = ebeanServer; + this.persistenceContext = request.getPersistenceContext(); + this.ebeanServer = request.getServer(); this.defaultBatchSize = ebeanServer.getLazyLoadBatchSize(); - this.rootDescriptor = rootDescriptor; - this.readOnly = readOnly; + this.rootDescriptor = request.getBeanDescriptor(); + SpiQuery query = request.getQuery(); + this.readOnly = query.isReadOnly(); this.excludeBeanCache = Boolean.FALSE.equals(query.isUseBeanCache()); this.useAutofetchManager = query.getAutoFetchManager() != null; diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadManyContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadManyContext.java index a8f5ff1fa..b2e7bf833 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadManyContext.java +++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadManyContext.java @@ -17,70 +17,71 @@ import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany; import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties; public class DLoadManyContext extends DLoadBaseContext implements LoadManyContext { - + protected final BeanPropertyAssocMany property; - + private List bufferList; - + private LoadBuffer currentBuffer; - - public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany property, - String path, int defaultBatchSize, OrmQueryProperties queryProps) { - super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps); + public DLoadManyContext(DLoadContext parent, BeanPropertyAssocMany property, String path, int defaultBatchSize, + OrmQueryProperties queryProps) { - this.property = property; - this.bufferList = new ArrayList(); + super(parent, property.getBeanDescriptor(), path, defaultBatchSize, queryProps); + + this.property = property; + // bufferList only required when using query joins (queryFetch) + this.bufferList = (!queryFetch) ? null : new ArrayList(); 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; } - - public void configureQuery(SpiQuery query){ - - // propagate the readOnly state - if (parent.isReadOnly() != null){ - query.setReadOnly(parent.isReadOnly()); - } - query.setParentNode(objectGraphNode); - - if (queryProps != null){ - queryProps.configureBeanQuery(query); - } - - if (parent.isUseAutofetchManager()){ - query.setAutofetch(true); - } - } - public BeanPropertyAssocMany getBeanProperty() { - return property; - } + public void configureQuery(SpiQuery query) { - public BeanDescriptor getBeanDescriptor() { - return desc; - } + // propagate the readOnly state + if (parent.isReadOnly() != null) { + query.setReadOnly(parent.isReadOnly()); + } + query.setParentNode(objectGraphNode); - - public String getName() { - return parent.getEbeanServer().getName(); - } + if (queryProps != null) { + queryProps.configureBeanQuery(query); + } - public void register(BeanCollection bc){ - - bc.setLoader(0, currentBuffer); - if (currentBuffer.add(bc)) { - // the currentBuffer is full so create another one + if (parent.isUseAutofetchManager()) { + query.setAutofetch(true); + } + } + + public BeanPropertyAssocMany getBeanProperty() { + return property; + } + + public BeanDescriptor getBeanDescriptor() { + return desc; + } + + public String getName() { + return parent.getEbeanServer().getName(); + } + + public void register(BeanCollection bc) { + + if (currentBuffer.isFull()) { currentBuffer = createBuffer(secondaryBatchSize); } - } + currentBuffer.add(bc); + bc.setLoader(0, currentBuffer); + } - - public void loadSecondaryQuery(OrmQueryRequest parentRequest, int requestedBatchSize, boolean all){ + public void loadSecondaryQuery(OrmQueryRequest parentRequest, int requestedBatchSize, boolean all) { if (!queryFetch) { throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?"); @@ -89,33 +90,38 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex 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); + 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. + * 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 PersistenceContext persistenceContext; private final DLoadManyContext context; private final int batchSize; private final List> 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>(batchSize); } @@ -123,11 +129,17 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex /** * Return true if the buffer is full. */ - public boolean add(BeanCollection bc) { - list.add(bc); + public boolean isFull() { return batchSize == list.size(); } + /** + * Return true if the buffer is full. + */ + public void add(BeanCollection bc) { + list.add(bc); + } + @Override public List> getBatch() { return list; @@ -137,22 +149,22 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex public BeanPropertyAssocMany getBeanProperty() { return context.property; } - + @Override public ObjectGraphNode getObjectGraphNode() { return context.objectGraphNode; } - + @Override - public void configureQuery(SpiQuery query){ + public void configureQuery(SpiQuery query) { context.configureQuery(query); } - + @Override public String getName() { return context.serverName; } - + @Override public BeanDescriptor getBeanDescriptor() { return context.desc; @@ -160,9 +172,9 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex @Override public PersistenceContext getPersistenceContext() { - return context.getPersistenceContext(); + return persistenceContext; } - + @Override public String getFullPath() { return context.fullPath; @@ -182,9 +194,10 @@ public class DLoadManyContext extends DLoadBaseContext implements LoadManyContex return; } } - - // Should reduce the list by checking each beanCollection in the L2 first before executing the query - + + // 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); } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java index 96549891b..52f39ab16 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java @@ -14,7 +14,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryListener; import com.avaje.ebean.bean.BeanCollection; import com.avaje.ebean.bean.BeanCollectionAdd; import com.avaje.ebean.bean.EntityBean; @@ -24,7 +23,6 @@ import com.avaje.ebean.bean.NodeUsageListener; import com.avaje.ebean.bean.ObjectGraphNode; import com.avaje.ebean.bean.PersistenceContext; import com.avaje.ebeaninternal.api.LoadContext; -import com.avaje.ebeaninternal.api.SpiEbeanServer; import com.avaje.ebeaninternal.api.SpiExpressionList; import com.avaje.ebeaninternal.api.SpiQuery; import com.avaje.ebeaninternal.api.SpiQuery.Mode; @@ -41,7 +39,6 @@ import com.avaje.ebeaninternal.server.deploy.DbReadContext; import com.avaje.ebeaninternal.server.el.ElPropertyValue; import com.avaje.ebeaninternal.server.lib.util.StringHelper; import com.avaje.ebeaninternal.server.querydefn.OrmQueryProperties; -import com.avaje.ebeaninternal.server.transaction.DefaultPersistenceContext; import com.avaje.ebeaninternal.server.type.DataBind; import com.avaje.ebeaninternal.server.type.DataReader; @@ -135,8 +132,6 @@ public class CQuery implements DbReadContext, CancelableQuery { private final SpiQuery query; - private final QueryListener queryListener; - private Map currentPathMap; private String currentPrefix; @@ -189,8 +184,6 @@ public class CQuery implements DbReadContext, CancelableQuery { */ private final ElPropertyValue manyPropertyEl; - private final int backgroundFetchAfter; - private final int maxRowsLimit; /** @@ -198,8 +191,6 @@ public class CQuery implements DbReadContext, CancelableQuery { */ private boolean hasHitBackgroundFetchAfter; - private final PersistenceContext persistenceContext; - private DataReader dataReader; /** @@ -276,20 +267,7 @@ public class CQuery implements DbReadContext, CancelableQuery { this.desc = request.getBeanDescriptor(); this.predicates = predicates; - this.queryListener = query.getListener(); - if (queryListener == null) { - // normal, use the one from the transaction - this.persistenceContext = request.getPersistenceContext(); - } else { - // 'Row Level Transaction Context'... - // local transaction context that will be reset - // after each 'master' bean is sent to the listener - this.persistenceContext = new DefaultPersistenceContext(); - } - this.maxRowsLimit = query.getMaxRows() > 0 ? query.getMaxRows() : GLOBAL_ROW_LIMIT; - this.backgroundFetchAfter = query.getBackgroundFetchAfter() > 0 ? query - .getBackgroundFetchAfter() : Integer.MAX_VALUE; this.help = createHelp(request); this.collection = (BeanCollection) (help != null ? help.createEmpty(false) : null); @@ -443,7 +421,7 @@ public class CQuery implements DbReadContext, CancelableQuery { * Return the persistence context. */ public PersistenceContext getPersistenceContext() { - return persistenceContext; + return request.getPersistenceContext(); } public void setLoadedBean(Object bean, Object id, Object lazyLoadParentId) { @@ -466,7 +444,7 @@ public class CQuery implements DbReadContext, CancelableQuery { if (lazyLoadParentId != null) { if (!lazyLoadParentId.equals(this.lazyLoadParentId)) { // get the appropriate parent bean from the persistence context - this.lazyLoadParentBean = persistenceContext.get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId); + this.lazyLoadParentBean = getPersistenceContext().get(lazyLoadManyProperty.getBeanDescriptor().getBeanType(), lazyLoadParentId); this.lazyLoadParentId = lazyLoadParentId; } @@ -564,12 +542,6 @@ public class CQuery implements DbReadContext, CancelableQuery { return false; } - if (inForeground && loadedBeanCount >= backgroundFetchAfter) { - hasHitBackgroundFetchAfter = true; - collection.setFinishedFetch(false); - return false; - } - if (!manyIncluded) { // simple query... no details... return readRow(); @@ -687,13 +659,8 @@ public class CQuery implements DbReadContext, CancelableQuery { private void readTheRows(boolean inForeground) throws SQLException { while (hasNextBean(inForeground)) { - if (queryListener != null) { - queryListener.process(getLoadedBean()); - - } else { - // add to the list/set/map - help.add(collection, getLoadedBean()); - } + // add to the list/set/map + help.add(collection, getLoadedBean()); } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java index e277ba5f6..6ac406995 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java +++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryFetchIds.java @@ -73,7 +73,6 @@ public class CQueryFetchIds { private int rowCount; private final int maxRows; - private final int bgFetchAfter; /** * Create the Sql select based on the request. @@ -86,7 +85,6 @@ public class CQueryFetchIds { this.query = request.getQuery(); this.sql = sql; this.maxRows = query.getMaxRows(); - this.bgFetchAfter = query.getBackgroundFetchAfter(); query.setGeneratedSql(sql); @@ -184,9 +182,6 @@ public class CQueryFetchIds { hasMoreRows = rset.next(); break; - } else if (bgFetchAfter > 0 && rowCount >= bgFetchAfter) { - useBackgroundToContinueFetch = true; - break; } } diff --git a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java index 99ceb508e..b54a1578e 100644 --- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java +++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java @@ -21,7 +21,6 @@ import com.avaje.ebean.OrderBy.Property; import com.avaje.ebean.PagingList; import com.avaje.ebean.Query; import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryListener; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.RawSql; import com.avaje.ebean.bean.BeanCollectionTouched; @@ -68,8 +67,6 @@ public class DefaultOrmQuery implements SpiQuery { * Used to add beans to the PersistanceContext prior to query. */ private transient ArrayList contextAdditions; - - private transient QueryListener queryListener; /** * For lazy loading of ManyToMany we need to add a join to the intersection @@ -142,11 +139,6 @@ public class DefaultOrmQuery implements SpiQuery { private boolean futureFetch; private List partialIds; - - /** - * The rows after which the fetch continues in a bg thread. - */ - private int backgroundFetchAfter; private int timeout = -1; @@ -437,7 +429,6 @@ public class DefaultOrmQuery implements SpiQuery { copy.additionalWhere = additionalWhere; copy.additionalHaving = additionalHaving; copy.distinct = distinct; - copy.backgroundFetchAfter = backgroundFetchAfter; copy.timeout = timeout; copy.mapKey = mapKey; copy.id = id; @@ -1016,26 +1007,6 @@ public class DefaultOrmQuery implements SpiQuery { return this; } - /** - * Return the findListener is one has been set. - */ - public QueryListener getListener() { - return queryListener; - } - - /** - * Set a FindListener. This is designed for large fetches where lots are - * rows are to be processed and instead of returning all the rows they are - * processed one at a time. - *

- * Note that the returning List Set or Map will be empty. - *

- */ - public DefaultOrmQuery setListener(QueryListener queryListener) { - this.queryListener = queryListener; - return this; - } - public Class getBeanType() { return beanType; } @@ -1112,15 +1083,6 @@ public class DefaultOrmQuery implements SpiQuery { return this; } - public int getBackgroundFetchAfter() { - return backgroundFetchAfter; - } - - public DefaultOrmQuery setBackgroundFetchAfter(int backgroundFetchAfter) { - this.backgroundFetchAfter = backgroundFetchAfter; - return this; - } - public Object getId() { return id; } @@ -1235,23 +1197,6 @@ public class DefaultOrmQuery implements SpiQuery { return whereExpressions; } - /** - * Return true if using background fetching or a queryListener. - */ - public boolean createOwnTransaction() { - if (futureFetch){ - // the future fetches have already created - // their own transaction - return false; - } - if (backgroundFetchAfter > 0 || queryListener != null) { - // run in own transaction as we can't know how long - // the background fetching will continue etc - return true; - } - return false; - } - public String getGeneratedSql() { return generatedSql; } diff --git a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java index cfa5695f2..0323837fa 100644 --- a/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/util/DefaultExpressionList.java @@ -17,7 +17,6 @@ import com.avaje.ebean.OrderBy; import com.avaje.ebean.PagingList; import com.avaje.ebean.Query; import com.avaje.ebean.QueryIterator; -import com.avaje.ebean.QueryListener; import com.avaje.ebean.QueryResultVisitor; import com.avaje.ebean.event.BeanQueryRequest; import com.avaje.ebeaninternal.api.HashQueryPlanBuilder; @@ -213,19 +212,10 @@ public class DefaultExpressionList implements SpiExpressionList { return query.setMaxRows(maxRows); } - public Query setBackgroundFetchAfter(int backgroundFetchAfter) { - return query.setBackgroundFetchAfter(backgroundFetchAfter); - } - public Query setMapKey(String mapKey) { return query.setMapKey(mapKey); } - @Deprecated - public Query setListener(QueryListener queryListener) { - return query.setListener(queryListener); - } - public Query setUseCache(boolean useCache) { return query.setUseCache(useCache); } diff --git a/src/main/java/com/avaje/ebeaninternal/util/FilterExpressionList.java b/src/main/java/com/avaje/ebeaninternal/util/FilterExpressionList.java index ef607ea5d..fdbb42e6a 100644 --- a/src/main/java/com/avaje/ebeaninternal/util/FilterExpressionList.java +++ b/src/main/java/com/avaje/ebeaninternal/util/FilterExpressionList.java @@ -14,7 +14,6 @@ import com.avaje.ebean.FutureRowCount; import com.avaje.ebean.OrderBy; import com.avaje.ebean.PagingList; import com.avaje.ebean.Query; -import com.avaje.ebean.QueryListener; import com.avaje.ebeaninternal.api.SpiExpressionList; import com.avaje.ebeaninternal.server.expression.FilterExprPath; @@ -128,19 +127,10 @@ public class FilterExpressionList extends DefaultExpressionList { throw new PersistenceException(notAllowedMessage); } - public Query setBackgroundFetchAfter(int backgroundFetchAfter) { - return rootQuery.setBackgroundFetchAfter(backgroundFetchAfter); - } - public Query setFirstRow(int firstRow) { return rootQuery.setFirstRow(firstRow); } - - @Deprecated - public Query setListener(QueryListener queryListener) { - return rootQuery.setListener(queryListener); - } - + public Query setMapKey(String mapKey) { return rootQuery.setMapKey(mapKey); } diff --git a/src/test/java/com/avaje/tests/basic/TestBackgroundFetchAfter.java b/src/test/java/com/avaje/tests/basic/TestBackgroundFetchAfter.java deleted file mode 100644 index 0260f978d..000000000 --- a/src/test/java/com/avaje/tests/basic/TestBackgroundFetchAfter.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.avaje.tests.basic; - -import junit.framework.Assert; - -import org.junit.Test; - -import com.avaje.ebean.BaseTestCase; -import com.avaje.ebean.Ebean; -import com.avaje.ebean.Query; -import com.avaje.ebeaninternal.api.SpiEbeanServer; -import com.avaje.tests.model.basic.Order; -import com.avaje.tests.model.basic.ResetBasicData; - -public class TestBackgroundFetchAfter extends BaseTestCase { - - @Test - public void testWrtJoin() { - - ResetBasicData.reset(); - - SpiEbeanServer server = (SpiEbeanServer)Ebean.getServer(null); - boolean h2Db = "h2".equals(server.getDatabasePlatform().getName()); - - // limit not in sql as join to many - Query q = Ebean.find(Order.class) - .fetch("details") - .setBackgroundFetchAfter(3) - .setMaxRows(10); - - q.findList(); - String sql = q.getGeneratedSql(); - - if (h2Db){ - Assert.assertTrue(sql.indexOf("limit") == -1); - } - - // allows limit use as no join to many - q = Ebean.find(Order.class) - .setBackgroundFetchAfter(3) - .setMaxRows(10); - - q.findList(); - sql = q.getGeneratedSql(); - - if (h2Db){ - Assert.assertTrue(sql.indexOf("limit") > -1); - } - - // allows limit use as join to one (not many) - q = Ebean.find(Order.class) - .fetch("customer") - .setBackgroundFetchAfter(3) - .setMaxRows(10); - - q.findList(); - sql = q.getGeneratedSql(); - - if (h2Db){ - Assert.assertTrue(sql.indexOf("limit") > -1); - } - } - -}