Merge remote-tracking branch 'ebean/master' into pr/bugfix/subquery_without_where

This commit is contained in:
Jonas Pöhler committed 2021-08-17 16:07:02 +02:00
commit e1731b87ec
844 files changed
+5154 -4973

No files matched your search

-6
View File
@@ -1,9 +1,3 @@
GITHUB ISSUES ARE STRICTLY CONTROLLED FOR THIS PROJECT.
Refer to http://ebean-orm.github.io/support for the policies controlling the use of github issues.
Please post issues to the Ebean group https://groups.google.com/forum/#!forum/ebean first.
## Expected behavior ## Expected behavior
## Actual behavior ## Actual behavior
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</parent> </parent>
<name>ebean api</name> <name>ebean api</name>
@@ -50,7 +50,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-annotation</artifactId> <artifactId>ebean-annotation</artifactId>
<version>7.0</version> <version>7.2</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -16,18 +16,15 @@ import java.util.concurrent.locks.ReentrantLock;
* <p> * <p>
* This uses either DatabaseConfig or properties in the application.properties file to * This uses either DatabaseConfig or properties in the application.properties file to
* configure and create a Database instance. * configure and create a Database instance.
* </p>
* <p> * <p>
* The Database instance can either be registered with the DB singleton or * The Database instance can either be registered with the DB singleton or
* not. The DB singleton effectively holds a map of Database by a name. * not. The DB singleton effectively holds a map of Database by a name.
* If the Database is registered with the DB singleton you can retrieve it * If the Database is registered with the DB singleton you can retrieve it
* later via {@link DB#byName(String)}. * later via {@link DB#byName(String)}.
* </p>
* <p> * <p>
* One Database can be nominated as the 'default/primary' Database. Many * One Database can be nominated as the 'default/primary' Database. Many
* methods on the DB singleton such as {@link DB#find(Class)} are just a * methods on the DB singleton such as {@link DB#find(Class)} are just a
* convenient way of using the 'default/primary' Database. * convenient way of using the 'default/primary' Database.
* </p>
*/ */
public class DatabaseFactory { public class DatabaseFactory {
@@ -48,7 +45,7 @@ public class DatabaseFactory {
public static void initialiseContainer(ContainerConfig containerConfig) { public static void initialiseContainer(ContainerConfig containerConfig) {
lock.lock(); lock.lock();
try { try {
getContainer(containerConfig); container(containerConfig);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@@ -60,7 +57,7 @@ public class DatabaseFactory {
public static Database create(String name) { public static Database create(String name) {
lock.lock(); lock.lock();
try { try {
return getContainer(null).createServer(name); return container(null).createServer(name);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
@@ -68,6 +65,16 @@ public class DatabaseFactory {
/** /**
* Create using the DatabaseConfig object to configure the database. * Create using the DatabaseConfig object to configure the database.
*
* <pre>{@code
*
* DatabaseConfig config = new DatabaseConfig();
* config.setName("db");
* config.loadProperties();
*
* Database database = DatabaseFactory.create(config);
*
* }</pre>
*/ */
public static Database create(DatabaseConfig config) { public static Database create(DatabaseConfig config) {
lock.lock(); lock.lock();
@@ -115,7 +122,6 @@ public class DatabaseFactory {
* Shutdown gracefully all Database instances cleaning up any resources as required. * Shutdown gracefully all Database instances cleaning up any resources as required.
* <p> * <p>
* This is typically invoked via JVM shutdown hook and not explicitly called. * This is typically invoked via JVM shutdown hook and not explicitly called.
* </p>
*/ */
public static void shutdown() { public static void shutdown() {
lock.lock(); lock.lock();
@@ -127,15 +133,15 @@ public class DatabaseFactory {
} }
private static Database createInternal(DatabaseConfig config) { private static Database createInternal(DatabaseConfig config) {
return getContainer(config.getContainerConfig()).createServer(config); return container(config.getContainerConfig()).createServer(config);
} }
/** /**
* Get the EbeanContainer initialising it if necessary. * Return the SpiContainer initialising it if necessary.
* *
* @param containerConfig the configuration controlling clustering communication * @param containerConfig the configuration controlling clustering communication
*/ */
private static SpiContainer getContainer(ContainerConfig containerConfig) { private static SpiContainer container(ContainerConfig containerConfig) {
// thread safe in that all calling methods hold lock // thread safe in that all calling methods hold lock
if (container != null) { if (container != null) {
return container; return container;
@@ -27,17 +27,6 @@ public interface EntityBean extends Serializable {
throw new NotEnhancedException(); throw new NotEnhancedException();
} }
/**
* Return the enhancement marker value.
* <p>
* This is the class name of the enhanced class and used to check that all
* entity classes are enhanced (specifically not just a super class).
* </p>
*/
default String _ebean_getMarker() {
throw new NotEnhancedException();
}
/** /**
* Create and return a new entity bean instance. * Create and return a new entity bean instance.
*/ */
@@ -51,6 +51,11 @@ public final class EntityBeanIntercept implements Serializable {
*/ */
private static final byte FLAG_ORIG_VALUE_SET = 8; private static final byte FLAG_ORIG_VALUE_SET = 8;
/**
* Flags indicating if the mutable hash is set.
*/
private static final byte FLAG_MUTABLE_HASH_SET = 16;
private transient final ReentrantLock lock = new ReentrantLock(); private transient final ReentrantLock lock = new ReentrantLock();
private transient NodeUsageCollector nodeUsageCollector; private transient NodeUsageCollector nodeUsageCollector;
private transient PersistenceContext persistenceContext; private transient PersistenceContext persistenceContext;
@@ -91,6 +96,17 @@ public final class EntityBeanIntercept implements Serializable {
private Object ownerId; private Object ownerId;
private int sortOrder; private int sortOrder;
/**
* Holds information of json loaded jackson beans (e.g. the original json or checksum).
*/
private MutableValueInfo[] mutableInfo;
/**
* Holds json content determined at point of dirty check.
* Stored here on dirty check such that we only convert to json once.
*/
private MutableValueNext[] mutableNext;
/** /**
* Create a intercept with a given entity. * Create a intercept with a given entity.
*/ */
@@ -228,6 +244,17 @@ public final class EntityBeanIntercept implements Serializable {
* if any embedded beans are either new or dirty (and hence need saving). * if any embedded beans are either new or dirty (and hence need saving).
*/ */
public boolean isDirty() { public boolean isDirty() {
if (dirty) {
return true;
}
if (mutableInfo != null) {
for (int i = 0; i < mutableInfo.length; i++) {
if (mutableInfo[i] != null && !mutableInfo[i].isEqualToObject(owner._ebean_getField(i))) {
dirty = true;
break;
}
}
}
return dirty; return dirty;
} }
@@ -368,8 +395,18 @@ public final class EntityBeanIntercept implements Serializable {
this.owner._ebean_setEmbeddedLoaded(); this.owner._ebean_setEmbeddedLoaded();
this.lazyLoadProperty = -1; this.lazyLoadProperty = -1;
this.origValues = null; this.origValues = null;
// after save, transfer the mutable next values back to mutable info
if (mutableNext != null) {
for (int i = 0; i < mutableNext.length; i++) {
MutableValueNext next = mutableNext[i];
if (next != null) {
mutableInfo(i, next.info());
}
}
}
this.mutableNext = null;
for (int i = 0; i < flags.length; i++) { for (int i = 0; i < flags.length; i++) {
flags[i] &= ~(FLAG_CHANGED_PROP + FLAG_ORIG_VALUE_SET); flags[i] &= ~(FLAG_CHANGED_PROP | FLAG_ORIG_VALUE_SET);
} }
this.dirty = false; this.dirty = false;
} }
@@ -442,6 +479,10 @@ public final class EntityBeanIntercept implements Serializable {
* Return the original value that was changed via an update. * Return the original value that was changed via an update.
*/ */
public Object getOrigValue(int propertyIndex) { public Object getOrigValue(int propertyIndex) {
if ((flags[propertyIndex] & (FLAG_ORIG_VALUE_SET | FLAG_MUTABLE_HASH_SET)) == FLAG_MUTABLE_HASH_SET) {
// mutable hash set, but not ORIG_VALUE
setOriginalValue(propertyIndex, mutableInfo[propertyIndex].get());
}
if (origValues == null) { if (origValues == null) {
return null; return null;
} }
@@ -638,7 +679,7 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyNames(Set<String> props, String prefix) { public void addDirtyPropertyNames(Set<String> props, String prefix) {
int len = getPropertyLength(); int len = getPropertyLength();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { if (isChangedProp(i)) {
// the property has been changed on this bean // the property has been changed on this bean
props.add((prefix == null ? getProperty(i) : prefix + getProperty(i))); props.add((prefix == null ? getProperty(i) : prefix + getProperty(i)));
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
@@ -656,7 +697,7 @@ public final class EntityBeanIntercept implements Serializable {
String[] names = owner._ebean_getPropertyNames(); String[] names = owner._ebean_getPropertyNames();
int len = getPropertyLength(); int len = getPropertyLength();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { if (isChangedProp(i)) {
if (propertyNames.contains(names[i])) { if (propertyNames.contains(names[i])) {
return true; return true;
} }
@@ -684,7 +725,7 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) { public void addDirtyPropertyValues(Map<String, ValuePair> dirtyValues, String prefix) {
int len = getPropertyLength(); int len = getPropertyLength();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { if (isChangedProp(i)) {
// the property has been changed on this bean // the property has been changed on this bean
String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i)); String propName = (prefix == null ? getProperty(i) : prefix + getProperty(i));
Object newVal = owner._ebean_getField(i); Object newVal = owner._ebean_getField(i);
@@ -706,7 +747,7 @@ public final class EntityBeanIntercept implements Serializable {
public void addDirtyPropertyValues(BeanDiffVisitor visitor) { public void addDirtyPropertyValues(BeanDiffVisitor visitor) {
int len = getPropertyLength(); int len = getPropertyLength();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { if (isChangedProp(i)) {
// the property has been changed on this bean // the property has been changed on this bean
Object newVal = owner._ebean_getField(i); Object newVal = owner._ebean_getField(i);
Object oldVal = getOrigValue(i); Object oldVal = getOrigValue(i);
@@ -741,7 +782,7 @@ public final class EntityBeanIntercept implements Serializable {
} }
int len = getPropertyLength(); int len = getPropertyLength();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) { if ((flags[i] & FLAG_CHANGED_PROP) != 0) { // we do not check against mutablecontent here.
sb.append(i).append(','); sb.append(i).append(',');
} else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) { } else if ((flags[i] & FLAG_EMBEDDED_DIRTY) != 0) {
// an embedded property has been changed - recurse // an embedded property has been changed - recurse
@@ -1138,4 +1179,60 @@ public final class EntityBeanIntercept implements Serializable {
} }
return ret; return ret;
} }
private boolean isChangedProp(int i) {
if ((flags[i] & FLAG_CHANGED_PROP) != 0) {
return true;
} else if (mutableInfo == null || mutableInfo[i] == null || mutableInfo[i].isEqualToObject(owner._ebean_getField(i))) {
return false;
} else {
// mark for change
flags[i] |= FLAG_CHANGED_PROP;
dirty = true; // this makes the bean automatically dirty!
return true;
}
}
/**
* Return the MutableValueInfo for the given property or null.
*/
public MutableValueInfo mutableInfo(int propertyIndex) {
return mutableInfo == null ? null : mutableInfo[propertyIndex];
}
/**
* Set the MutableValueInfo for the given property.
*/
public void mutableInfo(int propertyIndex, MutableValueInfo info) {
if (mutableInfo == null) {
mutableInfo = new MutableValueInfo[flags.length];
}
flags[propertyIndex] |= FLAG_MUTABLE_HASH_SET;
mutableInfo[propertyIndex] = info;
}
/**
* Dirty detection set the next mutable property content and info .
* <p>
* Set here as the mutable property dirty detection is based on json content comparison.
* We only want to perform the json serialisation once so storing it here as part of
* dirty detection so that we can get it back to bind in insert or update etc.
*/
public void mutableNext(int propertyIndex, MutableValueNext next) {
if (mutableNext == null) {
mutableNext = new MutableValueNext[flags.length];
}
mutableNext[propertyIndex] = next;
}
/**
* Update the 'next' mutable info returning the content that was obtained via dirty detection.
*/
public String mutableNext(int propertyIndex) {
if (mutableNext == null) {
return null;
}
return mutableNext[propertyIndex].content();
}
} }
@@ -0,0 +1,42 @@
package io.ebean.bean;
/**
* Holds information on mutable values (like plain beans stored as json).
* <p>
* Used internally in EntityBeanIntercept for dirty detection on mutable values.
* Typically, mutation detection is based on a hash/checksum of json content or the
* original json content itself.
* <p>
* Refer to the mapping options {@code @DbJson(mutationDetection)}.
*/
public interface MutableValueInfo {
/**
* Compares the given json returning null if deemed unchanged or returning
* the MutableValueNext to use if deemed dirty/changed.
* <p>
* Returning MutableValueNext allows an implementation based on hash/checksum
* to only perform that computation once.
*
* @return Null if deemed unchanged or the MutableValueNext if deemed changed.
*/
MutableValueNext nextDirty(String json);
/**
* Compares the given object to an internal value.
* <p>
* This is used to support changelog/beanState. The implementation can serialize the
* object into json form and compare it against the original json.
*/
boolean isEqualToObject(Object obj);
/**
* Creates a new instance from the internal json string.
* <p>
* This is used to provide an original/old value for change logging / persist listeners.
* This is only available for properties that have {@code @DbJson(keepSource=true)}.
*/
default Object get() {
return null;
}
}
@@ -0,0 +1,17 @@
package io.ebean.bean;
/**
* Represents a next value to use for mutable content properties (DbJson with jackson beans).
*/
public interface MutableValueNext {
/**
* Return the next content to use. Provided such that we serialise to json once.
*/
String content();
/**
* Return the next MutableValueInfo to use after an update.
*/
MutableValueInfo info();
}
@@ -7,9 +7,7 @@ import io.ebean.EbeanVersion;
import io.ebean.PersistenceContextScope; import io.ebean.PersistenceContextScope;
import io.ebean.Query; import io.ebean.Query;
import io.ebean.Transaction; import io.ebean.Transaction;
import io.ebean.annotation.Encrypted; import io.ebean.annotation.*;
import io.ebean.annotation.PersistBatch;
import io.ebean.annotation.Platform;
import io.ebean.cache.ServerCachePlugin; import io.ebean.cache.ServerCachePlugin;
import io.ebean.config.dbplatform.DatabasePlatform; import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.config.dbplatform.DbEncrypt; import io.ebean.config.dbplatform.DbEncrypt;
@@ -194,10 +192,9 @@ public class DatabaseConfig {
private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL; private JsonConfig.Include jsonInclude = JsonConfig.Include.ALL;
/** /**
* When true then by default DbJson beans are assumed to be dirty. * The default mode used for {@code @DbJson} with Jackson ObjectMapper.
* I believe we want to change this default to false in the future.
*/ */
private boolean jsonDirtyByDefault = true; private MutationDetection jsonMutationDetection = MutationDetection.HASH;
/** /**
* The database platform name. Used to imply a DatabasePlatform to use. * The database platform name. Used to imply a DatabasePlatform to use.
@@ -322,6 +319,8 @@ public class DatabaseConfig {
*/ */
private ExternalTransactionManager externalTransactionManager; private ExternalTransactionManager externalTransactionManager;
private boolean skipDataSourceCheck;
/** /**
* The data source (if programmatically provided). * The data source (if programmatically provided).
*/ */
@@ -744,23 +743,21 @@ public class DatabaseConfig {
} }
/** /**
* Return true if DbJson beans are assumed dirty by default. * Return the default MutableDetection to use with {@code @DbJson} using Jackson.
* <p> *
* That is, when true beans that do not implement ModifyAwareType are by * @see DbJson#mutationDetection()
* default assumed to be dirty and included in updates.
*/ */
public boolean isJsonDirtyByDefault() { public MutationDetection getJsonMutationDetection() {
return jsonDirtyByDefault; return jsonMutationDetection;
} }
/** /**
* Set to false if we want DbJson beans to not be assumed to be dirty. * Set the default MutableDetection to use with {@code @DbJson} using Jackson.
* <p> *
* That is, when true beans that do not implement ModifyAwareType are by * @see DbJson#mutationDetection()
* default assumed to be dirty and included in updates.
*/ */
public void setJsonDirtyByDefault(boolean jsonDirtyByDefault) { public void setJsonMutationDetection(MutationDetection jsonMutationDetection) {
this.jsonDirtyByDefault = jsonDirtyByDefault; this.jsonMutationDetection = jsonMutationDetection;
} }
/** /**
@@ -1656,6 +1653,20 @@ public class DatabaseConfig {
this.autoTuneConfig = autoTuneConfig; this.autoTuneConfig = autoTuneConfig;
} }
/**
* Return true if the startup DataSource check should be skipped.
*/
public boolean skipDataSourceCheck() {
return skipDataSourceCheck;
}
/**
* Set to true to skip the startup DataSource check.
*/
public void setSkipDataSourceCheck(boolean skipDataSourceCheck) {
this.skipDataSourceCheck = skipDataSourceCheck;
}
/** /**
* Return the DataSource. * Return the DataSource.
*/ */
@@ -2935,8 +2946,9 @@ public class DatabaseConfig {
jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude); jsonInclude = p.getEnum(JsonConfig.Include.class, "jsonInclude", jsonInclude);
jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime); jsonDateTime = p.getEnum(JsonConfig.DateTime.class, "jsonDateTime", jsonDateTime);
jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate); jsonDate = p.getEnum(JsonConfig.Date.class, "jsonDate", jsonDate);
jsonDirtyByDefault = p.getBoolean("jsonDirtyByDefault", jsonDirtyByDefault); jsonMutationDetection = p.getEnum(MutationDetection.class, "jsonMutationDetection", jsonMutationDetection);
skipDataSourceCheck = p.getBoolean("skipDataSourceCheck", skipDataSourceCheck);
runMigration = p.getBoolean("migration.run", runMigration); runMigration = p.getBoolean("migration.run", runMigration);
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate); ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
ddlRun = p.getBoolean("ddl.run", ddlRun); ddlRun = p.getBoolean("ddl.run", ddlRun);
@@ -14,10 +14,9 @@ import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
/** /**
* Manages the shutdown of the JVM Runtime. * Manages the shutdown of Ebean.
* <p> * <p>
* Makes sure all the resources are shutdown properly and in order. * Makes sure all the resources are shutdown properly and in order.
* </p>
*/ */
public final class ShutdownManager { public final class ShutdownManager {
@@ -44,6 +43,9 @@ public final class ShutdownManager {
private ShutdownManager() { private ShutdownManager() {
} }
/**
* Registers the container (potentially with cluster management).
*/
public static void registerContainer(SpiContainer ebeanContainer) { public static void registerContainer(SpiContainer ebeanContainer) {
container = ebeanContainer; container = ebeanContainer;
} }
@@ -94,7 +96,7 @@ public final class ShutdownManager {
/** /**
* Register the shutdown hook with the Runtime. * Register the shutdown hook with the Runtime.
*/ */
protected static void registerShutdownHook() { private static void registerShutdownHook() {
lock.lock(); lock.lock();
try { try {
String value = System.getProperty("ebean.registerShutdownHook"); String value = System.getProperty("ebean.registerShutdownHook");
@@ -123,13 +125,10 @@ public final class ShutdownManager {
// Already run shutdown... // Already run shutdown...
return; return;
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Shutting down"); logger.debug("Shutting down");
} }
stopping = true; stopping = true;
deregisterShutdownHook(); deregisterShutdownHook();
String shutdownRunner = System.getProperty("ebean.shutdown.runnable"); String shutdownRunner = System.getProperty("ebean.shutdown.runnable");
@@ -147,7 +146,6 @@ public final class ShutdownManager {
// shutdown cluster networking if active // shutdown cluster networking if active
container.shutdown(); container.shutdown();
} }
// shutdown any registered servers that have not // shutdown any registered servers that have not
// already been shutdown manually // already been shutdown manually
for (Database server : databases) { for (Database server : databases) {
@@ -158,7 +156,6 @@ public final class ShutdownManager {
ex.printStackTrace(); ex.printStackTrace();
} }
} }
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) { if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
deregisterAllJdbcDrivers(); deregisterAllJdbcDrivers();
} }
@@ -168,15 +165,15 @@ public final class ShutdownManager {
} }
private static void deregisterAllJdbcDrivers() { private static void deregisterAllJdbcDrivers() {
// This manually deregisters all JDBC drivers // This manually de-registers all JDBC drivers
Enumeration<Driver> drivers = DriverManager.getDrivers(); Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) { while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement(); Driver driver = drivers.nextElement();
try { try {
logger.info("Deregistering jdbc driver: " + driver); logger.info("De-registering jdbc driver: " + driver);
DriverManager.deregisterDriver(driver); DriverManager.deregisterDriver(driver);
} catch (SQLException e) { } catch (SQLException e) {
logger.error("Error deregistering driver " + driver, e); logger.error("Error de-registering driver " + driver, e);
} }
} }
} }
@@ -209,6 +206,9 @@ public final class ShutdownManager {
} }
private static class ShutdownHook extends Thread { private static class ShutdownHook extends Thread {
private ShutdownHook() {
super("EbeanHook");
}
@Override @Override
public void run() { public void run() {
ShutdownManager.shutdown(); ShutdownManager.shutdown();
@@ -18,22 +18,22 @@ public abstract class AbstractMetricVisitor implements MetricVisitor {
} }
@Override @Override
public boolean isReset() { public boolean reset() {
return reset; return reset;
} }
@Override @Override
public boolean isCollectTransactionMetrics() { public boolean collectTransactionMetrics() {
return collectTransactionMetrics; return collectTransactionMetrics;
} }
@Override @Override
public boolean isCollectQueryMetrics() { public boolean collectQueryMetrics() {
return collectQueryMetrics; return collectQueryMetrics;
} }
@Override @Override
public boolean isCollectL2Metrics() { public boolean collectL2Metrics() {
return collectL2Metrics; return collectL2Metrics;
} }
@@ -27,17 +27,17 @@ public class BasicMetricVisitor extends AbstractMetricVisitor implements ServerM
} }
@Override @Override
public List<MetaTimedMetric> getTimedMetrics() { public List<MetaTimedMetric> timedMetrics() {
return timed; return timed;
} }
@Override @Override
public List<MetaQueryMetric> getQueryMetrics() { public List<MetaQueryMetric> queryMetrics() {
return query; return query;
} }
@Override @Override
public List<MetaCountMetric> getCountMetrics() { public List<MetaCountMetric> countMetrics() {
return count; return count;
} }
@@ -8,6 +8,13 @@ public interface MetaCountMetric extends MetaMetric {
/** /**
* Return the total count. * Return the total count.
*/ */
long getCount(); long count();
/**
* Migrate to count()
*/
@Deprecated
default long getCount() {
return count();
}
} }
@@ -8,6 +8,13 @@ public interface MetaMetric {
/** /**
* Return the metric name. * Return the metric name.
*/ */
String getName(); String name();
/**
* Migrate to name().
*/
@Deprecated
default String getName() {
return name();
}
} }
@@ -8,21 +8,45 @@ public interface MetaQueryMetric extends MetaTimedMetric {
/** /**
* The type of entity or DTO bean. * The type of entity or DTO bean.
*/ */
Class<?> getType(); Class<?> type();
/**
* Migrate to type().
*/
@Deprecated
default Class<?> getType() {
return type();
}
/** /**
* The label for the query (can be null). * The label for the query (can be null).
*/ */
String getLabel(); String label();
/**
* Migrate to label().
*/
@Deprecated
default String getLabel() {
return label();
}
/** /**
* The actual SQL of the query. * The actual SQL of the query.
*/ */
String getSql(); String sql();
/**
* Migrate to sql().
*/
@Deprecated
default String getSql() {
return sql();
}
/** /**
* Return the hash of the plan. * Return the hash of the plan.
*/ */
String getHash(); String hash();
} }
@@ -10,45 +10,45 @@ public interface MetaQueryPlan {
/** /**
* Return the bean type for the query. * Return the bean type for the query.
*/ */
Class<?> getBeanType(); Class<?> beanType();
/** /**
* Return the label of the query. * Return the label of the query.
*/ */
String getLabel(); String label();
/** /**
* Return the profile location for the query. * Return the profile location for the query.
*/ */
ProfileLocation getProfileLocation(); ProfileLocation profileLocation();
/** /**
* Return the sql of the query. * Return the sql of the query.
*/ */
String getSql(); String sql();
/** /**
* Return the hash of the plan. * Return the hash of the plan.
*/ */
String getHash(); String hash();
/** /**
* Return a description of the bind values. * Return a description of the bind values.
*/ */
String getBind(); String bind();
/** /**
* Return the raw plan. * Return the raw plan.
*/ */
String getPlan(); String plan();
/** /**
* Return the query execution time associated with the bind values capture. * Return the query execution time associated with the bind values capture.
*/ */
long getQueryTimeMicros(); long queryTimeMicros();
/** /**
* Return the total count of times bind capture has occurred. * Return the total count of times bind capture has occurred.
*/ */
long getCaptureCount(); long captureCount();
} }
@@ -9,27 +9,68 @@ public interface MetaTimedMetric extends MetaMetric {
/** /**
* Return the metric location if defined. * Return the metric location if defined.
*/ */
String getLocation(); String location();
/**
* Migrate to location()
*/
@Deprecated
default String getLocation() {
return location();
}
/** /**
* Return the total count. * Return the total count.
*/ */
long getCount(); long count();
/**
* Migrate to count()
*/
@Deprecated
default long getCount() {
return count();
}
/** /**
* Return the total execution time in micros. * Return the total execution time in micros.
*/ */
long getTotal(); long total();
/**
* Migrate to total()
*/
@Deprecated
default long getTotal() {
return total();
}
/** /**
* Return the max execution time in micros. * Return the max execution time in micros.
*/ */
long getMax(); long max();
/**
* Migrate to max()
*/
@Deprecated
default long getMax() {
return max();
}
/** /**
* Return the mean execution time in micros. * Return the mean execution time in micros.
*/ */
long getMean(); long mean();
/**
* Migrate to mean()
*/
@Deprecated
default long getMean() {
return mean();
}
/** /**
* Return true if this is the first metrics collection for this query. * Return true if this is the first metrics collection for this query.
@@ -8,22 +8,22 @@ public interface MetricVisitor {
/** /**
* Return true if the metrics should be reset. * Return true if the metrics should be reset.
*/ */
boolean isReset(); boolean reset();
/** /**
* Return true if we should visit the transaction metrics. * Return true if we should visit the transaction metrics.
*/ */
boolean isCollectTransactionMetrics(); boolean collectTransactionMetrics();
/** /**
* Return true if we should visit the ORM and SQL query metrics. * Return true if we should visit the ORM and SQL query metrics.
*/ */
boolean isCollectQueryMetrics(); boolean collectQueryMetrics();
/** /**
* Return true if we should visit the L2 cache metrics. * Return true if we should visit the L2 cache metrics.
*/ */
boolean isCollectL2Metrics(); boolean collectL2Metrics();
/** /**
* Visit has started. * Visit has started.
@@ -32,7 +32,7 @@ public class QueryPlanInit {
* Return the query execution time threshold which must be exceeded to initiate * Return the query execution time threshold which must be exceeded to initiate
* query plan collection. * query plan collection.
*/ */
public long getThresholdMicros() { public long thresholdMicros() {
return thresholdMicros; return thresholdMicros;
} }
@@ -40,7 +40,7 @@ public class QueryPlanInit {
* Set the query execution time threshold which must be exceeded to initiate * Set the query execution time threshold which must be exceeded to initiate
* query plan collection. * query plan collection.
*/ */
public void setThresholdMicros(long thresholdMicros) { public void thresholdMicros(long thresholdMicros) {
this.thresholdMicros = thresholdMicros; this.thresholdMicros = thresholdMicros;
} }
@@ -54,14 +54,14 @@ public class QueryPlanInit {
/** /**
* Return the specific hashes that we want to collect query plans on. * Return the specific hashes that we want to collect query plans on.
*/ */
public Set<String> getHashes() { public Set<String> hashes() {
return hashes; return hashes;
} }
/** /**
* Set the specific hashes that we want to collect query plans on. * Set the specific hashes that we want to collect query plans on.
*/ */
public void setHashes(Set<String> hashes) { public void hashes(Set<String> hashes) {
this.hashes = hashes; this.hashes = hashes;
} }
} }
@@ -18,7 +18,7 @@ public class QueryPlanRequest {
* have been around for a while (e.g. 5 mins) and so reasonably represent * have been around for a while (e.g. 5 mins) and so reasonably represent
* bind values that match the slowest execution for this query plan. * bind values that match the slowest execution for this query plan.
*/ */
public long getSince() { public long since() {
return since; return since;
} }
@@ -28,14 +28,14 @@ public class QueryPlanRequest {
* *
* @param since The minimum age of the bind values capture. * @param since The minimum age of the bind values capture.
*/ */
public void setSince(long since) { public void since(long since) {
this.since = since; this.since = since;
} }
/** /**
* Return the maximum number of plans to capture. * Return the maximum number of plans to capture.
*/ */
public int getMaxCount() { public int maxCount() {
return maxCount; return maxCount;
} }
@@ -45,7 +45,7 @@ public class QueryPlanRequest {
* Use this to limit how much query plan capturing is done as query * Use this to limit how much query plan capturing is done as query
* plan capture is actual database load. * plan capture is actual database load.
*/ */
public void setMaxCount(int maxCount) { public void maxCount(int maxCount) {
this.maxCount = maxCount; this.maxCount = maxCount;
} }
@@ -54,7 +54,7 @@ public class QueryPlanRequest {
* <p> * <p>
* Query plan collection will stop once this time is exceeded. * Query plan collection will stop once this time is exceeded.
*/ */
public long getMaxTimeMillis() { public long maxTimeMillis() {
return maxTimeMillis; return maxTimeMillis;
} }
@@ -65,7 +65,7 @@ public class QueryPlanRequest {
* this to ensure the query plan capture does not use excessive amount * this to ensure the query plan capture does not use excessive amount
* of time - put too much load on the database. * of time - put too much load on the database.
*/ */
public void setMaxTimeMillis(long maxTimeMillis) { public void maxTimeMillis(long maxTimeMillis) {
this.maxTimeMillis = maxTimeMillis; this.maxTimeMillis = maxTimeMillis;
} }
} }
@@ -10,16 +10,39 @@ public interface ServerMetrics {
/** /**
* Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate. * Return timed metrics for Transactions, labelled SqlQuery, labelled SqlUpdate.
*/ */
List<MetaTimedMetric> getTimedMetrics(); List<MetaTimedMetric> timedMetrics();
/**
* Migrate to timedMetrics().
*/
@Deprecated
default List<MetaTimedMetric> getTimedMetrics() {
return timedMetrics();
}
/** /**
* Return the query metrics. * Return the query metrics.
*/ */
List<MetaQueryMetric> getQueryMetrics(); List<MetaQueryMetric> queryMetrics();
/**
* Migrate to queryMetrics().
*/
@Deprecated
default List<MetaQueryMetric> getQueryMetrics() {
return queryMetrics();
}
/** /**
* Return the Counter metrics. * Return the Counter metrics.
*/ */
List<MetaCountMetric> getCountMetrics(); List<MetaCountMetric> countMetrics();
/**
* Migrate to countMetrics().
*/
@Deprecated
default List<MetaCountMetric> getCountMetrics() {
return countMetrics();
}
} }
@@ -8,12 +8,12 @@ import java.util.Comparator;
public interface ServerMetricsAsJson { public interface ServerMetricsAsJson {
/** /**
* Set to false to exclude profile location and sql. * Set to false in order to exclude profile location and sql.
*/ */
ServerMetricsAsJson withExtraAttributes(boolean withLocation); ServerMetricsAsJson withExtraAttributes(boolean withLocation);
/** /**
* Set to false to exclude SQL hash. * Set to false in order to exclude SQL hash.
*/ */
ServerMetricsAsJson withHash(boolean withHash); ServerMetricsAsJson withHash(boolean withHash);
@@ -32,7 +32,7 @@ public class SortMetric {
@Override @Override
public int compare(MetaCountMetric o1, MetaCountMetric o2) { public int compare(MetaCountMetric o1, MetaCountMetric o2) {
return stringCompare(o1.getName(), o2.getName()); return stringCompare(o1.name(), o2.name());
} }
} }
@@ -43,8 +43,8 @@ public class SortMetric {
@Override @Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) { public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
int i = stringCompare(o1.getName(), o2.getName()); int i = stringCompare(o1.name(), o2.name());
return i != 0 ? i : Long.compare(o1.getCount(), o2.getCount()); return i != 0 ? i : Long.compare(o1.count(), o2.count());
} }
} }
@@ -55,7 +55,7 @@ public class SortMetric {
@Override @Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) { public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getCount(), o1.getCount()); return Long.compare(o2.count(), o1.count());
} }
} }
@@ -66,7 +66,7 @@ public class SortMetric {
@Override @Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) { public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getTotal(), o1.getTotal()); return Long.compare(o2.total(), o1.total());
} }
} }
@@ -77,7 +77,7 @@ public class SortMetric {
@Override @Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) { public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getMean(), o1.getMean()); return Long.compare(o2.mean(), o1.mean());
} }
} }
@@ -88,7 +88,7 @@ public class SortMetric {
@Override @Override
public int compare(MetaTimedMetric o1, MetaTimedMetric o2) { public int compare(MetaTimedMetric o1, MetaTimedMetric o2) {
return Long.compare(o2.getMax(), o1.getMax()); return Long.compare(o2.max(), o1.max());
} }
} }
} }
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</parent> </parent>
<!-- <parent>--> <!-- <parent>-->
<!-- <groupId>org.avaje</groupId>--> <!-- <groupId>org.avaje</groupId>-->
@@ -26,7 +26,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -146,7 +146,8 @@ public class BaseQueryTuner {
case ID_LIST: case ID_LIST:
case UPDATE: case UPDATE:
case DELETE: case DELETE:
case SUBQUERY: case SQ_EXISTS:
case SQ_IN:
return false; return false;
default: default:
// not using autoTune when explicitly loading the l2 bean cache // not using autoTune when explicitly loading the l2 bean cache
+19 -19
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</parent> </parent>
<name>ebean bom</name> <name>ebean bom</name>
@@ -14,12 +14,12 @@
<properties> <properties>
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version> <ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
<ebean-migration-auto.version>1.0</ebean-migration-auto.version> <ebean-migration-auto.version>1.1</ebean-migration-auto.version>
<ebean-migration.version>12.4.0</ebean-migration.version> <ebean-migration.version>12.11.0</ebean-migration.version>
<ebean-test-docker.version>4.1</ebean-test-docker.version> <ebean-test-docker.version>4.1</ebean-test-docker.version>
<ebean-datasource.version>7.0</ebean-datasource.version> <ebean-datasource.version>7.0</ebean-datasource.version>
<ebean-agent.version>12.10.0</ebean-agent.version> <ebean-agent.version>12.11.0</ebean-agent.version>
<ebean-maven-plugin.version>12.10.0</ebean-maven-plugin.version> <ebean-maven-plugin.version>12.11.0</ebean-maven-plugin.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
@@ -81,88 +81,88 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean</artifactId> <artifactId>ebean</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId> <artifactId>ebean-externalmapping-api</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-xml</artifactId> <artifactId>ebean-externalmapping-xml</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-autotune</artifactId> <artifactId>ebean-autotune</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-querybean</artifactId> <artifactId>ebean-querybean</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>querybean-generator</artifactId> <artifactId>querybean-generator</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>kotlin-querybean-generator</artifactId> <artifactId>kotlin-querybean-generator</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId> <artifactId>ebean-test</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-postgis</artifactId> <artifactId>ebean-postgis</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-redis</artifactId> <artifactId>ebean-redis</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
@@ -16,7 +16,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -163,4 +163,15 @@ public interface DataBinder {
* Bind an array value. * Bind an array value.
*/ */
void setArray(String arrayType, Object[] elements) throws SQLException; void setArray(String arrayType, Object[] elements) throws SQLException;
/**
* Push json from dirty detection to be available for binding.
*/
void pushJson(String json);
/**
* Pop json made during dirty detection for scalarType binding.
*/
String popJson();
} }
@@ -48,4 +48,14 @@ public interface DataReader {
Object getObject() throws SQLException; Object getObject() throws SQLException;
InputStream getBinaryStream() throws SQLException; InputStream getBinaryStream() throws SQLException;
/**
* Push json from dirty detection to be available for binding.
*/
void pushJson(String json);
/**
* Pop json made during dirty detection for scalarType binding.
*/
String popJson();
} }
@@ -2,6 +2,7 @@ package io.ebean.core.type;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonParser;
import io.ebean.text.StringFormatter; import io.ebean.text.StringFormatter;
import io.ebean.text.StringParser; import io.ebean.text.StringParser;
@@ -34,6 +35,10 @@ import java.sql.SQLException;
*/ */
public interface ScalarType<T> extends StringParser, StringFormatter, ScalarDataReader<T> { public interface ScalarType<T> extends StringParser, StringFormatter, ScalarDataReader<T> {
default boolean isJsonMapper() {
return false;
}
/** /**
* Return true if this is a binary type and can not support parse() and format() from/to string. * Return true if this is a binary type and can not support parse() and format() from/to string.
* This allows Ebean to optimise marshalling types to string. * This allows Ebean to optimise marshalling types to string.
+11 -20
View File
@@ -3,7 +3,7 @@
<parent> <parent>
<artifactId>ebean-parent</artifactId> <artifactId>ebean-parent</artifactId>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>ebean-core</artifactId> <artifactId>ebean-core</artifactId>
@@ -20,22 +20,13 @@
<profiles> <profiles>
<profile> <profile>
<!-- Note: to use this profile, you need to download manually the db2jcc4 driver.
After that, install it into your local maven repository:
mvn install:install-file \
-Dfile=db2jcc4.jar \
-DgroupId=com.ibm.jdbc \
-DartifactId=db2jcc4 \
-Dversion=4.23.42 \
-Dpackaging=jar
-->
<id>db2</id> <id>db2</id>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/com.ibm.db2/jcc -->
<dependency> <dependency>
<groupId>com.ibm.jdbc</groupId> <groupId>com.ibm.db2</groupId>
<artifactId>db2jcc4</artifactId> <artifactId>jcc</artifactId>
<version>4.23.42</version> <version>11.5.5.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -52,13 +43,13 @@
<dependency> <dependency>
<groupId>io.avaje</groupId> <groupId>io.avaje</groupId>
<artifactId>classpath-scanner</artifactId> <artifactId>classpath-scanner</artifactId>
<version>4.2</version> <version>6.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-migration-auto</artifactId> <artifactId>ebean-migration-auto</artifactId>
<version>1.0</version> <version>1.1</version>
</dependency> </dependency>
<!-- keep testing in core using ebean-ddl-generator & ebean-migration --> <!-- keep testing in core using ebean-ddl-generator & ebean-migration -->
@@ -72,7 +63,7 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-ddl-generator</artifactId> <artifactId>ebean-ddl-generator</artifactId>
<version>12.9.4-RC1</version> <version>12.11.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
@@ -87,19 +78,19 @@
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-api</artifactId> <artifactId>ebean-api</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-core-type</artifactId> <artifactId>ebean-core-type</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.ebean</groupId> <groupId>io.ebean</groupId>
<artifactId>ebean-externalmapping-api</artifactId> <artifactId>ebean-externalmapping-api</artifactId>
<version>12.10.1-SNAPSHOT</version> <version>12.11.2-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
@@ -6,7 +6,7 @@ import java.util.List;
/** /**
* The results of bean cache hit. * The results of bean cache hit.
*/ */
public class BeanCacheResult<T> { public final class BeanCacheResult<T> {
private final List<Entry<T>> list = new ArrayList<>(); private final List<Entry<T>> list = new ArrayList<>();
@@ -27,7 +27,7 @@ public class BeanCacheResult<T> {
/** /**
* Bean and cache key pair. * Bean and cache key pair.
*/ */
static class Entry<T> { static final class Entry<T> {
private final T bean; private final T bean;
private final Object key; private final Object key;
@@ -7,7 +7,7 @@ import java.io.IOException;
/** /**
* Context used to read binary format messages. * Context used to read binary format messages.
*/ */
public class BinaryReadContext { public final class BinaryReadContext {
private final DataInputStream in; private final DataInputStream in;
@@ -6,10 +6,9 @@ import java.io.IOException;
/** /**
* Context used to write binary message (like RemoteTransactionEvent). * Context used to write binary message (like RemoteTransactionEvent).
*/ */
public class BinaryWriteContext { public final class BinaryWriteContext {
private final DataOutputStream out; private final DataOutputStream out;
private long counter; private long counter;
public BinaryWriteContext(DataOutputStream out) { public BinaryWriteContext(DataOutputStream out) {
@@ -4,11 +4,7 @@ import io.ebeaninternal.server.persist.MultiValueWrapper;
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam; import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.*;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
/** /**
@@ -17,35 +13,28 @@ import java.util.Map.Entry;
* Supports ordered or named parameters. * Supports ordered or named parameters.
* </p> * </p>
*/ */
public class BindParams implements Serializable { public final class BindParams implements Serializable {
private static final long serialVersionUID = 4541081933302086285L; private static final long serialVersionUID = 4541081933302086285L;
private final List<Param> positionedParameters = new ArrayList<>(); private final List<Param> positionedParameters = new ArrayList<>();
private final Map<String, Param> namedParameters = new LinkedHashMap<>(); private final Map<String, Param> namedParameters = new LinkedHashMap<>();
/** /**
* This is the sql. For named parameters this is the sql after the named * This is the sql. For named parameters this is the sql after the named
* parameters have been replaced with question mark place holders and the * parameters have been replaced with question mark place holders and the
* parameters have been ordered by addNamedParamInOrder(). * parameters have been ordered by addNamedParamInOrder().
*/ */
private String preparedSql; private String preparedSql;
/** /**
* Bind hash and count used to detect when the bind values have changed such * Bind hash and count used to detect when the bind values have changed such
* that the generated SQL (with named parameters) needs to be recalculated. * that the generated SQL (with named parameters) needs to be recalculated.
*/ */
private String bindHash; private String bindHash;
/** /**
* Helper to add positioned parameters in order. * Helper to add positioned parameters in order.
*/ */
private int addPos; private int addPos;
public BindParams() {
}
/** /**
* Reset positioned parameters (usually due to bind parameter expansion). * Reset positioned parameters (usually due to bind parameter expansion).
*/ */
@@ -54,12 +43,11 @@ public class BindParams implements Serializable {
positionedParameters.clear(); positionedParameters.clear();
} }
public int queryBindHash() { public void queryBindHash(BindValuesKey key) {
int hc = namedParameters.hashCode(); key.add(positionedParameters.size());
for (Param positionedParameter : positionedParameters) { for (Param param : positionedParameters) {
hc = hc * 92821 + positionedParameter.hashCode(); param.queryBindHash(key);
} }
return hc;
} }
/** /**
@@ -424,7 +412,14 @@ public class BindParams implements Serializable {
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
return o != null && (o == this || (o instanceof Param) && hashCode() == o.hashCode()); if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Param param = (Param) o;
return isInParam == param.isInParam && isOutParam == param.isOutParam && type == param.type && Objects.equals(inValue, param.inValue);
}
void queryBindHash(BindValuesKey key) {
key.add(isInParam).add(isOutParam).add(type).add(inValue);
} }
/** /**
@@ -0,0 +1,35 @@
package io.ebeaninternal.api;
import java.util.ArrayList;
import java.util.List;
/**
* BindValues used for L2 query cache key matching.
* <p>
* The equals/hashCode implementation must meet the requirement that the query bind values
* match for L2 query cache hit (given the query plan hash is already a match).
*/
public final class BindValuesKey {
private final List<Object> values = new ArrayList<>();
/**
* Add a bind value.
*/
public BindValuesKey add(Object value) {
values.add(value);
return this;
}
@Override
public boolean equals(Object obj) {
return obj instanceof BindValuesKey && ((BindValuesKey) obj).values.equals(values);
}
@Override
public int hashCode() {
return values.hashCode();
}
}
@@ -11,10 +11,9 @@ import java.util.Set;
/** /**
* Used for bean cache lookup with where ids in expression. * Used for bean cache lookup with where ids in expression.
*/ */
public class CacheIdLookupMany<T> implements CacheIdLookup<T> { public final class CacheIdLookupMany<T> implements CacheIdLookup<T> {
private final IdInExpression idInExpression; private final IdInExpression idInExpression;
private int remaining; private int remaining;
public CacheIdLookupMany(IdInExpression idInExpression) { public CacheIdLookupMany(IdInExpression idInExpression) {
@@ -7,7 +7,7 @@ import java.util.List;
/** /**
* Used for bean cache lookup with a single id value. * Used for bean cache lookup with a single id value.
*/ */
public class CacheIdLookupSingle<T> implements CacheIdLookup<T> { public final class CacheIdLookupSingle<T> implements CacheIdLookup<T> {
private final Object idValue; private final Object idValue;
private boolean found; private boolean found;
@@ -1,16 +1,12 @@
package io.ebeaninternal.api; package io.ebeaninternal.api;
import io.ebean.annotation.Platform; import io.ebean.annotation.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* Helper to indicate that an EbeanServer should come up offline * Helper to indicate that an EbeanServer should come up offline
* typically for DDL generation purposes. * typically for DDL generation purposes.
*/ */
public class DbOffline { public final class DbOffline {
private static final Logger logger = LoggerFactory.getLogger(DbOffline.class);
private static final String KEY = "ebean.dboffline"; private static final String KEY = "ebean.dboffline";
@@ -73,7 +69,6 @@ public class DbOffline {
public static void reset() { public static void reset() {
generateMigration = false; generateMigration = false;
System.clearProperty(KEY); System.clearProperty(KEY);
logger.debug("reset");
} }
} }
@@ -8,7 +8,7 @@ import io.ebean.metric.TimedMetric;
/** /**
* Extra metrics collected to measure internal behaviour. * Extra metrics collected to measure internal behaviour.
*/ */
public class ExtraMetrics { public final class ExtraMetrics {
private final TimedMetric bindCapture; private final TimedMetric bindCapture;
private final TimedMetric planCollect; private final TimedMetric planCollect;
@@ -3,18 +3,17 @@ package io.ebeaninternal.api;
/** /**
* A hash key for a query including both the query plan and bind values. * A hash key for a query including both the query plan and bind values.
*/ */
public class HashQuery { public final class HashQuery {
private final CQueryPlanKey planHash; private final CQueryPlanKey planHash;
private final BindValuesKey bindValuesKey;
private final int bindHash;
/** /**
* Create the HashQuery. * Create the HashQuery.
*/ */
public HashQuery(CQueryPlanKey planHash, int bindHash) { public HashQuery(CQueryPlanKey planHash, BindValuesKey bindValuesKey) {
this.planHash = planHash; this.planHash = planHash;
this.bindHash = bindHash; this.bindValuesKey = bindValuesKey;
} }
@Override @Override
@@ -25,7 +24,7 @@ public class HashQuery {
@Override @Override
public int hashCode() { public int hashCode() {
int hc = 92821 * planHash.hashCode(); int hc = 92821 * planHash.hashCode();
hc = 92821 * hc + bindHash; hc = 92821 * hc + bindValuesKey.hashCode();
return hc; return hc;
} }
@@ -37,8 +36,7 @@ public class HashQuery {
if (!(obj instanceof HashQuery)) { if (!(obj instanceof HashQuery)) {
return false; return false;
} }
HashQuery e = (HashQuery) obj; HashQuery e = (HashQuery) obj;
return e.bindHash == bindHash && e.planHash.equals(planHash); return e.bindValuesKey.equals(bindValuesKey) && e.planHash.equals(planHash);
} }
} }
@@ -6,7 +6,7 @@ import io.ebean.TxScope;
/** /**
* Helper object to make AOP generated code simpler. * Helper object to make AOP generated code simpler.
*/ */
public class HelpScopeTrans { public final class HelpScopeTrans {
private static boolean enabled = true; private static boolean enabled = true;
/** /**
@@ -13,16 +13,12 @@ import java.util.Set;
/** /**
* Request for loading ManyToOne and OneToOne relationships. * Request for loading ManyToOne and OneToOne relationships.
*/ */
public class LoadBeanRequest extends LoadRequest { public final class LoadBeanRequest extends LoadRequest {
private final List<EntityBeanIntercept> batch; private final List<EntityBeanIntercept> batch;
private final LoadBeanBuffer loadBuffer; private final LoadBeanBuffer loadBuffer;
private final String lazyLoadProperty; private final String lazyLoadProperty;
private final boolean loadCache; private final boolean loadCache;
private boolean loadedFromCache; private boolean loadedFromCache;
/** /**
@@ -92,9 +88,7 @@ public class LoadBeanRequest extends LoadRequest {
* Return the list of Id values for the beans in the lazy load buffer. * Return the list of Id values for the beans in the lazy load buffer.
*/ */
public List<Object> getIdList() { public List<Object> getIdList() {
List<Object> idList = new ArrayList<>(); List<Object> idList = new ArrayList<>();
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor(); BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
for (EntityBeanIntercept ebi : batch) { for (EntityBeanIntercept ebi : batch) {
idList.add(desc.getId(ebi.getOwner())); idList.add(desc.getId(ebi.getOwner()));
@@ -106,10 +100,8 @@ public class LoadBeanRequest extends LoadRequest {
* Configure the query for lazy loading execution. * Configure the query for lazy loading execution.
*/ */
public void configureQuery(SpiQuery<?> query, List<Object> idList) { public void configureQuery(SpiQuery<?> query, List<Object> idList) {
query.setMode(SpiQuery.Mode.LAZYLOAD_BEAN); query.setMode(SpiQuery.Mode.LAZYLOAD_BEAN);
query.setPersistenceContext(loadBuffer.getPersistenceContext()); query.setPersistenceContext(loadBuffer.getPersistenceContext());
String mode = isLazy() ? "+lazy" : "+query"; String mode = isLazy() ? "+lazy" : "+query";
query.setLoadDescription(mode, getDescription()); query.setLoadDescription(mode, getDescription());
@@ -117,9 +109,7 @@ public class LoadBeanRequest extends LoadRequest {
// cascade the batch size (if set) for further lazy loading // cascade the batch size (if set) for further lazy loading
query.setLazyLoadBatchSize(getBatchSize()); query.setLazyLoadBatchSize(getBatchSize());
} }
loadBuffer.configureQuery(query, lazyLoadProperty); loadBuffer.configureQuery(query, lazyLoadProperty);
if (idList.size() == 1) { if (idList.size() == 1) {
query.where().idEq(idList.get(0)); query.where().idEq(idList.get(0));
} else { } else {
@@ -131,19 +121,16 @@ public class LoadBeanRequest extends LoadRequest {
* Load the beans into the L2 cache if that is requested and check for load failures due to deletes. * Load the beans into the L2 cache if that is requested and check for load failures due to deletes.
*/ */
public void postLoad(List<?> list) { public void postLoad(List<?> list) {
Set<Object> loadedIds = new HashSet<>(); Set<Object> loadedIds = new HashSet<>();
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor(); BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
// collect Ids and maybe load bean cache // collect Ids and maybe load bean cache
for (Object aList : list) { for (Object bean : list) {
EntityBean loadedBean = (EntityBean) aList; EntityBean loadedBean = (EntityBean) bean;
loadedIds.add(desc.getId(loadedBean)); loadedIds.add(desc.getId(loadedBean));
} }
if (isLoadCache()) { if (isLoadCache()) {
desc.cacheBeanPutAll(list); desc.cacheBeanPutAll(list);
} }
if (lazyLoadProperty != null) { if (lazyLoadProperty != null) {
for (EntityBeanIntercept ebi : batch) { for (EntityBeanIntercept ebi : batch) {
// check if the underlying row in DB was deleted. Mark the bean as 'failed' if // check if the underlying row in DB was deleted. Mark the bean as 'failed' if
@@ -15,16 +15,13 @@ import java.util.List;
/** /**
* Request for loading Associated Many Beans. * Request for loading Associated Many Beans.
*/ */
public class LoadManyRequest extends LoadRequest { public final class LoadManyRequest extends LoadRequest {
private static final Logger logger = LoggerFactory.getLogger(LoadManyRequest.class); private static final Logger logger = LoggerFactory.getLogger(LoadManyRequest.class);
private final List<BeanCollection<?>> batch; private final List<BeanCollection<?>> batch;
private final LoadManyBuffer loadContext; private final LoadManyBuffer loadContext;
private final boolean onlyIds; private final boolean onlyIds;
private final boolean loadCache; private final boolean loadCache;
/** /**
@@ -17,16 +17,13 @@ import java.util.TreeSet;
* Holds the joins needs to support the many where predicates. * Holds the joins needs to support the many where predicates.
* These joins are independent of any 'fetch' joins on the many. * These joins are independent of any 'fetch' joins on the many.
*/ */
public class ManyWhereJoins implements Serializable { public final class ManyWhereJoins implements Serializable {
private static final long serialVersionUID = -6490181101871795417L; private static final long serialVersionUID = -6490181101871795417L;
private final TreeMap<String, PropertyJoin> joins = new TreeMap<>(); private final TreeMap<String, PropertyJoin> joins = new TreeMap<>();
private List<String> formulaJoinProperties; private List<String> formulaJoinProperties;
private boolean aggregation; private boolean aggregation;
/** /**
* 'Mode' indicating that joins added while this is true are required to be outer joins. * 'Mode' indicating that joins added while this is true are required to be outer joins.
*/ */
@@ -1,12 +0,0 @@
package io.ebeaninternal.api;
import java.io.Serializable;
/**
* Object used as a synchronization monitor that is serializable.
*/
public class Monitor implements Serializable {
private static final long serialVersionUID = -2741687226680981940L;
}
@@ -11,7 +11,7 @@ import java.util.Map;
/** /**
* Natural key entry with name value pairs for each of the properties making up the key. * Natural key entry with name value pairs for each of the properties making up the key.
*/ */
class NaturalKeyEntryBasic implements NaturalKeyEntry { final class NaturalKeyEntryBasic implements NaturalKeyEntry {
private final Map<String,Object> map = new HashMap<>(); private final Map<String,Object> map = new HashMap<>();
private final String key; private final String key;
@@ -1,6 +1,6 @@
package io.ebeaninternal.api; package io.ebeaninternal.api;
class NaturalKeyEntrySimple implements NaturalKeyEntry { final class NaturalKeyEntrySimple implements NaturalKeyEntry {
private final String key; private final String key;
private final Object val; private final Object val;
@@ -3,7 +3,7 @@ package io.ebeaninternal.api;
/** /**
* A property value pair in a natural key lookup. * A property value pair in a natural key lookup.
*/ */
public class NaturalKeyEq { public final class NaturalKeyEq {
final String property; final String property;
final Object value; final Object value;
@@ -11,28 +11,22 @@ import java.util.Set;
/** /**
* Collects the data for processing the natural key cache processing. * Collects the data for processing the natural key cache processing.
*/ */
public class NaturalKeyQueryData<T> { public final class NaturalKeyQueryData<T> {
private final BeanNaturalKey naturalKey; private final BeanNaturalKey naturalKey;
/** /**
* Only one of IN or IN PAIRS is allowed. * Only one of IN or IN PAIRS is allowed.
*/ */
private boolean hasIn; private boolean hasIn;
// IN Pairs clause - only one allowed // IN Pairs clause - only one allowed
private String inProperty0, inProperty1; private String inProperty0, inProperty1;
private List<Pairs.Entry> inPairs; private List<Pairs.Entry> inPairs;
// IN clause - only one allowed // IN clause - only one allowed
private List<Object> inValues; private List<Object> inValues;
private String inProperty; private String inProperty;
// normal EQ expressions // normal EQ expressions
private List<NaturalKeyEq> eqList; private List<NaturalKeyEq> eqList;
private NaturalKeySet set; private NaturalKeySet set;
private int hitCount; private int hitCount;
public NaturalKeyQueryData(BeanNaturalKey naturalKey) { public NaturalKeyQueryData(BeanNaturalKey naturalKey) {
@@ -4,8 +4,7 @@ import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class NaturalKeySet { public final class NaturalKeySet {
private final Map<Object, NaturalKeyEntry> map = new LinkedHashMap<>(); private final Map<Object, NaturalKeyEntry> map = new LinkedHashMap<>();
@@ -2,7 +2,7 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.type.bindcapture.BindCapture; import io.ebeaninternal.server.type.bindcapture.BindCapture;
class NoopQueryBindCapture implements SpiQueryBindCapture { final class NoopQueryBindCapture implements SpiQueryBindCapture {
@Override @Override
public boolean collectFor(long timeMicros) { public boolean collectFor(long timeMicros) {
@@ -6,7 +6,7 @@ import io.ebean.meta.QueryPlanRequest;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
class NoopQueryPlanManager implements QueryPlanManager { final class NoopQueryPlanManager implements QueryPlanManager {
@Override @Override
public void setDefaultThreshold(long thresholdMicros) { public void setDefaultThreshold(long thresholdMicros) {
@@ -3,7 +3,7 @@ package io.ebeaninternal.api;
import io.ebean.annotation.Platform; import io.ebean.annotation.Platform;
import io.ebean.util.StringHelper; import io.ebean.util.StringHelper;
public class PlatformMatch { public final class PlatformMatch {
/** /**
* Return true if the script platforms is a match/supported for the given platform. * Return true if the script platforms is a match/supported for the given platform.
@@ -15,7 +15,6 @@ public class PlatformMatch {
if (platforms == null || platforms.trim().isEmpty()) { if (platforms == null || platforms.trim().isEmpty()) {
return true; return true;
} }
// match on base platform name and platform name // match on base platform name and platform name
for (String name : StringHelper.splitNames(platforms)) { for (String name : StringHelper.splitNames(platforms)) {
if (name.equalsIgnoreCase(platform.base().name()) || name.equalsIgnoreCase(platform.name())) { if (name.equalsIgnoreCase(platform.base().name()) || name.equalsIgnoreCase(platform.name())) {
@@ -5,16 +5,9 @@ import io.ebeaninternal.server.query.SqlJoinType;
/** /**
* Represents a join required for a given property and whether than needs to be an outer join. * Represents a join required for a given property and whether than needs to be an outer join.
*/ */
public class PropertyJoin { public final class PropertyJoin {
/**
* The property name.
*/
private final String property; private final String property;
/**
* Set to true if the property needs to be an outer join.
*/
private final SqlJoinType joinType; private final SqlJoinType joinType;
public PropertyJoin(String property, SqlJoinType joinType) { public PropertyJoin(String property, SqlJoinType joinType) {
@@ -7,7 +7,7 @@ import java.util.ArrayList;
/** /**
* Used internally to handle the scoping of transactions for methods. * Used internally to handle the scoping of transactions for methods.
*/ */
public class ScopeTrans { public final class ScopeTrans {
private static final int OPCODE_ATHROW = 191; private static final int OPCODE_ATHROW = 191;
@@ -15,43 +15,32 @@ public class ScopeTrans {
* The transaction in scope (can be null). * The transaction in scope (can be null).
*/ */
private final SpiTransaction transaction; private final SpiTransaction transaction;
/** /**
* If true by default rollback on Checked exceptions. * If true by default rollback on Checked exceptions.
*/ */
private final boolean rollbackOnChecked; private final boolean rollbackOnChecked;
/** /**
* True if the transaction was created and hence should be committed * True if the transaction was created and hence should be committed
* on finally if it hasn't already been rolled back. * on finally if it hasn't already been rolled back.
*/ */
private final boolean created; private final boolean created;
/** /**
* Explicit set of Exceptions that DO NOT cause a rollback to occur. * Explicit set of Exceptions that DO NOT cause a rollback to occur.
*/ */
private final ArrayList<Class<? extends Throwable>> noRollbackFor; private final ArrayList<Class<? extends Throwable>> noRollbackFor;
/** /**
* Explicit set of Exceptions that DO cause a rollback to occur. * Explicit set of Exceptions that DO cause a rollback to occur.
*/ */
private final ArrayList<Class<? extends Throwable>> rollbackFor; private final ArrayList<Class<? extends Throwable>> rollbackFor;
private Boolean restoreBatch; private Boolean restoreBatch;
private Boolean restoreBatchOnCascade; private Boolean restoreBatchOnCascade;
private int restoreBatchSize; private int restoreBatchSize;
private Boolean restoreBatchGeneratedKeys; private Boolean restoreBatchGeneratedKeys;
private boolean restoreBatchFlushOnQuery; private boolean restoreBatchFlushOnQuery;
/** /**
* Flag set when a rollback has occurred. * Flag set when a rollback has occurred.
*/ */
private boolean rolledBack; private boolean rolledBack;
/** /**
* Flag set when nested commit has occurred. * Flag set when nested commit has occurred.
*/ */
@@ -10,15 +10,13 @@ import javax.persistence.PersistenceException;
* *
* These can be nested and internally they are pushed and popped from a stack. * These can be nested and internally they are pushed and popped from a stack.
*/ */
public class ScopedTransaction extends SpiTransactionProxy { public final class ScopedTransaction extends SpiTransactionProxy {
private final TransactionScopeManager manager; private final TransactionScopeManager manager;
/** /**
* Stack of 'nested' transactions. * Stack of 'nested' transactions.
*/ */
private final ArrayStack<ScopeTrans> stack = new ArrayStack<>(); private final ArrayStack<ScopeTrans> stack = new ArrayStack<>();
private ScopeTrans current; private ScopeTrans current;
/** /**
@@ -8,6 +8,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.event.readaudit.ReadAuditLogger; import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare; import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetricVisitor; import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.core.SpiResultSet; import io.ebeaninternal.server.core.SpiResultSet;
import io.ebeaninternal.server.core.timezone.DataTimeZone; import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.deploy.BeanDescriptor; import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -149,7 +150,7 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollect
/** /**
* Compile a query. * Compile a query.
*/ */
<T> CQuery<T> compileQuery(Query<T> query, Transaction t); <T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t);
/** /**
* Execute the findId's query but without copying the query. * Execute the findId's query but without copying the query.
@@ -54,9 +54,9 @@ public interface SpiExpression extends Expression {
void queryPlanHash(StringBuilder builder); void queryPlanHash(StringBuilder builder);
/** /**
* Return the hash value for the values that will be bound. * Build the key for bind values of the query.
*/ */
int queryBindHash(); void queryBindKey(BindValuesKey key);
/** /**
* Return true if the expression is the same with respect to bind values. * Return true if the expression is the same with respect to bind values.
@@ -8,10 +8,9 @@ import java.util.Set;
/** /**
* Property expression validation request for a given root bean type. * Property expression validation request for a given root bean type.
*/ */
public class SpiExpressionValidation { public final class SpiExpressionValidation {
private final BeanType<?> desc; private final BeanType<?> desc;
private final LinkedHashSet<String> unknown = new LinkedHashSet<>(); private final LinkedHashSet<String> unknown = new LinkedHashSet<>();
public SpiExpressionValidation(BeanType<?> desc) { public SpiExpressionValidation(BeanType<?> desc) {
@@ -84,7 +84,7 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
/** /**
* Find single attribute. * Find single attribute.
*/ */
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute"), ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false),
/** /**
* Find rowCount. * Find rowCount.
@@ -92,9 +92,14 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
COUNT(FIND_COUNT, "findCount"), COUNT(FIND_COUNT, "findCount"),
/** /**
* A subquery used as part of a where clause. * A subquery used as part of an exists where clause.
*/ */
SUBQUERY(FIND_SUBQUERY, "subquery"), SQ_EXISTS(FIND_SUBQUERY, "sqExists", false, false),
/**
* A subquery used as part of an in where clause.
*/
SQ_IN(FIND_SUBQUERY, "sqIn", false, false),
/** /**
* Delete query. * Delete query.
@@ -107,17 +112,21 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
UPDATE(FIND_UPDATE, "update", true); UPDATE(FIND_UPDATE, "update", true);
private final boolean update; private final boolean update;
private final boolean defaultSelect;
private final String profileEventId; private final String profileEventId;
private final String label; private final String label;
Type(String profileEventId, String label) { Type(String profileEventId, String label) {
this(profileEventId, label, false); this(profileEventId, label, false, true);
} }
Type(String profileEventId, String label, boolean update) { Type(String profileEventId, String label, boolean update) {
this(profileEventId, label, update, true);
}
Type(String profileEventId, String label, boolean update, boolean defaultSelect) {
this.profileEventId = profileEventId; this.profileEventId = profileEventId;
this.label = label; this.label = label;
this.update = update; this.update = update;
this.defaultSelect = defaultSelect;
} }
/** /**
@@ -127,6 +136,13 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
return update; return update;
} }
/**
* Return true if this allows default select clause.
*/
public boolean defaultSelect() {
return defaultSelect;
}
public String profileEventId() { public String profileEventId() {
return profileEventId; return profileEventId;
} }
@@ -629,13 +645,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
CQueryPlanKey prepare(SpiOrmQueryRequest<T> request); CQueryPlanKey prepare(SpiOrmQueryRequest<T> request);
/** /**
* Calculate a hash based on the bind values used in the query. * Build the key for the bind values used in the query (for l2 query cache).
* <p> * <p>
* Combined with queryPlanHash() to return getQueryHash (a unique hash for a * Combined with queryPlanHash() to return queryHash (a unique key for a query).
* query).
* </p>
*/ */
int queryBindHash(); void queryBindKey(BindValuesKey key);
/** /**
* Identifies queries that are exactly the same including bind variables. * Identifies queries that are exactly the same including bind variables.
@@ -18,7 +18,7 @@ public interface SpiQueryPlan {
String getName(); String getName();
/** /**
* The hash for the query plan. * The hash of the sql.
*/ */
String getHash(); String getHash();
@@ -20,7 +20,7 @@ import java.util.List;
* to the TransactionEventManager. * to the TransactionEventManager.
* </p> * </p>
*/ */
public class TransactionEvent implements Serializable { public final class TransactionEvent implements Serializable {
private static final long serialVersionUID = 7230903304106097120L; private static final long serialVersionUID = 7230903304106097120L;
@@ -29,13 +29,9 @@ public class TransactionEvent implements Serializable {
* the cluster). * the cluster).
*/ */
private final transient boolean local; private final transient boolean local;
private TransactionEventTable eventTables; private TransactionEventTable eventTables;
private transient List<PersistRequestBean<?>> listenerNotify; private transient List<PersistRequestBean<?>> listenerNotify;
private transient DeleteByIdMap deleteByIdMap; private transient DeleteByIdMap deleteByIdMap;
private transient CacheChangeSet changeSet; private transient CacheChangeSet changeSet;
/** /**
@@ -110,11 +106,9 @@ public class TransactionEvent implements Serializable {
* Build and return the cache changeSet. * Build and return the cache changeSet.
*/ */
public CacheChangeSet buildCacheChanges(TransactionManager manager) { public CacheChangeSet buildCacheChanges(TransactionManager manager) {
if (changeSet == null && deleteByIdMap == null && eventTables == null) { if (changeSet == null && deleteByIdMap == null && eventTables == null) {
return null; return null;
} }
if (changeSet == null) { if (changeSet == null) {
changeSet = new CacheChangeSet(); changeSet = new CacheChangeSet();
} }
@@ -28,20 +28,17 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
} }
public void add(TransactionEventTable table) { public void add(TransactionEventTable table) {
for (TableIUD iud : table.values()) { for (TableIUD iud : table.values()) {
add(iud); add(iud);
} }
} }
public void add(String table, boolean insert, boolean update, boolean delete) { public void add(String table, boolean insert, boolean update, boolean delete) {
table = table.toUpperCase(); table = table.toUpperCase();
add(new TableIUD(table, insert, update, delete)); add(new TableIUD(table, insert, update, delete));
} }
public void add(TableIUD newTableIUD) { public void add(TableIUD newTableIUD) {
TableIUD existingTableIUD = map.put(newTableIUD.getTableName(), newTableIUD); TableIUD existingTableIUD = map.put(newTableIUD.getTableName(), newTableIUD);
if (existingTableIUD != null) { if (existingTableIUD != null) {
newTableIUD.add(existingTableIUD); newTableIUD.add(existingTableIUD);
@@ -56,7 +53,7 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
return map.values(); return map.values();
} }
public static class TableIUD implements Serializable, BulkTableEvent, BinaryWritable { public static final class TableIUD implements Serializable, BulkTableEvent, BinaryWritable {
private static final long serialVersionUID = -1958317571064162089L; private static final long serialVersionUID = -1958317571064162089L;
@@ -73,12 +70,10 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
} }
public static TableIUD readBinaryMessage(BinaryReadContext dataInput) throws IOException { public static TableIUD readBinaryMessage(BinaryReadContext dataInput) throws IOException {
String table = dataInput.readUTF(); String table = dataInput.readUTF();
boolean insert = dataInput.readBoolean(); boolean insert = dataInput.readBoolean();
boolean update = dataInput.readBoolean(); boolean update = dataInput.readBoolean();
boolean delete = dataInput.readBoolean(); boolean delete = dataInput.readBoolean();
return new TableIUD(table, insert, update, delete); return new TableIUD(table, insert, update, delete);
} }
@@ -17,7 +17,7 @@ import java.util.Set;
/** /**
* Utility that converts between JSON content and simple java Maps/Lists. * Utility that converts between JSON content and simple java Maps/Lists.
*/ */
public class DJsonService implements SpiJsonService { public final class DJsonService implements SpiJsonService {
/** /**
* Write the nested Map/List as json. * Write the nested Map/List as json.
@@ -14,7 +14,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
class EJsonReader { final class EJsonReader {
static final JsonFactory json = new JsonFactory(); static final JsonFactory json = new JsonFactory();
@@ -14,7 +14,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
class EJsonWriter { final class EJsonWriter {
/** /**
* Base jsonFactory implementation used when it is not passed in. * Base jsonFactory implementation used when it is not passed in.
@@ -7,7 +7,7 @@ import java.io.Serializable;
/** /**
* Detects when content has been modified and as such needs to be persisted (included in an update). * Detects when content has been modified and as such needs to be persisted (included in an update).
*/ */
public class ModifyAwareFlag implements ModifyAwareType, Serializable { public final class ModifyAwareFlag implements ModifyAwareType, Serializable {
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
@@ -7,10 +7,9 @@ import java.util.Iterator;
/** /**
* Wraps an iterator for the purposes of detecting modifications. * Wraps an iterator for the purposes of detecting modifications.
*/ */
public class ModifyAwareIterator<E> implements Iterator<E> { public final class ModifyAwareIterator<E> implements Iterator<E> {
private final ModifyAwareType owner; private final ModifyAwareType owner;
private final Iterator<E> it; private final Iterator<E> it;
/** /**
@@ -13,12 +13,11 @@ import java.util.Objects;
/** /**
* Modify aware wrapper of a list. * Modify aware wrapper of a list.
*/ */
public class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable { public final class ModifyAwareList<E> implements List<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
final List<E> list; final List<E> list;
final ModifyAwareType owner; final ModifyAwareType owner;
public ModifyAwareList(List<E> list) { public ModifyAwareList(List<E> list) {
@@ -7,10 +7,9 @@ import java.util.ListIterator;
/** /**
* Modify aware wrapper of a ListIterator. * Modify aware wrapper of a ListIterator.
*/ */
public class ModifyAwareListIterator<E> implements ListIterator<E> { public final class ModifyAwareListIterator<E> implements ListIterator<E> {
final ModifyAwareType owner; final ModifyAwareType owner;
final ListIterator<E> iterator; final ListIterator<E> iterator;
public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) { public ModifyAwareListIterator(ModifyAwareType owner, ListIterator<E> iterator) {
@@ -12,15 +12,11 @@ import java.util.Set;
/** /**
* Map that is wraps an underlying map for the purpose of detecting changes. * Map that is wraps an underlying map for the purpose of detecting changes.
*/ */
public class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable { public final class ModifyAwareMap<K, V> implements Map<K, V>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
final ModifyAwareType owner; final ModifyAwareType owner;
/**
* The underlying map.
*/
final Map<K, V> map; final Map<K, V> map;
public ModifyAwareMap(Map<K, V> underlying) { public ModifyAwareMap(Map<K, V> underlying) {
@@ -11,13 +11,12 @@ import java.util.Set;
/** /**
* Wraps a Set for the purposes of detecting modifications. * Wraps a Set for the purposes of detecting modifications.
*/ */
public class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable { public final class ModifyAwareSet<E> implements Set<E>, ModifyAwareType, Serializable {
private static final long serialVersionUID = 1; private static final long serialVersionUID = 1;
protected final ModifyAwareType owner; private final ModifyAwareType owner;
private final Set<E> set;
protected final Set<E> set;
/** /**
* Create as top level with it's own ModifyAwareOwner instance wrapping the given Set. * Create as top level with it's own ModifyAwareOwner instance wrapping the given Set.
@@ -8,7 +8,7 @@ import io.ebeaninternal.server.core.DefaultContainer;
/** /**
* Default container factory found via service loader. * Default container factory found via service loader.
*/ */
public class DContainerFactory implements SpiContainerFactory { public final class DContainerFactory implements SpiContainerFactory {
@Override @Override
public SpiContainer create(ContainerConfig containerConfig) { public SpiContainer create(ContainerConfig containerConfig) {
@@ -5,7 +5,7 @@ import io.ebeaninternal.api.SpiQuery;
/** /**
* Noop service when AutoTuneService is not available. * Noop service when AutoTuneService is not available.
*/ */
public class NoAutoTuneService implements AutoTuneService { public final class NoAutoTuneService implements AutoTuneService {
@Override @Override
public void startup() { public void startup() {
@@ -8,10 +8,9 @@ import java.util.Collection;
/** /**
* Change to remove bean from L2 cache. * Change to remove bean from L2 cache.
*/ */
class CacheChangeBeanRemove implements CacheChange { final class CacheChangeBeanRemove implements CacheChange {
private final BeanDescriptor<?> descriptor; private final BeanDescriptor<?> descriptor;
private final Collection<Object> ids; private final Collection<Object> ids;
CacheChangeBeanRemove(Object id, BeanDescriptor<?> descriptor) { CacheChangeBeanRemove(Object id, BeanDescriptor<?> descriptor) {
@@ -7,7 +7,7 @@ import java.util.Map;
/** /**
* Put a new bean entry into the cache. * Put a new bean entry into the cache.
*/ */
class CacheChangeBeanUpdate implements CacheChange { final class CacheChangeBeanUpdate implements CacheChange {
private final BeanDescriptor<?> desc; private final BeanDescriptor<?> desc;
private final String key; private final String key;
@@ -5,7 +5,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
/** /**
* Change the natural key mapping for a bean. * Change the natural key mapping for a bean.
*/ */
class CacheChangeNaturalKeyPut implements CacheChange { final class CacheChangeNaturalKeyPut implements CacheChange {
private final BeanDescriptor<?> descriptor; private final BeanDescriptor<?> descriptor;
private final String key; private final String key;
@@ -14,18 +14,13 @@ import java.util.Set;
/** /**
* List of changes to be applied to L2 cache. * List of changes to be applied to L2 cache.
*/ */
public class CacheChangeSet { public final class CacheChangeSet {
private final List<CacheChange> entries = new ArrayList<>(); private final List<CacheChange> entries = new ArrayList<>();
private final Set<String> touchedTables = new HashSet<>(); private final Set<String> touchedTables = new HashSet<>();
private final Set<BeanDescriptor<?>> queryCaches = new HashSet<>(); private final Set<BeanDescriptor<?>> queryCaches = new HashSet<>();
private final Set<BeanDescriptor<?>> beanCaches = new HashSet<>(); private final Set<BeanDescriptor<?>> beanCaches = new HashSet<>();
private final Map<BeanDescriptor<?>, CacheChangeBeanRemove> beanRemoveMap = new HashMap<>(); private final Map<BeanDescriptor<?>, CacheChangeBeanRemove> beanRemoveMap = new HashMap<>();
private final Map<ManyKey, ManyChange> manyChangeMap = new HashMap<>(); private final Map<ManyKey, ManyChange> manyChangeMap = new HashMap<>();
/** /**
@@ -173,14 +168,11 @@ public class CacheChangeSet {
/** /**
* Changes for a specific many property. * Changes for a specific many property.
*/ */
private static class ManyChange implements CacheChange { private static final class ManyChange implements CacheChange {
final ManyKey key; final ManyKey key;
final Set<Object> removes = new HashSet<>(); final Set<Object> removes = new HashSet<>();
final Map<Object, CachedManyIds> puts = new LinkedHashMap<>(); final Map<Object, CachedManyIds> puts = new LinkedHashMap<>();
boolean clear; boolean clear;
ManyChange(ManyKey key) { ManyChange(ManyKey key) {
@@ -229,10 +221,9 @@ public class CacheChangeSet {
/** /**
* Key for changes on a many property. * Key for changes on a many property.
*/ */
private static class ManyKey { private static final class ManyKey {
private final BeanDescriptor<?> desc; private final BeanDescriptor<?> desc;
private final String manyProperty; private final String manyProperty;
ManyKey(BeanDescriptor<?> desc, String manyProperty) { ManyKey(BeanDescriptor<?> desc, String manyProperty) {
@@ -10,18 +10,13 @@ import io.ebeaninternal.server.cluster.ClusterManager;
/** /**
* Configuration options when creating the default cache manager. * Configuration options when creating the default cache manager.
*/ */
public class CacheManagerOptions { public final class CacheManagerOptions {
private final ClusterManager clusterManager; private final ClusterManager clusterManager;
private final DatabaseConfig databaseConfig; private final DatabaseConfig databaseConfig;
private final boolean localL2Caching; private final boolean localL2Caching;
private CurrentTenantProvider currentTenantProvider; private CurrentTenantProvider currentTenantProvider;
private QueryCacheEntryValidate queryCacheEntryValidate; private QueryCacheEntryValidate queryCacheEntryValidate;
private ServerCacheFactory cacheFactory = new DefaultServerCacheFactory(); private ServerCacheFactory cacheFactory = new DefaultServerCacheFactory();
private ServerCacheOptions beanDefault = new ServerCacheOptions(); private ServerCacheOptions beanDefault = new ServerCacheOptions();
private ServerCacheOptions queryDefault = new ServerCacheOptions(); private ServerCacheOptions queryDefault = new ServerCacheOptions();
@@ -11,13 +11,12 @@ import java.util.Map;
/** /**
* Data held in the bean cache for cached beans. * Data held in the bean cache for cached beans.
*/ */
public class CachedBeanData implements Externalizable { public final class CachedBeanData implements Externalizable {
private long whenCreated; private long whenCreated;
private long version; private long version;
private String discValue; private String discValue;
private Map<String, Object> data; private Map<String, Object> data;
/** /**
* The sharable bean is effectively transient (near cache only). * The sharable bean is effectively transient (near cache only).
*/ */
@@ -9,10 +9,9 @@ import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
public class CachedBeanDataFromBean { public final class CachedBeanDataFromBean {
public static CachedBeanData extract(BeanDescriptor<?> desc, EntityBean bean) { public static CachedBeanData extract(BeanDescriptor<?> desc, EntityBean bean) {
EntityBeanIntercept ebi = bean._ebean_getIntercept(); EntityBeanIntercept ebi = bean._ebean_getIntercept();
Map<String, Object> data = new LinkedHashMap<>(); Map<String, Object> data = new LinkedHashMap<>();
@@ -46,7 +45,6 @@ public class CachedBeanDataFromBean {
} }
private static EntityBean createSharableBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept beanEbi) { private static EntityBean createSharableBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept beanEbi) {
if (!desc.isCacheSharableBeans() || !beanEbi.isFullyLoadedBean()) { if (!desc.isCacheSharableBeans() || !beanEbi.isFullyLoadedBean()) {
return null; return null;
} }
@@ -7,30 +7,24 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty; import io.ebeaninternal.server.deploy.BeanProperty;
import io.ebeaninternal.server.deploy.BeanPropertyAssocMany; import io.ebeaninternal.server.deploy.BeanPropertyAssocMany;
public class CachedBeanDataToBean { public final class CachedBeanDataToBean {
public static void load(BeanDescriptor<?> desc, EntityBean bean, CachedBeanData cacheBeanData, PersistenceContext context) { public static void load(BeanDescriptor<?> desc, EntityBean bean, CachedBeanData cacheBeanData, PersistenceContext context) {
EntityBeanIntercept ebi = bean._ebean_getIntercept(); EntityBeanIntercept ebi = bean._ebean_getIntercept();
// any future lazy loading skips L2 bean cache // any future lazy loading skips L2 bean cache
ebi.setLoadedFromCache(true); ebi.setLoadedFromCache(true);
BeanProperty idProperty = desc.getIdProperty(); BeanProperty idProperty = desc.getIdProperty();
if (desc.getInheritInfo() != null) { if (desc.getInheritInfo() != null) {
desc = desc.getInheritInfo().readType(bean.getClass()).desc(); desc = desc.getInheritInfo().readType(bean.getClass()).desc();
} }
if (idProperty != null) { if (idProperty != null) {
// load the id property // load the id property
loadProperty(bean, cacheBeanData, ebi, idProperty, context); loadProperty(bean, cacheBeanData, ebi, idProperty, context);
} }
// load the non-many properties // load the non-many properties
for (BeanProperty prop : desc.propertiesNonMany()) { for (BeanProperty prop : desc.propertiesNonMany()) {
loadProperty(bean, cacheBeanData, ebi, prop, context); loadProperty(bean, cacheBeanData, ebi, prop, context);
} }
for (BeanPropertyAssocMany<?> prop : desc.propertiesMany()) { for (BeanPropertyAssocMany<?> prop : desc.propertiesMany()) {
if (prop.isElementCollection()) { if (prop.isElementCollection()) {
loadProperty(bean, cacheBeanData, ebi, prop, context); loadProperty(bean, cacheBeanData, ebi, prop, context);
@@ -38,12 +32,10 @@ public class CachedBeanDataToBean {
prop.createReferenceIfNull(bean); prop.createReferenceIfNull(bean);
} }
} }
ebi.setLoadedLazy(); ebi.setLoadedLazy();
} }
private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop, PersistenceContext context) { private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop, PersistenceContext context) {
if (cacheBeanData.isLoaded(prop.getName())) { if (cacheBeanData.isLoaded(prop.getName())) {
if (!ebi.isLoadedProperty(prop.getPropertyIndex())) { if (!ebi.isLoadedProperty(prop.getPropertyIndex())) {
Object value = cacheBeanData.getData(prop.getName()); Object value = cacheBeanData.getData(prop.getName());
@@ -10,7 +10,7 @@ import java.io.ObjectOutput;
* <p> * <p>
* Put into L2 cache such that we know the type of a bean with inheritance. * Put into L2 cache such that we know the type of a bean with inheritance.
*/ */
public class CachedBeanId implements Externalizable { public final class CachedBeanId implements Externalizable {
private String discValue; private String discValue;
private Object id; private Object id;
@@ -13,7 +13,7 @@ import java.util.List;
* This is effectively just the Id values for each of the beans in the collection. * This is effectively just the Id values for each of the beans in the collection.
* </p> * </p>
*/ */
public class CachedManyIds implements Externalizable { public final class CachedManyIds implements Externalizable {
private List<Object> idList; private List<Object> idList;
@@ -13,7 +13,7 @@ import java.util.List;
* Used to hide the Supplier part of the SpiCacheManager API from public use. * Used to hide the Supplier part of the SpiCacheManager API from public use.
* </p> * </p>
*/ */
public class DefaultCacheAdapter implements ServerCacheManager { public final class DefaultCacheAdapter implements ServerCacheManager {
private final SpiCacheManager cacheManager; private final SpiCacheManager cacheManager;
@@ -23,14 +23,13 @@ import java.util.concurrent.locks.ReentrantLock;
/** /**
* Manages the construction of caches. * Manages the construction of caches.
*/ */
class DefaultCacheHolder { final class DefaultCacheHolder {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL"); private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>(); private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
private final ServerCacheFactory cacheFactory; private final ServerCacheFactory cacheFactory;
private final ServerCacheOptions beanDefault; private final ServerCacheOptions beanDefault;
private final ServerCacheOptions queryDefault; private final ServerCacheOptions queryDefault;
@@ -76,7 +75,6 @@ class DefaultCacheHolder {
* Return the cache for a given bean type. * Return the cache for a given bean type.
*/ */
private ServerCache getCacheInternal(Class<?> beanType, ServerCacheType type, String collectionProperty) { private ServerCache getCacheInternal(Class<?> beanType, ServerCacheType type, String collectionProperty) {
String shortName = key(beanType.getSimpleName(), collectionProperty, type); String shortName = key(beanType.getSimpleName(), collectionProperty, type);
String fullKey = key(beanType.getName(), collectionProperty, type); String fullKey = key(beanType.getName(), collectionProperty, type);
return allCaches.computeIfAbsent(fullKey, s -> createCache(beanType, type, fullKey, shortName)); return allCaches.computeIfAbsent(fullKey, s -> createCache(beanType, type, fullKey, shortName));
@@ -143,10 +141,8 @@ class DefaultCacheHolder {
} }
private ServerCacheOptions getBeanOptions(Class<?> cls) { private ServerCacheOptions getBeanOptions(Class<?> cls) {
Cache cache = cls.getAnnotation(Cache.class); Cache cache = cls.getAnnotation(Cache.class);
boolean nearCache = (cache != null && cache.nearCache()); boolean nearCache = (cache != null && cache.nearCache());
CacheBeanTuning tuning = cls.getAnnotation(CacheBeanTuning.class); CacheBeanTuning tuning = cls.getAnnotation(CacheBeanTuning.class);
if (tuning != null) { if (tuning != null) {
return new ServerCacheOptions(nearCache, tuning).applyDefaults(beanDefault); return new ServerCacheOptions(nearCache, tuning).applyDefaults(beanDefault);
@@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.Serializable; import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
@@ -37,8 +38,7 @@ public class DefaultServerCache implements ServerCache {
/** /**
* The underlying map (ConcurrentHashMap or similar) * The underlying map (ConcurrentHashMap or similar)
*/ */
protected final Map<Object, CacheEntry> map; protected final Map<Object, SoftReference<CacheEntry>> map;
protected final CountMetric hitCount; protected final CountMetric hitCount;
protected final CountMetric missCount; protected final CountMetric missCount;
protected final CountMetric putCount; protected final CountMetric putCount;
@@ -48,16 +48,11 @@ public class DefaultServerCache implements ServerCache {
protected final String name; protected final String name;
protected final String shortName; protected final String shortName;
private final int maxSize;
private int maxSize;
private final int trimFrequency; private final int trimFrequency;
private final int maxIdleSecs;
private int maxIdleSecs; private final int maxSecsToLive;
private final TenantAwareKey tenantAwareKey;
private int maxSecsToLive;
private TenantAwareKey tenantAwareKey;
public DefaultServerCache(DefaultServerCacheConfig config) { public DefaultServerCache(DefaultServerCacheConfig config) {
this.name = config.getName(); this.name = config.getName();
@@ -70,7 +65,6 @@ public class DefaultServerCache implements ServerCache {
this.trimFrequency = config.determineTrimFrequency(); this.trimFrequency = config.determineTrimFrequency();
MetricFactory factory = MetricFactory.get(); MetricFactory factory = MetricFactory.get();
String prefix = "l2n."; String prefix = "l2n.";
this.hitCount = factory.createCountMetric(prefix + shortName + ".hit"); this.hitCount = factory.createCountMetric(prefix + shortName + ".hit");
this.missCount = factory.createCountMetric(prefix + shortName + ".miss"); this.missCount = factory.createCountMetric(prefix + shortName + ".miss");
@@ -81,9 +75,7 @@ public class DefaultServerCache implements ServerCache {
} }
public void periodicTrim(BackgroundExecutor executor) { public void periodicTrim(BackgroundExecutor executor) {
EvictionRunnable trim = new EvictionRunnable(); EvictionRunnable trim = new EvictionRunnable();
// default to trimming the cache every 60 seconds // default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency; long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS); executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
@@ -101,11 +93,9 @@ public class DefaultServerCache implements ServerCache {
@Override @Override
public ServerCacheStatistics getStatistics(boolean reset) { public ServerCacheStatistics getStatistics(boolean reset) {
ServerCacheStatistics cacheStats = new ServerCacheStatistics(); ServerCacheStatistics cacheStats = new ServerCacheStatistics();
cacheStats.setCacheName(name); cacheStats.setCacheName(name);
cacheStats.setMaxSize(maxSize); cacheStats.setMaxSize(maxSize);
cacheStats.setSize(size()); cacheStats.setSize(size());
cacheStats.setHitCount(hitCount.get(reset)); cacheStats.setHitCount(hitCount.get(reset));
cacheStats.setMissCount(missCount.get(reset)); cacheStats.setMissCount(missCount.get(reset));
@@ -113,7 +103,6 @@ public class DefaultServerCache implements ServerCache {
cacheStats.setRemoveCount(removeCount.get(reset)); cacheStats.setRemoveCount(removeCount.get(reset));
cacheStats.setClearCount(clearCount.get(reset)); cacheStats.setClearCount(clearCount.get(reset));
cacheStats.setEvictCount(evictCount.get(reset)); cacheStats.setEvictCount(evictCount.get(reset));
return cacheStats; return cacheStats;
} }
@@ -133,10 +122,8 @@ public class DefaultServerCache implements ServerCache {
@Override @Override
public int getHitRatio() { public int getHitRatio() {
long mc = missCount.get(false); long mc = missCount.get(false);
long hc = hitCount.get(false); long hc = hitCount.get(false);
long totalCount = hc + mc; long totalCount = hc + mc;
if (totalCount == 0) { if (totalCount == 0) {
return 0; return 0;
@@ -177,7 +164,6 @@ public class DefaultServerCache implements ServerCache {
*/ */
@Override @Override
public Object get(Object id) { public Object get(Object id) {
CacheEntry entry = getCacheEntry(id); CacheEntry entry = getCacheEntry(id);
if (entry == null) { if (entry == null) {
missCount.increment(); missCount.increment();
@@ -199,7 +185,8 @@ public class DefaultServerCache implements ServerCache {
* Get the cache entry - override for query cache to validate dependent tables. * Get the cache entry - override for query cache to validate dependent tables.
*/ */
protected CacheEntry getCacheEntry(Object id) { protected CacheEntry getCacheEntry(Object id) {
return map.get(key(id)); final SoftReference<CacheEntry> ref = map.get(key(id));
return ref != null ? ref.get() : null;
} }
@Override @Override
@@ -213,7 +200,7 @@ public class DefaultServerCache implements ServerCache {
@Override @Override
public void put(Object id, Object value) { public void put(Object id, Object value) {
Object key = key(id); Object key = key(id);
map.put(key, new CacheEntry(key, value)); map.put(key, new SoftReference<>(new CacheEntry(key, value)));
putCount.increment(); putCount.increment();
} }
@@ -222,8 +209,8 @@ public class DefaultServerCache implements ServerCache {
*/ */
@Override @Override
public void remove(Object id) { public void remove(Object id) {
CacheEntry entry = map.remove(key(id)); SoftReference<CacheEntry> entry = map.remove(key(id));
if (entry != null) { if (entry != null && entry.get() != null) {
removeCount.increment(); removeCount.increment();
} }
} }
@@ -250,74 +237,69 @@ public class DefaultServerCache implements ServerCache {
* Run the eviction based on Idle time, Time to live and LRU last access. * Run the eviction based on Idle time, Time to live and LRU last access.
*/ */
public void runEviction() { public void runEviction() {
long trimForMaxSize; long trimForMaxSize;
if (maxSize == 0) { if (maxSize == 0) {
trimForMaxSize = 0; trimForMaxSize = 0;
} else { } else {
trimForMaxSize = size() - maxSize; trimForMaxSize = size() - maxSize;
} }
if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) { if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
// nothing to trim on this cache // nothing to trim on this cache
return; return;
} }
long startNanos = System.nanoTime(); long startNanos = System.nanoTime();
long trimmedByIdle = 0; long trimmedByIdle = 0;
long trimmedByGC = 0;
long trimmedByTTL = 0; long trimmedByTTL = 0;
long trimmedByLRU = 0; long trimmedByLRU = 0;
List<CacheEntry> activeList = new ArrayList<>(map.size()); List<CacheEntry> activeList = new ArrayList<>(map.size());
long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs); long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive); long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive);
Iterator<SoftReference<CacheEntry>> it = map.values().iterator();
Iterator<CacheEntry> it = map.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
CacheEntry cacheEntry = it.next(); SoftReference<CacheEntry> ref = it.next();
if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) { final CacheEntry cacheEntry = ref.get();
if (cacheEntry == null) {
it.remove();
trimmedByGC++;
} else if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) {
it.remove(); it.remove();
trimmedByIdle++; trimmedByIdle++;
} else if (maxSecsToLive > 0 && ttlExpireNano > cacheEntry.getCreateTime()) { } else if (maxSecsToLive > 0 && ttlExpireNano > cacheEntry.getCreateTime()) {
it.remove(); it.remove();
trimmedByTTL++; trimmedByTTL++;
} else if (trimForMaxSize > 0) { } else if (trimForMaxSize > 0) {
activeList.add(cacheEntry); activeList.add(cacheEntry);
} }
} }
if (trimForMaxSize > 0 && activeList.size() > maxSize) {
if (trimForMaxSize > 0) { // sort into last access time ascending
trimmedByLRU = activeList.size() - maxSize; activeList.sort(BY_LAST_ACCESS);
if (trimmedByLRU > 0) { int trimSize = getTrimSize();
// sort into last access time ascending for (int i = trimSize; i < activeList.size(); i++) {
activeList.sort(BY_LAST_ACCESS); // remove if still in the cache
int trimSize = getTrimSize(); if (map.remove(activeList.get(i).getKey()) != null) {
for (int i = trimSize; i < activeList.size(); i++) { trimmedByLRU++;
// remove if still in the cache
map.remove(activeList.get(i).getKey());
} }
} }
} }
evictCount.add(trimmedByIdle); evictCount.add(trimmedByIdle);
evictCount.add(trimmedByGC);
evictCount.add(trimmedByTTL); evictCount.add(trimmedByTTL);
evictCount.add(trimmedByLRU); evictCount.add(trimmedByLRU);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS); long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}]" logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}] gc[{}]",
, name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU); name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU, trimmedByGC);
} }
} }
/** /**
* Runnable that calls the eviction routine. * Runnable that calls the eviction routine.
*/ */
public class EvictionRunnable implements Runnable { public final class EvictionRunnable implements Runnable {
@Override @Override
public void run() { public void run() {
@@ -328,7 +310,7 @@ public class DefaultServerCache implements ServerCache {
/** /**
* Comparator for sorting by last access time. * Comparator for sorting by last access time.
*/ */
public static class CompareByLastAccess implements Comparator<CacheEntry>, Serializable { public static final class CompareByLastAccess implements Comparator<CacheEntry>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -341,7 +323,7 @@ public class DefaultServerCache implements ServerCache {
/** /**
* Wraps the value to additionally hold createTime and lastAccessTime and hit counter. * Wraps the value to additionally hold createTime and lastAccessTime and hit counter.
*/ */
public static class CacheEntry { public static final class CacheEntry {
private final Object key; private final Object key;
private final Object value; private final Object value;
@@ -4,26 +4,26 @@ import io.ebean.cache.QueryCacheEntryValidate;
import io.ebean.cache.ServerCacheConfig; import io.ebean.cache.ServerCacheConfig;
import io.ebean.cache.ServerCacheOptions; import io.ebean.cache.ServerCacheOptions;
import io.ebean.config.CurrentTenantProvider; import io.ebean.config.CurrentTenantProvider;
import io.ebeaninternal.server.cache.DefaultServerCache.CacheEntry;
import java.lang.ref.SoftReference;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class DefaultServerCacheConfig { public final class DefaultServerCacheConfig {
private final ServerCacheConfig config; private final ServerCacheConfig config;
private final int maxSize;
private int maxSize; private final int maxIdleSecs;
private int maxIdleSecs; private final int maxSecsToLive;
private int maxSecsToLive; private final int trimFrequency;
private int trimFrequency; private final Map<Object, SoftReference<CacheEntry>> map;
private Map<Object, DefaultServerCache.CacheEntry> map;
public DefaultServerCacheConfig(ServerCacheConfig config) { public DefaultServerCacheConfig(ServerCacheConfig config) {
this(config, new ConcurrentHashMap<>()); this(config, new ConcurrentHashMap<>());
} }
public DefaultServerCacheConfig(ServerCacheConfig config, Map<Object, DefaultServerCache.CacheEntry> map) { public DefaultServerCacheConfig(ServerCacheConfig config, Map<Object, SoftReference<CacheEntry>> map) {
this.config = config; this.config = config;
this.map = map; this.map = map;
@@ -50,7 +50,7 @@ public class DefaultServerCacheConfig {
return config.getShortName(); return config.getShortName();
} }
public Map<Object, DefaultServerCache.CacheEntry> getMap() { public Map<Object, SoftReference<CacheEntry>> getMap() {
return map; return map;
} }
@@ -11,7 +11,7 @@ import io.ebean.cache.ServerCacheNotify;
/** /**
* Default implementation of ServerCacheFactory. * Default implementation of ServerCacheFactory.
*/ */
class DefaultServerCacheFactory implements ServerCacheFactory { final class DefaultServerCacheFactory implements ServerCacheFactory {
private final BackgroundExecutor executor; private final BackgroundExecutor executor;
@@ -31,7 +31,6 @@ class DefaultServerCacheFactory implements ServerCacheFactory {
@Override @Override
public ServerCache createCache(ServerCacheConfig config) { public ServerCache createCache(ServerCacheConfig config) {
DefaultServerCache cache; DefaultServerCache cache;
if (config.isQueryCache()) { if (config.isQueryCache()) {
// use a server cache aware of extra validation and QueryCacheEntry // use a server cache aware of extra validation and QueryCacheEntry
@@ -19,18 +19,14 @@ import java.util.Map;
/** /**
* Manages the bean and query caches. * Manages the bean and query caches.
*/ */
public class DefaultServerCacheManager implements SpiCacheManager { public final class DefaultServerCacheManager implements SpiCacheManager {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.REGION"); private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.REGION");
private final Map<String, SpiCacheRegion> regionMap = new HashMap<>(); private final Map<String, SpiCacheRegion> regionMap = new HashMap<>();
private final ClusterManager clusterManager; private final ClusterManager clusterManager;
private final DefaultCacheHolder cacheHolder; private final DefaultCacheHolder cacheHolder;
private final boolean localL2Caching; private final boolean localL2Caching;
private final String serverName; private final String serverName;
/** /**
@@ -8,7 +8,7 @@ import io.ebean.config.DatabaseConfig;
/** /**
* Default implementation of ServerCachePlugin. * Default implementation of ServerCachePlugin.
*/ */
public class DefaultServerCachePlugin implements ServerCachePlugin { public final class DefaultServerCachePlugin implements ServerCachePlugin {
/** /**
* Creates the default ServerCacheFactory. * Creates the default ServerCacheFactory.
@@ -3,6 +3,8 @@ package io.ebeaninternal.server.cache;
import io.ebean.cache.QueryCacheEntry; import io.ebean.cache.QueryCacheEntry;
import io.ebean.cache.QueryCacheEntryValidate; import io.ebean.cache.QueryCacheEntryValidate;
import java.lang.ref.SoftReference;
/** /**
* Server cache for query caching. * Server cache for query caching.
* <p> * <p>
@@ -27,7 +29,8 @@ public class DefaultServerQueryCache extends DefaultServerCache {
@Override @Override
protected CacheEntry getCacheEntry(Object id) { protected CacheEntry getCacheEntry(Object id) {
Object key = key(id); Object key = key(id);
CacheEntry entry = map.get(key); final SoftReference<CacheEntry> ref = map.get(key);
CacheEntry entry = ref != null ? ref.get() : null;
if (entry == null) { if (entry == null) {
return null; return null;
} }
@@ -12,11 +12,10 @@ import java.util.List;
/** /**
* Cache events broadcast across the cluster. * Cache events broadcast across the cluster.
*/ */
public class RemoteCacheEvent implements BinaryWritable { public final class RemoteCacheEvent implements BinaryWritable {
private boolean clearAll; private final boolean clearAll;
private final List<String> clearCaches;
private List<String> clearCaches;
/** /**
* Clear all the caches. * Clear all the caches.
@@ -57,10 +56,8 @@ public class RemoteCacheEvent implements BinaryWritable {
} }
public static RemoteCacheEvent readBinaryMessage(BinaryReadContext dataInput) throws IOException { public static RemoteCacheEvent readBinaryMessage(BinaryReadContext dataInput) throws IOException {
boolean clearAll = dataInput.readBoolean(); boolean clearAll = dataInput.readBoolean();
int size = dataInput.readInt(); int size = dataInput.readInt();
List<String> clearCache = null; List<String> clearCache = null;
if (size > 0) { if (size > 0) {
clearCache = new ArrayList<>(size); clearCache = new ArrayList<>(size);
@@ -68,7 +65,6 @@ public class RemoteCacheEvent implements BinaryWritable {
clearCache.add(dataInput.readUTF()); clearCache.add(dataInput.readUTF());
} }
} }
return new RemoteCacheEvent(clearAll, clearCache); return new RemoteCacheEvent(clearAll, clearCache);
} }
@@ -14,21 +14,14 @@ import java.util.Map;
/** /**
* Builds JSON document for a bean change. * Builds JSON document for a bean change.
*/ */
class ChangeJsonBuilder { final class ChangeJsonBuilder {
protected final JsonFactory jsonFactory = new JsonFactory(); private final JsonFactory jsonFactory = new JsonFactory();
protected final JsonContext json;
ChangeJsonBuilder(JsonContext json) {
this.json = json;
}
/** /**
* Write the bean change as JSON. * Write the bean change as JSON.
*/ */
void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet) throws IOException { void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet) throws IOException {
try (JsonGenerator generator = jsonFactory.createGenerator(writer)) { try (JsonGenerator generator = jsonFactory.createGenerator(writer)) {
writeBeanChange(generator, bean, changeSet); writeBeanChange(generator, bean, changeSet);
generator.flush(); generator.flush();
@@ -39,9 +32,7 @@ class ChangeJsonBuilder {
* Write the bean change as JSON document containing the transaction header details. * Write the bean change as JSON document containing the transaction header details.
*/ */
private void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet) throws IOException { private void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet) throws IOException {
gen.writeStartObject(); gen.writeStartObject();
gen.writeNumberField("ts", bean.getEventTime()); gen.writeNumberField("ts", bean.getEventTime());
gen.writeStringField("change", bean.getEvent().getCode()); gen.writeStringField("change", bean.getEvent().getCode());
gen.writeStringField("type", bean.getType()); gen.writeStringField("type", bean.getType());
@@ -49,9 +40,7 @@ class ChangeJsonBuilder {
if (bean.getTenantId() != null) { if (bean.getTenantId() != null) {
gen.writeStringField("tenantId", bean.getTenantId().toString()); gen.writeStringField("tenantId", bean.getTenantId().toString());
} }
writeBeanTransactionDetails(gen, changeSet); writeBeanTransactionDetails(gen, changeSet);
writeBeanValues(gen, bean); writeBeanValues(gen, bean);
gen.writeEndObject(); gen.writeEndObject();
} }
@@ -60,7 +49,6 @@ class ChangeJsonBuilder {
* Denormalise by writing the transaction header details. * Denormalise by writing the transaction header details.
*/ */
private void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet) throws IOException { private void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet) throws IOException {
String source = changeSet.getSource(); String source = changeSet.getSource();
if (source != null) { if (source != null) {
gen.writeStringField("source", source); gen.writeStringField("source", source);
@@ -87,12 +75,10 @@ class ChangeJsonBuilder {
* For insert and update write the new/old values. * For insert and update write the new/old values.
*/ */
private void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException { private void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException {
if (bean.getEvent() != ChangeType.DELETE) { if (bean.getEvent() != ChangeType.DELETE) {
gen.writeFieldName("data"); gen.writeFieldName("data");
gen.writeRaw(":"); gen.writeRaw(":");
gen.writeRaw(bean.getData()); gen.writeRaw(bean.getData());
String oldData = bean.getOldData(); String oldData = bean.getOldData();
if (oldData != null) { if (oldData != null) {
gen.writeRaw(",\"oldData\":"); gen.writeRaw(",\"oldData\":");
@@ -15,12 +15,12 @@ import java.util.Properties;
/** /**
* Simply logs the change sets in JSON form to logger named <code>io.ebean.ChangeLog</code>. * Simply logs the change sets in JSON form to logger named <code>io.ebean.ChangeLog</code>.
*/ */
public class DefaultChangeLogListener implements ChangeLogListener, Plugin { public final class DefaultChangeLogListener implements ChangeLogListener, Plugin {
/** /**
* The usual application specific logger. * The usual application specific logger.
*/ */
protected static final Logger logger = LoggerFactory.getLogger(DefaultChangeLogListener.class); private static final Logger logger = LoggerFactory.getLogger(DefaultChangeLogListener.class);
/** /**
* The named logger we send the change set payload to. Can be externally configured as desired. * The named logger we send the change set payload to. Can be externally configured as desired.
@@ -45,8 +45,7 @@ public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
*/ */
@Override @Override
public void configure(SpiServer server) { public void configure(SpiServer server) {
jsonBuilder = new ChangeJsonBuilder(server.json()); jsonBuilder = new ChangeJsonBuilder();
Properties properties = server.getServerConfig().getProperties(); Properties properties = server.getServerConfig().getProperties();
if (properties != null) { if (properties != null) {
String bufferSize = properties.getProperty("ebean.changeLog.bufferSize"); String bufferSize = properties.getProperty("ebean.changeLog.bufferSize");
@@ -11,7 +11,7 @@ import io.ebean.event.changelog.ChangeSet;
* on the changeSet. * on the changeSet.
* </p> * </p>
*/ */
public class DefaultChangeLogPrepare implements ChangeLogPrepare { public final class DefaultChangeLogPrepare implements ChangeLogPrepare {
/** /**
* Just return true to send change set through to the logger. * Just return true to send change set through to the logger.
@@ -14,10 +14,9 @@ import java.util.Set;
/** /**
* Default implementation of ChangeLogRegister. * Default implementation of ChangeLogRegister.
*/ */
public class DefaultChangeLogRegister implements ChangeLogRegister { public final class DefaultChangeLogRegister implements ChangeLogRegister {
private static final BasicFilter INCLUDE_INSERTS = new BasicFilter(true); private static final BasicFilter INCLUDE_INSERTS = new BasicFilter(true);
private static final BasicFilter EXCLUDE_INSERTS = new BasicFilter(false); private static final BasicFilter EXCLUDE_INSERTS = new BasicFilter(false);
private final boolean defaultInsertsInclude; private final boolean defaultInsertsInclude;
@@ -31,20 +30,16 @@ public class DefaultChangeLogRegister implements ChangeLogRegister {
@Override @Override
public ChangeLogFilter getChangeFilter(Class<?> beanType) { public ChangeLogFilter getChangeFilter(Class<?> beanType) {
ChangeLog changeLog = getChangeLog(beanType); ChangeLog changeLog = getChangeLog(beanType);
if (changeLog == null) { if (changeLog == null) {
return null; return null;
} }
String[] updatesThatInclude = changeLog.updatesThatInclude(); String[] updatesThatInclude = changeLog.updatesThatInclude();
if (updatesThatInclude.length == 0) { if (updatesThatInclude.length == 0) {
return insertModeInclude(changeLog.inserts()) ? INCLUDE_INSERTS : EXCLUDE_INSERTS; return insertModeInclude(changeLog.inserts()) ? INCLUDE_INSERTS : EXCLUDE_INSERTS;
} }
Set<String> updateProps = new HashSet<>(); Set<String> updateProps = new HashSet<>();
Collections.addAll(updateProps, updatesThatInclude); Collections.addAll(updateProps, updatesThatInclude);
return new UpdateFilter(insertModeInclude(changeLog.inserts()), updateProps); return new UpdateFilter(insertModeInclude(changeLog.inserts()), updateProps);
} }
@@ -23,25 +23,16 @@ import javax.persistence.PersistenceException;
public abstract class AbstractSqlQueryRequest implements CancelableQuery { public abstract class AbstractSqlQueryRequest implements CancelableQuery {
protected final SpiSqlBinding query; protected final SpiSqlBinding query;
protected final SpiEbeanServer server; protected final SpiEbeanServer server;
protected SpiTransaction transaction; protected SpiTransaction transaction;
private boolean createdTransaction; private boolean createdTransaction;
protected String sql; protected String sql;
protected ResultSet resultSet; protected ResultSet resultSet;
protected String bindLog = ""; protected String bindLog = "";
protected PreparedStatement pstmt; protected PreparedStatement pstmt;
protected long startNano; protected long startNano;
private final ReentrantLock lock = new ReentrantLock(); private final ReentrantLock lock = new ReentrantLock();
/** /**
* Create the BeanFindRequest. * Create the BeanFindRequest.
*/ */
@@ -161,7 +152,8 @@ public abstract class AbstractSqlQueryRequest implements CancelableQuery {
this.bindLog = binder.bind(bindParams, pstmt, conn); this.bindLog = binder.bind(bindParams, pstmt, conn);
} }
if (isLogSql()) { if (isLogSql()) {
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")")); long micros = (System.nanoTime() - startNano) / 1000L;
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ") --micros(", micros + ")"));
} }
} finally { } finally {
lock.unlock(); lock.unlock();
@@ -33,7 +33,7 @@ public final class BindPadding {
* Extra padding on binding id's in order to get better hit ratio on DB prepared statements / query plans. * Extra padding on binding id's in order to get better hit ratio on DB prepared statements / query plans.
*/ */
static int padding(int size) { static int padding(int size) {
if (size == 1) { if (size <= 1) {
return 0; return 0;
} }
if (size <= 5) { if (size <= 5) {
@@ -17,7 +17,7 @@ import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
class DScriptRunner implements ScriptRunner { final class DScriptRunner implements ScriptRunner {
private static final String NEWLINE = "\n"; private static final String NEWLINE = "\n";
Loaded 100 of 844 files, more files were not shown because too many files have changed in this diff. Show more