diff --git a/src/main/java/com/avaje/ebean/EbeanServer.java b/src/main/java/com/avaje/ebean/EbeanServer.java
index ec28b5d14..e6567b8bb 100644
--- a/src/main/java/com/avaje/ebean/EbeanServer.java
+++ b/src/main/java/com/avaje/ebean/EbeanServer.java
@@ -11,6 +11,7 @@ import javax.persistence.OptimisticLockException;
import com.avaje.ebean.annotation.CacheStrategy;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.config.ServerConfig;
+import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
@@ -117,6 +118,13 @@ public interface EbeanServer {
*/
public ExpressionFactory getExpressionFactory();
+ /**
+ * Return the MetaInfoManager which is used to get meta data from the EbeanServer
+ * such as query execution statistics.
+ */
+ public MetaInfoManager getMetaInfoManager();
+
+
/**
* Return the BeanState for a given entity bean.
*
diff --git a/src/main/java/com/avaje/ebean/bean/CallStack.java b/src/main/java/com/avaje/ebean/bean/CallStack.java
index 66f7a937f..43d17ce0e 100644
--- a/src/main/java/com/avaje/ebean/bean/CallStack.java
+++ b/src/main/java/com/avaje/ebean/bean/CallStack.java
@@ -1,6 +1,7 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
+import java.util.Arrays;
/**
* Represent the call stack (stack trace elements).
@@ -34,6 +35,25 @@ public final class CallStack implements Serializable {
}
this.pathHash = enc(hc);
}
+
+ public int hashCode() {
+ int hc = 0;
+ for (int i = 0; i < callStack.length; i++) {
+ hc = 31 * hc + callStack[i].hashCode();
+ }
+ return hc;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof CallStack)) {
+ return false;
+ }
+ CallStack e = (CallStack) obj;
+ return Arrays.equals(callStack, e.callStack);
+ }
/**
* Return the first element of the call stack.
diff --git a/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java b/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java
index 031f91e22..8cfd0e361 100644
--- a/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java
+++ b/src/main/java/com/avaje/ebean/bean/ObjectGraphNode.java
@@ -1,6 +1,7 @@
package com.avaje.ebean.bean;
import java.io.Serializable;
+import java.util.Objects;
/**
* Identifies a unique node of an object graph.
@@ -66,4 +67,23 @@ public final class ObjectGraphNode implements Serializable {
public String toString() {
return "origin:" + originQueryPoint + " " + ":" + path + ":" + path;
}
+
+ public int hashCode() {
+ int hc = 31 * originQueryPoint.hashCode();
+ hc = 31 * hc + Objects.hashCode(path);
+ return hc;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ObjectGraphNode)) {
+ return false;
+ }
+
+ ObjectGraphNode e = (ObjectGraphNode) obj;
+ return Objects.equals(e.path, path)
+ && e.originQueryPoint.equals(originQueryPoint);
+ }
}
diff --git a/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java b/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java
index 9c9f97635..d94487df7 100644
--- a/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java
+++ b/src/main/java/com/avaje/ebean/bean/ObjectGraphOrigin.java
@@ -14,17 +14,20 @@ import java.io.Serializable;
*/
public final class ObjectGraphOrigin implements Serializable {
- private static final long serialVersionUID = 410937765287968707L;
+ private static final long serialVersionUID = 410937765287968708L;
private final CallStack callStack;
- private final String key;
-
private final String beanType;
+ private final int queryHash;
+
+ private final String key;
+
public ObjectGraphOrigin(int queryHash, CallStack callStack, String beanType) {
this.callStack = callStack;
this.beanType = beanType;
+ this.queryHash = queryHash;
this.key = callStack.getOriginKey(queryHash);
}
@@ -58,4 +61,24 @@ public final class ObjectGraphOrigin implements Serializable {
return key + " " + beanType + " " + callStack.getFirstStackTraceElement();
}
+ public int hashCode() {
+ int hc = 31 * callStack.hashCode();
+ hc = 31 * hc + beanType.hashCode();
+ hc = 31 * hc + queryHash;
+ return hc;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof ObjectGraphOrigin)) {
+ return false;
+ }
+
+ ObjectGraphOrigin e = (ObjectGraphOrigin) obj;
+ return e.queryHash == queryHash
+ && e.beanType.equals(beanType)
+ && e.callStack.equals(callStack);
+ }
}
diff --git a/src/main/java/com/avaje/ebean/meta/MetaAutoFetchStatistic.java b/src/main/java/com/avaje/ebean/meta/MetaAutoFetchStatistic.java
index e7327d835..1c55e5c48 100644
--- a/src/main/java/com/avaje/ebean/meta/MetaAutoFetchStatistic.java
+++ b/src/main/java/com/avaje/ebean/meta/MetaAutoFetchStatistic.java
@@ -101,13 +101,13 @@ public class MetaAutoFetchStatistic implements Serializable {
private final String path;
- private final int exeCount;
+ private final long exeCount;
- private final int totalBeanLoaded;
+ private final long totalBeanLoaded;
- private final int totalMicros;
+ private final long totalMicros;
- public QueryStats(String path, int exeCount, int totalBeanLoaded, int totalMicros) {
+ public QueryStats(String path, long exeCount, long totalBeanLoaded, long totalMicros) {
this.path = path;
this.exeCount = exeCount;
this.totalBeanLoaded = totalBeanLoaded;
@@ -125,21 +125,21 @@ public class MetaAutoFetchStatistic implements Serializable {
/**
* The number of queries executed.
*/
- public int getExeCount() {
+ public long getExeCount() {
return exeCount;
}
/**
* The total number of beans loaded by the query.
*/
- public int getTotalBeanLoaded() {
+ public long getTotalBeanLoaded() {
return totalBeanLoaded;
}
/**
* The total time in microseconds of the queries.
*/
- public int getTotalMicros() {
+ public long getTotalMicros() {
return totalMicros;
}
diff --git a/src/main/java/com/avaje/ebean/meta/MetaBeanInfo.java b/src/main/java/com/avaje/ebean/meta/MetaBeanInfo.java
new file mode 100644
index 000000000..b991582e0
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/meta/MetaBeanInfo.java
@@ -0,0 +1,17 @@
+package com.avaje.ebean.meta;
+
+import java.util.List;
+
+public interface MetaBeanInfo {
+
+ /**
+ * Collect the current query plan statistics return the non-empty statistics.
+ */
+ public List collectQueryPlanStatistics(boolean reset);
+
+ /**
+ * Collect the current query plan statistics return all the statistics (include query plans that haven't had query executions).
+ */
+ public List collectAllQueryPlanStatistics(boolean reset);
+
+}
diff --git a/src/main/java/com/avaje/ebean/meta/MetaBeanQueryPlanStatistic.java b/src/main/java/com/avaje/ebean/meta/MetaBeanQueryPlanStatistic.java
new file mode 100644
index 000000000..6980c59c8
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/meta/MetaBeanQueryPlanStatistic.java
@@ -0,0 +1,79 @@
+package com.avaje.ebean.meta;
+
+
+
+/**
+ * Query execution statistics Meta data.
+ */
+public interface MetaBeanQueryPlanStatistic {
+
+ /**
+ * Return the bean type this query plan is for.
+ */
+ public Class> getBeanType();
+
+ /**
+ * Return true if this query plan was tuned by Autofetch.
+ */
+ public boolean isAutofetchTuned();
+
+ /**
+ * Return the query plan hash.
+ */
+ public int getQueryPlanHash();
+
+ /**
+ * Return the sql executed.
+ */
+ public String getSql();
+
+ /**
+ * Return the total number of queries executed.
+ */
+ public long getExecutionCount();
+
+ /**
+ * Return the total number of beans loaded by the queries.
+ *
+ * This excludes background fetching.
+ *
+ */
+ public long getTotalLoadedBeans();
+
+ /**
+ * Return the total time taken by executions of this query.
+ */
+ public long getTotalTimeMicros();
+
+ /**
+ * Return the max execution time for this query.
+ */
+ public long getMaxTimeMicros();
+
+ /**
+ * Return the time collection started (or was last reset).
+ */
+ public long getCollectionStart();
+
+ /**
+ * Return the time of the last query executed using this plan.
+ */
+ public long getLastQueryTime();
+
+ /**
+ * Return the average query execution time in microseconds.
+ *
+ * This excludes background fetching.
+ *
+ */
+ public long getAvgTimeMicros();
+
+ /**
+ * Return the average number of bean loaded per query.
+ *
+ * This excludes background fetching.
+ *
+ */
+ public long getAvgLoadedBeans();
+
+}
diff --git a/src/main/java/com/avaje/ebean/meta/MetaInfoManager.java b/src/main/java/com/avaje/ebean/meta/MetaInfoManager.java
new file mode 100644
index 000000000..aa3ee1f4c
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/meta/MetaInfoManager.java
@@ -0,0 +1,26 @@
+package com.avaje.ebean.meta;
+
+import java.util.List;
+
+public interface MetaInfoManager {
+
+ /**
+ * Return the MetaBeanInfo for a bean type.
+ */
+ public MetaBeanInfo getMetaBeanInfo(Class> beanClass);
+
+ /**
+ * Return all the MetaBeanInfo.
+ */
+ public List getMetaBeanInfoList();
+
+ /**
+ * Collect and return the query plan statistics for all the beans.
+ *
+ * Note that this excludes the query plan statistics where there has been no
+ * executions (since the last collection with reset).
+ *
+ */
+ public List collectQueryPlanStatistics(boolean reset);
+
+}
diff --git a/src/main/java/com/avaje/ebean/meta/MetaQueryStatistic.java b/src/main/java/com/avaje/ebean/meta/MetaQueryStatistic.java
deleted file mode 100644
index 6f0106536..000000000
--- a/src/main/java/com/avaje/ebean/meta/MetaQueryStatistic.java
+++ /dev/null
@@ -1,172 +0,0 @@
-package com.avaje.ebean.meta;
-
-import java.io.Serializable;
-
-import javax.persistence.Entity;
-
-/**
- * Query execution statistics Meta data.
- */
-@Entity
-public class MetaQueryStatistic implements Serializable {
-
- private static final long serialVersionUID = -8746524372894472583L;
-
- boolean autofetchTuned;
-
- String beanType;
-
- /**
- * The original query plan hash (calculated prior to autofetch tuning).
- */
- int origQueryPlanHash;
-
- /**
- * The final query plan hash (calculated after to autofetch tuning).
- */
- int finalQueryPlanHash;
-
- String sql;
-
- int executionCount;
-
- int totalLoadedBeans;
-
- int totalTimeMicros;
-
- long collectionStart;
-
- long lastQueryTime;
-
- int avgTimeMicros;
-
- int avgLoadedBeans;
-
- public MetaQueryStatistic() {
-
- }
-
- /**
- * Create a MetaQueryStatistic.
- */
- public MetaQueryStatistic(boolean autofetchTuned, String beanType, int plan, String sql,
- int executionCount, int totalLoadedBeans, int totalTimeMicros, long collectionStart,
- long lastQueryTime) {
-
- this.autofetchTuned = autofetchTuned;
- this.beanType = beanType;
- this.finalQueryPlanHash = plan;
- this.sql = sql;
- this.executionCount = executionCount;
- this.totalLoadedBeans = totalLoadedBeans;
- this.totalTimeMicros = totalTimeMicros;
- this.collectionStart = collectionStart;
-
- this.lastQueryTime = lastQueryTime;
- this.avgTimeMicros = executionCount == 0 ? 0 : totalTimeMicros / executionCount;
- this.avgLoadedBeans = executionCount == 0 ? 0 : totalLoadedBeans / executionCount;
- }
-
- public String toString() {
- return "type=" + beanType + " tuned:" + autofetchTuned + " origHash=" + origQueryPlanHash
- + " count=" + executionCount + " avgMicros=" + getAvgTimeMicros();
- }
-
- /**
- * Return true if this query plan was built for Autofetch tuned queries.
- */
- public boolean isAutofetchTuned() {
- return autofetchTuned;
- }
-
- /**
- * Return the original query plan hash (calculated prior to autofetch tuning).
- *
- * This will return 0 if there is no autofetch profiling or tuning on this
- * query.
- *
- */
- public int getOrigQueryPlanHash() {
- return origQueryPlanHash;
- }
-
- /**
- * Return the queryPlanHash value. This is unique for a given query plan.
- */
- public int getFinalQueryPlanHash() {
- return finalQueryPlanHash;
- }
-
- /**
- * Return the bean type.
- */
- public String getBeanType() {
- return beanType;
- }
-
- /**
- * Return the sql executed.
- */
- public String getSql() {
- return sql;
- }
-
- /**
- * Return the total number of queries executed.
- */
- public int getExecutionCount() {
- return executionCount;
- }
-
- /**
- * Return the total number of beans loaded by the queries.
- *
- * This excludes background fetching.
- *
- */
- public int getTotalLoadedBeans() {
- return totalLoadedBeans;
- }
-
- /**
- * Return the number of times this query was executed.
- */
- public int getTotalTimeMicros() {
- return totalTimeMicros;
- }
-
- /**
- * Return the time collection started.
- */
- public long getCollectionStart() {
- return collectionStart;
- }
-
- /**
- * Return the time of the last query executed using this plan.
- */
- public long getLastQueryTime() {
- return lastQueryTime;
- }
-
- /**
- * Return the average query execution time in microseconds.
- *
- * This excludes background fetching.
- *
- */
- public int getAvgTimeMicros() {
- return avgTimeMicros;
- }
-
- /**
- * Return the average number of bean loaded per query.
- *
- * This excludes background fetching.
- *
- */
- public int getAvgLoadedBeans() {
- return avgLoadedBeans;
- }
-
-}
diff --git a/src/main/java/com/avaje/ebean/meta/package-info.java b/src/main/java/com/avaje/ebean/meta/package-info.java
new file mode 100644
index 000000000..b637cdbc8
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/meta/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Meta data that can be retrieved for the EbeanServer.
+ */
+package com.avaje.ebean.meta;
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebean/meta/package.html b/src/main/java/com/avaje/ebean/meta/package.html
deleted file mode 100644
index 81281f219..000000000
--- a/src/main/java/com/avaje/ebean/meta/package.html
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-Entity Beans for getting "Meta" data from Ebean
-
-
-Entity Beans for getting "Meta" data from Ebean
-
-You can query these entity beans to get "meta" data from Ebean.
-This includes things like query execution statistics.
-
-
-// fetch the meta data that controls autoFetch query tuning
-Query query = Ebean.createQuery(MetaAutoFetchTunedFetch.class);
-List list = query.findList();
-
-
-
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/api/BindParams.java b/src/main/java/com/avaje/ebeaninternal/api/BindParams.java
index 2b68aa947..f5342779b 100644
--- a/src/main/java/com/avaje/ebeaninternal/api/BindParams.java
+++ b/src/main/java/com/avaje/ebeaninternal/api/BindParams.java
@@ -3,8 +3,7 @@ package com.avaje.ebeaninternal.api;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -14,22 +13,16 @@ import com.avaje.ebeaninternal.server.querydefn.NaturalKeyBindParam;
/**
* Parameters used for binding to a statement.
*
- * Used by FindByNativeSql and UpdateSql to support ordered and named
- * parameters. Note that you can use either ordered OR named parameters.
+ * Supports ordered or named parameters.
*
*/
public class BindParams implements Serializable {
private static final long serialVersionUID = 4541081933302086285L;
- private ArrayList positionedParameters = new ArrayList();
+ private List positionedParameters = new ArrayList();
- private HashMap namedParameters = new HashMap();
-
- /**
- * Need to create a hash when binding collection values (for in clauses).
- */
- private int queryPlanHash = 1;
+ private Map namedParameters = new LinkedHashMap();
/**
* This is the sql. For named parameters this is the sql after the named
@@ -38,6 +31,39 @@ public class BindParams implements Serializable {
*/
private String preparedSql;
+ public BindParams() {
+ }
+
+ public int queryBindHash() {
+ int hc = namedParameters.hashCode();
+ for (int i = 0; i < positionedParameters.size(); i++) {
+ hc = hc * 31 + positionedParameters.get(i).hashCode();
+ }
+ return hc;
+ }
+
+ /**
+ * Return the hash that should be included with the query plan.
+ *
+ * This is to handle binding collections to in clauses. The number of values
+ * in the collection effects the query (number of bind values) and so must be
+ * taken into account when calculating the query hash.
+ *
+ */
+ public int getQueryPlanHash() {
+ int hc = 31;
+ for (Param param : positionedParameters) {
+ hc = hc * 31 + param.queryBindCount();
+ }
+
+ for (Map.Entry entry : namedParameters.entrySet()) {
+ hc = hc * 31 + entry.getKey().hashCode();
+ hc = hc * 31 + entry.getValue().queryBindCount();
+ }
+
+ return hc;
+ }
+
/**
* Return a deep copy of the BindParams.
*/
@@ -46,45 +72,12 @@ public class BindParams implements Serializable {
for (Param p : positionedParameters) {
copy.positionedParameters.add(p.copy());
}
- Iterator> it = namedParameters.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- copy.namedParameters.put(entry.getKey(), entry.getValue().copy());
+ for (Entry entry : namedParameters.entrySet()) {
+ copy.namedParameters.put(entry.getKey(), entry.getValue().copy());
}
return copy;
}
- public int queryBindHash() {
- int hc = namedParameters.hashCode();
- for (int i = 0; i < positionedParameters.size(); i++) {
- hc = hc * 31 + positionedParameters.get(i).hashCode();
- }
- return hc;
- }
-
- public int hashCode() {
- int hc = getClass().hashCode();
- hc = hc * 31 + namedParameters.hashCode();
- for (int i = 0; i < positionedParameters.size(); i++) {
- hc = hc * 31 + positionedParameters.get(i).hashCode();
- }
- hc = hc * 31 + (preparedSql == null ? 0 : preparedSql.hashCode());
- return hc;
- }
-
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
- if (o == this) {
- return true;
- }
- if (o instanceof BindParams) {
- return hashCode() == o.hashCode();
- }
- return false;
- }
-
/**
* Return true if there are no bind parameters.
*/
@@ -131,10 +124,8 @@ public class BindParams implements Serializable {
* Set an In Out parameter using position.
*/
public void setParameter(int position, Object value, int outType) {
-
- addToQueryPlanHash(String.valueOf(position), value);
- Param p = getParam(position);
+ Param p = getParam(position);
p.setInValue(value);
p.setOutType(outType);
}
@@ -144,10 +135,8 @@ public class BindParams implements Serializable {
* must use setNullParameter.
*/
public void setParameter(int position, Object value) {
-
- addToQueryPlanHash(String.valueOf(position), value);
- Param p = getParam(position);
+ Param p = getParam(position);
p.setInValue(value);
}
@@ -182,10 +171,8 @@ public class BindParams implements Serializable {
* Set a named In Out parameter.
*/
public void setParameter(String name, Object value, int outType) {
-
- addToQueryPlanHash(name, value);
- Param p = getParam(name);
+ Param p = getParam(name);
p.setInValue(value);
p.setOutType(outType);
}
@@ -203,48 +190,22 @@ public class BindParams implements Serializable {
*/
public Param setParameter(String name, Object value) {
- addToQueryPlanHash(name, value);
-
- Param p = getParam(name);
+ Param p = getParam(name);
p.setInValue(value);
return p;
}
- /**
- * For binding collections calculate a hash to be used for the query plan.
- */
- private void addToQueryPlanHash(String name, Object value){
- if (value != null){
- if (value instanceof Collection>){
- queryPlanHash = queryPlanHash * 31 + name.hashCode();
- queryPlanHash = queryPlanHash * 31 + ((Collection>)value).size();
- }
- }
- }
-
- /**
- * Return the hash that should be included with the query plan.
- *
- * This is to handle binding collections to in clauses. The number
- * of values in the collection effects the query (number of bind values)
- * and so must be taken into account when calculating the query hash.
- *
- */
- public int getQueryPlanHash() {
- return queryPlanHash;
- }
-
- /**
- * Set an encryption key as a bind value.
- *
- * Needs special treatment as the value should not be included in a log.
- *
- */
- public Param setEncryptionKey(String name, Object value) {
- Param p = getParam(name);
- p.setEncryptionKey(value);
- return p;
- }
+ /**
+ * Set an encryption key as a bind value.
+ *
+ * Needs special treatment as the value should not be included in a log.
+ *
+ */
+ public Param setEncryptionKey(String name, Object value) {
+ Param p = getParam(name);
+ p.setEncryptionKey(value);
+ return p;
+ }
/**
* Register the named parameter as an Out parameter.
@@ -300,9 +261,9 @@ public class BindParams implements Serializable {
*/
public static final class OrderedList {
- final List paramList;
+ private final List paramList;
- final StringBuilder preparedSql;
+ private final StringBuilder preparedSql;
public OrderedList() {
this(new ArrayList());
@@ -373,6 +334,16 @@ public class BindParams implements Serializable {
public Param() {
}
+ public int queryBindCount() {
+ if (inValue == null) {
+ return 0;
+ }
+ if (inValue instanceof Collection>){
+ return ((Collection>)inValue).size();
+ }
+ return 1;
+ }
+
/**
* Create a deep copy of the Param.
*/
@@ -448,14 +419,14 @@ public class BindParams implements Serializable {
this.isInParam = true;
}
- /**
- * Set an encryption key (which can not be logged).
- */
- public void setEncryptionKey(Object in) {
- this.inValue = in;
- this.isInParam = true;
- this.encryptionKey = true;
- }
+ /**
+ * Set an encryption key (which can not be logged).
+ */
+ public void setEncryptionKey(Object in) {
+ this.inValue = in;
+ this.isInParam = true;
+ this.encryptionKey = true;
+ }
/**
* Specify that the In parameter is NULL and the specific type that it
@@ -506,12 +477,12 @@ public class BindParams implements Serializable {
this.textLocation = textLocation;
}
- /**
- * If true do not include this value in a transaction log.
- */
- public boolean isEncryptionKey() {
- return encryptionKey;
- }
-
+ /**
+ * If true do not include this value in a transaction log.
+ */
+ public boolean isEncryptionKey() {
+ return encryptionKey;
+ }
+
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManager.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManager.java
index f2e8cb37f..9cc6836e5 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManager.java
@@ -224,7 +224,7 @@ public interface AutoFetchManager extends NodeUsageListener {
* @param micros
* the query executing time in microseconds
*/
- public void collectQueryInfo(ObjectGraphNode node, int beans, int micros);
+ public void collectQueryInfo(ObjectGraphNode node, long beans, long micros);
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManagerFactory.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManagerFactory.java
index 7c110f5de..8abd76935 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManagerFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/AutoFetchManagerFactory.java
@@ -61,6 +61,7 @@ public class AutoFetchManagerFactory {
FileInputStream fi = new FileInputStream(autoFetchFile);
ObjectInputStream ois = new ObjectInputStream(fi);
AutoFetchManager profListener = (AutoFetchManager) ois.readObject();
+ ois.close();
logger.info("AutoFetch deserialized from file ["+autoFetchFile.getAbsolutePath()+"]");
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
index 11ee8e651..4e5ec7376 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/DefaultAutoFetchManager.java
@@ -527,7 +527,7 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
* query in which case the parentNode will be null, or a lazy loading query
* resulting from traversal of the object graph.
*/
- public void collectQueryInfo(ObjectGraphNode node, int beans, int micros) {
+ public void collectQueryInfo(ObjectGraphNode node, long beans, long micros) {
if (node != null){
ObjectGraphOrigin origin = node.getOriginQueryPoint();
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/Statistics.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/Statistics.java
index 7aa771f6d..95b8add62 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/Statistics.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/Statistics.java
@@ -127,7 +127,7 @@ public class Statistics implements Serializable {
}
- public void collectQueryInfo(ObjectGraphNode node, int beansLoaded, int micros) {
+ public void collectQueryInfo(ObjectGraphNode node, long beansLoaded, long micros) {
synchronized (monitor) {
String key = node.getPath();
diff --git a/src/main/java/com/avaje/ebeaninternal/server/autofetch/StatisticsQuery.java b/src/main/java/com/avaje/ebeaninternal/server/autofetch/StatisticsQuery.java
index d0b4bbd03..dcf9e335c 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/autofetch/StatisticsQuery.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/autofetch/StatisticsQuery.java
@@ -13,11 +13,11 @@ public class StatisticsQuery implements Serializable {
private final String path;
- private int exeCount;
+ private long exeCount;
- private int totalBeanLoaded;
+ private long totalBeanLoaded;
- private int totalMicros;
+ private long totalMicros;
public StatisticsQuery(String path){
this.path = path;
@@ -27,7 +27,7 @@ public class StatisticsQuery implements Serializable {
return new QueryStats(path, exeCount, totalBeanLoaded, totalMicros);
}
- public void add(int beansLoaded, int micros) {
+ public void add(long beansLoaded, long micros) {
exeCount++;
totalBeanLoaded += beansLoaded;
totalMicros += micros;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchStatisticFinder.java b/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchStatisticFinder.java
deleted file mode 100644
index 6bf429f7d..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchStatisticFinder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package com.avaje.ebeaninternal.server.bean;
-
-import java.util.Iterator;
-
-import javax.persistence.PersistenceException;
-
-import com.avaje.ebean.bean.BeanCollection;
-import com.avaje.ebean.common.BeanList;
-import com.avaje.ebean.event.BeanFinder;
-import com.avaje.ebean.event.BeanQueryRequest;
-import com.avaje.ebean.meta.MetaAutoFetchStatistic;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.api.SpiQuery;
-import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
-import com.avaje.ebeaninternal.server.autofetch.Statistics;
-
-/**
- * Bean Finder for MetaAutoFetchStatistic.
- *
- * This gets the meta data from the AutoFetchManager and creates a copy of that
- * data to give back to the caller in the form of MetaAutoFetchStatistic beans.
- *
- */
-public class BFAutoFetchStatisticFinder implements BeanFinder {
-
-
- public MetaAutoFetchStatistic find(BeanQueryRequest request) {
- SpiQuery query = (SpiQuery)request.getQuery();
- try {
- String queryPointKey = (String) query.getId();
-
- SpiEbeanServer server = (SpiEbeanServer) request.getEbeanServer();
- AutoFetchManager manager = server.getAutoFetchManager();
-
- Statistics stats = manager.getStatistics(queryPointKey);
- if (stats != null) {
- return stats.createPublicMeta();
- } else {
- return null;
- }
-
- } catch (Exception e) {
- throw new PersistenceException(e);
- }
- }
-
- /**
- * Only returns Lists at this stage.
- */
- public BeanCollection findMany(BeanQueryRequest request) {
-
- SpiQuery.Type queryType = ((SpiQuery>)request.getQuery()).getType();
- if (!queryType.equals(SpiQuery.Type.LIST)) {
- throw new PersistenceException("Only findList() supported at this stage.");
- }
-
- SpiEbeanServer server = (SpiEbeanServer) request.getEbeanServer();
- AutoFetchManager manager = server.getAutoFetchManager();
-
- BeanList list = new BeanList();
-
- Iterator it = manager.iterateStatistics();
- while (it.hasNext()) {
- Statistics stats = it.next();
- // create a copy for public use
- list.add(stats.createPublicMeta());
- }
-
- String orderBy = request.getQuery().order().toStringFormat();
- if (orderBy == null){
- orderBy = "beanType";
- }
- server.sort(list, orderBy);
-
-
- return list;
- }
-
-}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchTunedFetchFinder.java b/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchTunedFetchFinder.java
deleted file mode 100644
index 598512b09..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/bean/BFAutoFetchTunedFetchFinder.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.avaje.ebeaninternal.server.bean;
-
-import java.util.Iterator;
-
-import javax.persistence.PersistenceException;
-
-import com.avaje.ebean.bean.BeanCollection;
-import com.avaje.ebean.common.BeanList;
-import com.avaje.ebean.event.BeanFinder;
-import com.avaje.ebean.event.BeanQueryRequest;
-import com.avaje.ebean.meta.MetaAutoFetchTunedQueryInfo;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.api.SpiQuery;
-import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
-import com.avaje.ebeaninternal.server.autofetch.TunedQueryInfo;
-
-/**
- * BeanFinder for MetaAutoFetchTunedFetch.
- */
-public class BFAutoFetchTunedFetchFinder implements BeanFinder {
-
-
- public MetaAutoFetchTunedQueryInfo find(BeanQueryRequest request) {
-
- SpiQuery> query = (SpiQuery>)request.getQuery();
- try {
- String queryPointKey = (String)query.getId();
-
- SpiEbeanServer server = (SpiEbeanServer) request.getEbeanServer();
- AutoFetchManager manager = server.getAutoFetchManager();
-
- TunedQueryInfo tunedFetch = manager.getTunedQueryInfo(queryPointKey);
- if (tunedFetch != null){
- return tunedFetch.createPublicMeta();
- } else {
- return null;
- }
-
- } catch (Exception e){
- throw new PersistenceException(e);
- }
- }
-
- /**
- * Only returns Lists at this stage.
- */
- public BeanCollection findMany(BeanQueryRequest request) {
-
- SpiQuery.Type queryType = ((SpiQuery>)request.getQuery()).getType();
- if (!queryType.equals(SpiQuery.Type.LIST)){
- throw new PersistenceException("Only findList() supported at this stage.");
- }
-
- SpiEbeanServer server = (SpiEbeanServer) request.getEbeanServer();
- AutoFetchManager manager = server.getAutoFetchManager();
-
- BeanList list = new BeanList();
-
- Iterator it = manager.iterateTunedQueryInfo();
- while (it.hasNext()) {
- TunedQueryInfo tunedFetch = it.next();
- // create a copy for public use
- list.add(tunedFetch.createPublicMeta());
- }
-
- String orderBy = request.getQuery().order().toStringFormat();
- if (orderBy == null){
- orderBy = "beanType, origQueryPlanHash";
- }
- server.sort(list, orderBy);
-
-
- return list;
- }
-
-}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/bean/BFQueryStatisticFinder.java b/src/main/java/com/avaje/ebeaninternal/server/bean/BFQueryStatisticFinder.java
deleted file mode 100644
index b87df5eb7..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/bean/BFQueryStatisticFinder.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package com.avaje.ebeaninternal.server.bean;
-
-import java.util.Iterator;
-import java.util.List;
-
-import javax.persistence.PersistenceException;
-
-import com.avaje.ebean.bean.BeanCollection;
-import com.avaje.ebean.common.BeanList;
-import com.avaje.ebean.event.BeanFinder;
-import com.avaje.ebean.event.BeanQueryRequest;
-import com.avaje.ebean.meta.MetaQueryStatistic;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.api.SpiQuery;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-import com.avaje.ebeaninternal.server.query.CQueryPlan;
-
-/**
- * BeanFinder for MetaQueryStatistic.
- */
-public class BFQueryStatisticFinder implements BeanFinder {
-
-
- public MetaQueryStatistic find(BeanQueryRequest request) {
- throw new RuntimeException("Not Supported yet");
- }
-
- /**
- * Only returns Lists at this stage.
- */
- public BeanCollection findMany(BeanQueryRequest request) {
-
- SpiQuery.Type queryType = ((SpiQuery>)request.getQuery()).getType();
- if (!queryType.equals(SpiQuery.Type.LIST)){
- throw new PersistenceException("Only findList() supported at this stage.");
- }
-
- BeanList list = new BeanList();
-
- SpiEbeanServer server = (SpiEbeanServer) request.getEbeanServer();
- build(list, server);
-
- String orderBy = request.getQuery().order().toStringFormat();
- if (orderBy == null){
- orderBy = "beanType, origQueryPlanHash, autofetchTuned";
- }
- server.sort(list, orderBy);
-
- return list;
- }
-
- private void build(List list, SpiEbeanServer server) {
-
- for (BeanDescriptor> desc : server.getBeanDescriptors()) {
- desc.clearQueryStatistics();
- build(list, desc);
- }
- }
-
- private void build(List list, BeanDescriptor> desc) {
-
- Iterator it = desc.queryPlans();
- while (it.hasNext()) {
- CQueryPlan queryPlan = (CQueryPlan) it.next();
- list.add(queryPlan.createMetaQueryStatistic(desc.getFullName()));
- }
- }
-
-}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/bean/package.html b/src/main/java/com/avaje/ebeaninternal/server/bean/package.html
deleted file mode 100644
index f77109f52..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/bean/package.html
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-BeanFinders, BeanControllers etc for "meta" beans
-
-
-BeanFinders, BeanControllers etc for "meta" beans
-
-
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultMetaInfoManager.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultMetaInfoManager.java
new file mode 100644
index 000000000..5facae4a2
--- /dev/null
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultMetaInfoManager.java
@@ -0,0 +1,44 @@
+package com.avaje.ebeaninternal.server.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.avaje.ebean.meta.MetaBeanInfo;
+import com.avaje.ebean.meta.MetaBeanQueryPlanStatistic;
+import com.avaje.ebean.meta.MetaInfoManager;
+
+/**
+ * DefaultServer based implementation of MetaInfoManager.
+ */
+public class DefaultMetaInfoManager implements MetaInfoManager {
+
+ private final DefaultServer server;
+
+ public DefaultMetaInfoManager(DefaultServer server) {
+ this.server = server;
+ }
+
+ @Override
+ public MetaBeanInfo getMetaBeanInfo(Class> beanClass) {
+ return server.getBeanDescriptor(beanClass);
+ }
+
+ @Override
+ public List getMetaBeanInfoList() {
+
+ return new ArrayList(server.getBeanDescriptors());
+ }
+
+ @Override
+ public List collectQueryPlanStatistics(boolean reset) {
+
+ List list = new ArrayList();
+
+ for (MetaBeanInfo metaBeanInfo : getMetaBeanInfoList()) {
+ list.addAll(metaBeanInfo.collectQueryPlanStatistics(reset));
+ }
+
+ return list;
+ }
+
+}
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 d4db15306..45f2d1eba 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
@@ -57,6 +57,8 @@ import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanQueryAdapter;
+import com.avaje.ebean.meta.MetaBeanInfo;
+import com.avaje.ebean.meta.MetaInfoManager;
import com.avaje.ebean.text.csv.CsvReader;
import com.avaje.ebean.text.json.JsonContext;
import com.avaje.ebean.text.json.JsonElement;
@@ -168,6 +170,8 @@ public final class DefaultServer implements SpiEbeanServer {
private final JsonContext jsonContext;
+ private final MetaInfoManager metaInfoManager;
+
/**
* The MBean name used to register Ebean.
*/
@@ -208,6 +212,7 @@ public final class DefaultServer implements SpiEbeanServer {
*/
public DefaultServer(InternalConfiguration config, ServerCacheManager cache) {
+ this.metaInfoManager = new DefaultMetaInfoManager(this);
this.serverCacheManager = cache;
this.pstmtBatch = config.getPstmtBatch();
this.databasePlatform = config.getDatabasePlatform();
@@ -298,6 +303,11 @@ public final class DefaultServer implements SpiEbeanServer {
public DatabasePlatform getDatabasePlatform() {
return databasePlatform;
}
+
+ @Override
+ public MetaInfoManager getMetaInfoManager() {
+ return metaInfoManager;
+ }
public BackgroundExecutor getBackgroundExecutor() {
return backgroundExecutor;
@@ -1927,6 +1937,13 @@ public final class DefaultServer implements SpiEbeanServer {
return beanDescriptorManager.getBeanDescriptorList();
}
+ public List getMetaBeanInfoList() {
+
+ List list = new ArrayList();
+ list.addAll(getBeanDescriptors());
+ return list;
+ }
+
public void register(BeanPersistController c) {
List> list = beanDescriptorManager.getBeanDescriptorList();
for (int i = 0; i < list.size(); i++) {
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 b50c3610d..754876e2f 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/OrmQueryRequest.java
@@ -389,4 +389,8 @@ public final class OrmQueryRequest extends BeanRequest implements BeanQueryRe
}
}
+ public void flushPersistenceContextOnIterate() {
+ beanDescriptor.flushPersistenceContextOnIterate(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 f1cec100c..c3c873b1e 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
@@ -15,6 +15,9 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.PersistenceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import com.avaje.ebean.Query;
import com.avaje.ebean.Query.UseIndex;
import com.avaje.ebean.SqlUpdate;
@@ -33,6 +36,8 @@ import com.avaje.ebean.event.BeanFinder;
import com.avaje.ebean.event.BeanPersistController;
import com.avaje.ebean.event.BeanPersistListener;
import com.avaje.ebean.event.BeanQueryAdapter;
+import com.avaje.ebean.meta.MetaBeanInfo;
+import com.avaje.ebean.meta.MetaBeanQueryPlanStatistic;
import com.avaje.ebean.text.TextException;
import com.avaje.ebean.text.json.JsonWriteBeanVisitor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
@@ -59,6 +64,7 @@ import com.avaje.ebeaninternal.server.el.ElPropertyDeploy;
import com.avaje.ebeaninternal.server.el.ElPropertyValue;
import com.avaje.ebeaninternal.server.persist.DmlUtil;
import com.avaje.ebeaninternal.server.query.CQueryPlan;
+import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import com.avaje.ebeaninternal.server.query.SplitName;
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
import com.avaje.ebeaninternal.server.reflect.BeanReflect;
@@ -72,13 +78,10 @@ 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.
*/
-public class BeanDescriptor {
+public class BeanDescriptor implements MetaBeanInfo {
private static final Logger logger = LoggerFactory.getLogger(BeanDescriptor.class);
@@ -1149,6 +1152,27 @@ public class BeanDescriptor {
return new DeployUpdateParser(this).parse(ormUpdateStatement);
}
+ @Override
+ public List collectQueryPlanStatistics(boolean reset) {
+ return collectQueryPlanStatisticsInternal(reset, false);
+ }
+
+ @Override
+ public List collectAllQueryPlanStatistics(boolean reset) {
+ return collectQueryPlanStatisticsInternal(reset, false);
+ }
+
+ public List collectQueryPlanStatisticsInternal(boolean reset, boolean collectAll) {
+ List list = new ArrayList(queryPlanCache.size());
+ for (CQueryPlan queryPlan : queryPlanCache.values()) {
+ Snapshot snapshot = queryPlan.getSnapshot(reset);
+ if (collectAll || snapshot.getExecutionCount() > 0) {
+ list.add(snapshot);
+ }
+ }
+ return list;
+ }
+
/**
* Reset the statistics on all the query plans.
*/
@@ -2445,5 +2469,13 @@ public class BeanDescriptor {
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/loadcontext/DLoadBeanContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
index cd6d7264b..347f1a251 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
@@ -126,6 +126,11 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
return context.serverName;
}
+ @Override
+ public String getFullPath() {
+ return context.fullPath;
+ }
+
@Override
public BeanDescriptor> getBeanDescriptor() {
return context.desc;
@@ -171,10 +176,6 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
context.desc.getEbeanServer().loadBean(req);
}
- @Override
- public String getFullPath() {
- return context.fullPath;
- }
}
}
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 40ab36f72..cdbe59e29 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQuery.java
@@ -6,6 +6,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import javax.persistence.PersistenceException;
@@ -39,6 +40,7 @@ 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;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -204,8 +206,6 @@ public class CQuery implements DbReadContext, CancelableQuery {
private final CQueryPlan queryPlan;
- private long startNano;
-
private final Mode queryMode;
private final boolean autoFetchProfiling;
@@ -213,14 +213,17 @@ public class CQuery implements DbReadContext, CancelableQuery {
private final ObjectGraphNode autoFetchParentNode;
private final AutoFetchManager autoFetchManager;
+
private final WeakReference autoFetchManagerRef;
- private int executionTimeMicros;
-
private final Boolean readOnly;
private final SpiExpressionList> filterMany;
+ private long startNano;
+
+ private long executionTimeMicros;
+
/**
* Create the Sql select based on the request.
*/
@@ -520,7 +523,7 @@ public class CQuery implements DbReadContext, CancelableQuery {
}
}
- public int getQueryExecutionTimeMicros() {
+ public long getQueryExecutionTimeMicros() {
return executionTimeMicros;
}
@@ -638,7 +641,7 @@ public class CQuery implements DbReadContext, CancelableQuery {
protected void updateExecutionStatistics() {
try {
long exeNano = System.nanoTime() - startNano;
- executionTimeMicros = (int) exeNano / 1000;
+ executionTimeMicros = TimeUnit.NANOSECONDS.toMicros(exeNano);
if (autoFetchProfiling) {
autoFetchManager
@@ -674,7 +677,7 @@ public class CQuery implements DbReadContext, CancelableQuery {
}
protected boolean hasNextBean(boolean inForeground) throws SQLException {
-
+
if (!readBeanInternal(inForeground)) {
return false;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
index 9f6241cb8..d968faf96 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryBuilder.java
@@ -115,7 +115,7 @@ public class CQueryBuilder implements Constants {
String sql = s.getSql();
// cache the query plan
- queryPlan = new CQueryPlan(sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
+ queryPlan = new CQueryPlan(query.getBeanType(), sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryFetchIds(request, predicates, sql, backgroundExecutor);
@@ -171,7 +171,7 @@ public class CQueryBuilder implements Constants {
}
// cache the query plan
- queryPlan = new CQueryPlan(sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
+ queryPlan = new CQueryPlan(query.getBeanType(), sql, sqlTree, false, s.isIncludesRowNumberColumn(), predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryRowCount(request, predicates, sql);
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java
index ab2f3e2eb..93dcc678d 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorSimple.java
@@ -9,38 +9,37 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
/**
* QueryIterator that does not require a buffer for secondary queries.
- *
- * @author rbygrave
*/
class CQueryIteratorSimple implements QueryIterator {
- private final CQuery cquery;
- private final OrmQueryRequest request;
+ private final CQuery cquery;
+ private final OrmQueryRequest request;
- CQueryIteratorSimple(CQuery cquery, OrmQueryRequest request){
- this.cquery = cquery;
- this.request = request;
- }
-
- public boolean hasNext() {
- try {
- return cquery.hasNextBean(true);
- } catch (SQLException e){
- throw cquery.createPersistenceException(e);
- }
- }
+ CQueryIteratorSimple(CQuery cquery, OrmQueryRequest request) {
+ this.cquery = cquery;
+ this.request = request;
+ }
- public T next() {
- return cquery.getLoadedBean();
+ public boolean hasNext() {
+ try {
+ request.flushPersistenceContextOnIterate();
+ return cquery.hasNextBean(true);
+ } catch (SQLException e) {
+ throw cquery.createPersistenceException(e);
}
+ }
- public void close() {
- cquery.updateExecutionStatistics();
- cquery.close();
- request.endTransIfRequired();
- }
+ public T next() {
+ return cquery.getLoadedBean();
+ }
- public void remove() {
- throw new PersistenceException("Remove not allowed");
- }
+ public void close() {
+ cquery.updateExecutionStatistics();
+ cquery.close();
+ request.endTransIfRequired();
+ }
+
+ public void remove() {
+ throw new PersistenceException("Remove not allowed");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java
index 2df0fcd14..429766d85 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryIteratorWithBuffer.java
@@ -10,58 +10,58 @@ import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
/**
* A QueryIterator that uses a buffer to execute secondary queries periodically.
- *
- * @author rbygrave
*/
class CQueryIteratorWithBuffer implements QueryIterator {
- private final CQuery cquery;
- private final int bufferSize;
- private final OrmQueryRequest request;
- private final ArrayList buffer;
+ private final CQuery cquery;
+ private final int bufferSize;
+ private final OrmQueryRequest request;
+ private final ArrayList buffer;
- private boolean moreToLoad = true;
+ private boolean moreToLoad = true;
- CQueryIteratorWithBuffer(CQuery cquery, OrmQueryRequest request, int bufferSize) {
- this.cquery = cquery;
- this.request = request;
- this.bufferSize = bufferSize;
- this.buffer = new ArrayList(bufferSize);
- }
+ CQueryIteratorWithBuffer(CQuery cquery, OrmQueryRequest request, int bufferSize) {
+ this.cquery = cquery;
+ this.request = request;
+ this.bufferSize = bufferSize;
+ this.buffer = new ArrayList(bufferSize);
+ }
- public boolean hasNext() {
- try {
- if (buffer.isEmpty() && moreToLoad) {
- // load buffer
- int i = -1;
- while (moreToLoad && ++i < bufferSize) {
- if (cquery.hasNextBean(true)) {
- buffer.add(cquery.getLoadedBean());
- } else {
- moreToLoad = false;
- }
- }
- // execute secondary queries
- request.executeSecondaryQueries(bufferSize);
- }
- return !buffer.isEmpty();
+ public boolean hasNext() {
+ try {
+ if (buffer.isEmpty() && moreToLoad) {
+ // load buffer
+ request.flushPersistenceContextOnIterate();
- } catch (SQLException e) {
- throw cquery.createPersistenceException(e);
+ int i = -1;
+ while (moreToLoad && ++i < bufferSize) {
+ if (cquery.hasNextBean(true)) {
+ buffer.add(cquery.getLoadedBean());
+ } else {
+ moreToLoad = false;
+ }
}
- }
+ // execute secondary queries
+ request.executeSecondaryQueries(bufferSize);
+ }
+ return !buffer.isEmpty();
- public T next() {
- return buffer.remove(0);
+ } catch (SQLException e) {
+ throw cquery.createPersistenceException(e);
}
+ }
- public void close() {
- cquery.updateExecutionStatistics();
- cquery.close();
- request.endTransIfRequired();
- }
+ public T next() {
+ return buffer.remove(0);
+ }
- public void remove() {
- throw new PersistenceException("Remove not allowed");
- }
+ public void close() {
+ cquery.updateExecutionStatistics();
+ cquery.close();
+ request.endTransIfRequired();
+ }
+
+ public void remove() {
+ throw new PersistenceException("Remove not allowed");
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java
index 161e94cef..0f6380346 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlan.java
@@ -4,9 +4,9 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
-import com.avaje.ebean.meta.MetaQueryStatistic;
import com.avaje.ebeaninternal.server.core.OrmQueryRequest;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
+import com.avaje.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
import com.avaje.ebeaninternal.server.type.DataBind;
import com.avaje.ebeaninternal.server.type.DataReader;
import com.avaje.ebeaninternal.server.type.RsetDataReader;
@@ -51,7 +51,9 @@ public class CQueryPlan {
*/
private final BeanProperty[] encryptedProps;
- private CQueryStats queryStats = new CQueryStats();
+ private final CQueryPlanStats stats;
+
+ private final Class> beanType;
/**
* Create a query plan based on a OrmQueryRequest.
@@ -59,6 +61,8 @@ public class CQueryPlan {
public CQueryPlan(OrmQueryRequest> request, SqlLimitResponse sqlRes, SqlTree sqlTree,
boolean rawSql, String logWhereSql, String luceneQueryDescription) {
+ this.beanType = request.getBeanDescriptor().getBeanType();
+ this.stats = new CQueryPlanStats(this);
this.hash = request.getQueryPlanHash();
this.autofetchTuned = request.getQuery().isAutofetchTuned();
if (sqlRes != null){
@@ -77,9 +81,11 @@ public class CQueryPlan {
/**
* Create a query plan for a raw sql query.
*/
- public CQueryPlan(String sql, SqlTree sqlTree,
+ public CQueryPlan(Class> beanType, String sql, SqlTree sqlTree,
boolean rawSql, boolean rowNumberIncluded, String logWhereSql) {
+ this.beanType = beanType;
+ this.stats = new CQueryPlanStats(this);
this.hash = 0;
this.autofetchTuned = false;
this.sql = sql;
@@ -90,23 +96,27 @@ public class CQueryPlan {
this.encryptedProps = sqlTree.getEncryptedProps();
}
- public boolean isLucene() {
- return false;
+ public String toString() {
+ return beanType+" hash:"+hash;
}
- public DataReader createDataReader(ResultSet rset){
-
- return new RsetDataReader(rset);
- }
+ public Class> getBeanType() {
+ return beanType;
+ }
- public void bindEncryptedProperties(DataBind dataBind) throws SQLException {
- if (encryptedProps != null){
- for (int i = 0; i < encryptedProps.length; i++) {
- String key = encryptedProps[i].getEncryptKey().getStringValue();
- dataBind.setString(key);
- }
- }
- }
+ public DataReader createDataReader(ResultSet rset) {
+
+ return new RsetDataReader(rset);
+ }
+
+ public void bindEncryptedProperties(DataBind dataBind) throws SQLException {
+ if (encryptedProps != null) {
+ for (int i = 0; i < encryptedProps.length; i++) {
+ String key = encryptedProps[i].getEncryptKey().getStringValue();
+ dataBind.setString(key);
+ }
+ }
+ }
public boolean isAutofetchTuned() {
return autofetchTuned;
@@ -140,33 +150,33 @@ public class CQueryPlan {
* Reset the query statistics.
*/
public void resetStatistics() {
- queryStats = new CQueryStats();
+ stats.reset();
}
/**
* Register an execution time against this query plan;
*/
- public void executionTime(int loadedBeanCount, int timeMicros) {
- // Atomic operation
- queryStats = queryStats.add(loadedBeanCount, timeMicros);
+ public void executionTime(long loadedBeanCount, long timeMicros) {
+
+ stats.add(loadedBeanCount, timeMicros);
}
+ public Snapshot getSnapshot(boolean reset) {
+ return stats.getSnapshot(reset);
+ }
+
/**
* Return the current query statistics.
*/
- public CQueryStats getQueryStats() {
- return queryStats;
+ public CQueryPlanStats getQueryStats() {
+ return stats;
}
/**
* Return the time this query plan was last used.
*/
public long getLastQueryTime(){
- return queryStats.getLastQueryTime();
+ return stats.getLastQueryTime();
}
- public MetaQueryStatistic createMetaQueryStatistic(String beanName) {
- return queryStats.createMetaQueryStatistic(beanName, this);
- }
-
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java
new file mode 100644
index 000000000..d492403fe
--- /dev/null
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryPlanStats.java
@@ -0,0 +1,154 @@
+
+package com.avaje.ebeaninternal.server.query;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import com.avaje.ebean.meta.MetaBeanQueryPlanStatistic;
+import com.avaje.ebeaninternal.server.util.LongAdder;
+
+/**
+ * Statistics for a specific query plan that can accumulate.
+ */
+public final class CQueryPlanStats {
+
+ private final CQueryPlan queryPlan;
+
+ private final LongAdder count = new LongAdder();
+
+ private final LongAdder totalTime = new LongAdder();
+
+ private final LongAdder totalBeans = new LongAdder();
+
+ private final AtomicLong maxTime = new AtomicLong();
+
+ private final AtomicLong startTime = new AtomicLong(System.currentTimeMillis());
+
+ private long lastQueryTime;
+
+
+ public CQueryPlanStats(CQueryPlan queryPlan) {
+ this.queryPlan = queryPlan;
+ }
+
+ public void add(long loadedBeanCount, long timeMicros) {
+ count.increment();
+ totalBeans.add(loadedBeanCount);
+ totalTime.add(timeMicros);
+ if (timeMicros > maxTime.get()) {
+ // effectively a high water mark
+ maxTime.set(timeMicros);
+ }
+ lastQueryTime = System.currentTimeMillis();
+ }
+
+ public void reset() {
+ count.reset();
+ totalBeans.reset();
+ totalTime.reset();
+ maxTime.set(0);
+ startTime.set(System.currentTimeMillis());
+ }
+
+ public long getLastQueryTime() {
+ return lastQueryTime;
+ }
+
+ public Snapshot getSnapshot(boolean reset) {
+ // not guaranteed to be consistent - time gaps between getting each value
+ if (reset) {
+ return new Snapshot(queryPlan, count.sumThenReset(), totalTime.sumThenReset(), totalBeans.sumThenReset(), maxTime.getAndSet(0), startTime.getAndSet(System.currentTimeMillis()), lastQueryTime);
+ }
+ return new Snapshot(queryPlan, count.sum(), totalTime.sum(), totalBeans.sum(), maxTime.get(), startTime.get(), lastQueryTime);
+ }
+
+ /**
+ * A snapshot of the current statistics for a query plan.
+ */
+ public static class Snapshot implements MetaBeanQueryPlanStatistic {
+
+ private final CQueryPlan queryPlan;
+ private final long count;
+ private final long totalTime;
+ private final long totalBeans;
+ private final long maxTime;
+ private final long startTime;
+ private final long lastQueryTime;
+
+ public Snapshot(CQueryPlan queryPlan, long count, long totalTime, long totalBeans, long maxTime, long startTime, long lastQueryTime) {
+ super();
+ this.queryPlan = queryPlan;
+ this.count = count;
+ this.totalTime = totalTime;
+ this.totalBeans = totalBeans;
+ this.maxTime = maxTime;
+ this.startTime = startTime;
+ this.lastQueryTime = lastQueryTime;
+ }
+
+ public String toString() {
+ return queryPlan+" count:"+count+" time:"+totalTime+" maxTime:"+maxTime+" beans:"+totalBeans+" start:"+startTime+" lastQuery:"+lastQueryTime;
+ }
+
+ @Override
+ public Class> getBeanType() {
+ return queryPlan.getBeanType();
+ }
+
+ @Override
+ public long getExecutionCount() {
+ return count;
+ }
+
+ @Override
+ public long getTotalTimeMicros() {
+ return totalTime;
+ }
+
+ @Override
+ public long getTotalLoadedBeans() {
+ return totalBeans;
+ }
+
+ @Override
+ public long getMaxTimeMicros() {
+ return maxTime;
+ }
+
+ @Override
+ public long getCollectionStart() {
+ return startTime;
+ }
+
+ @Override
+ public long getLastQueryTime() {
+ return lastQueryTime;
+ }
+
+ @Override
+ public boolean isAutofetchTuned() {
+ return queryPlan.isAutofetchTuned();
+ }
+
+
+ @Override
+ public int getQueryPlanHash() {
+ return queryPlan.getHash();
+ }
+
+ @Override
+ public String getSql() {
+ return queryPlan.getSql();
+ }
+
+ @Override
+ public long getAvgTimeMicros() {
+ return count < 1 ? 0 : totalTime / count;
+ }
+
+ @Override
+ public long getAvgLoadedBeans() {
+ return count < 1 ? 0 : totalBeans / count;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryStats.java b/src/main/java/com/avaje/ebeaninternal/server/query/CQueryStats.java
deleted file mode 100644
index 616f62b5f..000000000
--- a/src/main/java/com/avaje/ebeaninternal/server/query/CQueryStats.java
+++ /dev/null
@@ -1,77 +0,0 @@
-
-package com.avaje.ebeaninternal.server.query;
-
-import com.avaje.ebean.meta.MetaQueryStatistic;
-
-/**
- * Statistics for query plan that can accumulate.
- */
-public final class CQueryStats {
-
- private final int count;
-
- private final int totalLoadedBeanCount;
-
- private final int totalTimeMicros;
-
- private final long startCollecting;
-
- private final long lastQueryTime;
-
- public CQueryStats() {
- count = 0;
- totalLoadedBeanCount = 0;
- totalTimeMicros = 0;
- startCollecting = System.currentTimeMillis();
- lastQueryTime = 0;
- }
-
- /**
- * Accumulate/Increment the statistics based on the previous statistics.
- */
- public CQueryStats(CQueryStats previous, int loadedBeanCount, int timeMicros) {
- count = previous.count + 1;
- totalLoadedBeanCount = previous.totalLoadedBeanCount + loadedBeanCount;
- totalTimeMicros = previous.totalTimeMicros + timeMicros;
- startCollecting = previous.startCollecting;
- lastQueryTime = System.currentTimeMillis();
- }
-
- public CQueryStats add(int loadedBeanCount, int timeMicros) {
- return new CQueryStats(this, loadedBeanCount, timeMicros);
- }
-
- public int getCount() {
- return count;
- }
-
- public int getAverageTimeMicros() {
- if (count == 0) {
- return 0;
- } else {
- return totalTimeMicros / count;
- }
- }
-
- public int getTotalLoadedBeanCount() {
- return totalLoadedBeanCount;
- }
-
- public int getTotalTimeMicros() {
- return totalTimeMicros;
- }
-
- public long getStartCollecting() {
- return startCollecting;
- }
-
- public long getLastQueryTime() {
- return lastQueryTime;
- }
-
- public MetaQueryStatistic createMetaQueryStatistic(String beanName, CQueryPlan qp) {
- return new MetaQueryStatistic(qp.isAutofetchTuned(), beanName, qp.getHash(),
- qp.getSql(), count, totalLoadedBeanCount, totalTimeMicros, startCollecting, lastQueryTime);
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebeaninternal/server/query/RawSqlSelectClauseBuilder.java b/src/main/java/com/avaje/ebeaninternal/server/query/RawSqlSelectClauseBuilder.java
index b11fbfc0a..5c92b11bf 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/query/RawSqlSelectClauseBuilder.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/query/RawSqlSelectClauseBuilder.java
@@ -83,7 +83,7 @@ public class RawSqlSelectClauseBuilder {
SqlTree sqlTree = sqlSelect.getSqlTree();
- CQueryPlan queryPlan = new CQueryPlan(sql, sqlTree, true, includeRowNumColumn, "");
+ CQueryPlan queryPlan = new CQueryPlan(query.getBeanType(), sql, sqlTree, true, includeRowNumColumn, "");
CQuery compiledQuery = new CQuery(request, predicates, queryPlan);
return compiledQuery;
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 5da53707b..6d6d748a8 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -112,6 +112,7 @@ public class DefaultOrmQuery implements SpiQuery {
private OrderBy orderBy;
private String loadMode;
+
private String loadDescription;
private String generatedSql;
@@ -127,7 +128,7 @@ public class DefaultOrmQuery implements SpiQuery {
private String lazyLoadProperty;
- private String lazyLoadManyPath;
+ private String lazyLoadManyPath;
/**
* Set to true if you want a DISTINCT query.
@@ -172,6 +173,7 @@ public class DefaultOrmQuery implements SpiQuery {
private boolean usageProfiling = true;
private boolean loadBeanCache;
+
private Boolean useBeanCache;
private Boolean useQueryCache;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
index d60922443..ed6922d38 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
@@ -2,9 +2,7 @@ package com.avaje.ebeaninternal.server.transaction;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Map;
-import java.util.Map.Entry;
import java.util.Set;
import com.avaje.ebean.bean.PersistenceContext;
@@ -17,8 +15,9 @@ import com.avaje.ebeaninternal.api.Monitor;
* id.
*
*
- * PersistenceContext lives on a Transaction and as such is expected to only have
- * a single thread accessing it at a time. This is not expected to be used concurrently.
+ * PersistenceContext lives on a Transaction and as such is expected to only
+ * have a single thread accessing it at a time. This is not expected to be used
+ * concurrently.
*
*
* Duplicate beans are ones having the same type and unique id value. These are
@@ -28,166 +27,172 @@ import com.avaje.ebeaninternal.api.Monitor;
*/
public final class DefaultPersistenceContext implements PersistenceContext {
- /**
- * Map used hold caches. One cache per bean type.
- */
- private final HashMap typeCache = new HashMap();
+ /**
+ * Map used hold caches. One cache per bean type.
+ */
+ private final HashMap typeCache = new HashMap();
- private final Monitor monitor = new Monitor();
-
- /**
- * Create a new PersistanceContext.
- */
- public DefaultPersistenceContext() {
- }
+ private final Monitor monitor = new Monitor();
- /**
- * Set an object into the PersistanceContext.
- */
- public void put(Object id, Object bean) {
- synchronized (monitor) {
- getClassContext(bean.getClass()).put(id, bean);
- }
- }
-
- public Object putIfAbsent(Object id, Object bean){
- synchronized (monitor) {
- return getClassContext(bean.getClass()).putIfAbsent(id, bean);
- }
- }
+ /**
+ * Create a new PersistanceContext.
+ */
+ public DefaultPersistenceContext() {
+ }
-
-
- /**
- * Return an object given its type and unique id.
- */
- public Object get(Class> beanType, Object id) {
- synchronized (monitor) {
- return getClassContext(beanType).get(id);
- }
+ /**
+ * Set an object into the PersistanceContext.
+ */
+ public void put(Object id, Object bean) {
+ synchronized (monitor) {
+ getClassContext(bean.getClass()).put(id, bean);
}
-
- public WithOption getWithOption(Class> beanType, Object id) {
- synchronized (monitor) {
- return getClassContext(beanType).getWithOption(id);
+ }
+
+ public Object putIfAbsent(Object id, Object bean) {
+ synchronized (monitor) {
+ return getClassContext(bean.getClass()).putIfAbsent(id, bean);
+ }
+ }
+
+ /**
+ * Return an object given its type and unique id.
+ */
+ public Object get(Class> beanType, Object id) {
+ synchronized (monitor) {
+ return getClassContext(beanType).get(id);
+ }
+ }
+
+ public WithOption getWithOption(Class> beanType, Object id) {
+ synchronized (monitor) {
+ return getClassContext(beanType).getWithOption(id);
+ }
+ }
+
+ /**
+ * Return the number of beans of the given type in the persistence context.
+ */
+ public int size(Class> beanType) {
+ synchronized (monitor) {
+ ClassContext classMap = typeCache.get(beanType.getName());
+ return classMap == null ? 0 : classMap.size();
+ }
+ }
+
+ /**
+ * Clear the PersistenceContext.
+ */
+ public void clear() {
+ synchronized (monitor) {
+ typeCache.clear();
+ }
+ }
+
+ public void clear(Class> beanType) {
+ synchronized (monitor) {
+ ClassContext classMap = typeCache.get(beanType.getName());
+ if (classMap != null) {
+ classMap.clear();
}
}
+ }
- /**
- * Return the number of beans of the given type in the persistence context.
- */
- public int size(Class> beanType) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- return classMap == null ? 0 : classMap.size();
- }
- }
-
- /**
- * Clear the PersistenceContext.
- */
- public void clear() {
- synchronized (monitor) {
- typeCache.clear();
- }
- }
-
- public void clear(Class> beanType) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null) {
- classMap.clear();
- }
- }
- }
-
- public void deleted(Class> beanType, Object id) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null && id != null) {
- classMap.deleted(id);
- }
+ public void deleted(Class> beanType, Object id) {
+ synchronized (monitor) {
+ ClassContext classMap = typeCache.get(beanType.getName());
+ if (classMap != null && id != null) {
+ classMap.deleted(id);
}
}
-
- public void clear(Class> beanType, Object id) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null && id != null) {
- classMap.remove(id);
- }
- }
+ }
+
+ public void clear(Class> beanType, Object id) {
+ synchronized (monitor) {
+ ClassContext classMap = typeCache.get(beanType.getName());
+ if (classMap != null && id != null) {
+ classMap.remove(id);
+ }
}
-
+ }
+
+ public String toString() {
+ synchronized (monitor) {
+ return typeCache.toString();
+ }
+ }
+
+ private ClassContext getClassContext(Class> beanType) {
+
+ String clsName = beanType.getName();
+ ClassContext classMap = typeCache.get(clsName);
+ if (classMap == null) {
+ classMap = new ClassContext();
+ typeCache.put(clsName, classMap);
+ }
+ return classMap;
+ }
+
+ private static class ClassContext {
+
+ private final Map