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

This commit is contained in:
Jonas Pöhler
2021-08-17 16:07:02 +02:00
844 changed files with 5154 additions and 4973 deletions
@@ -6,7 +6,7 @@ import java.util.List;
/**
* The results of bean cache hit.
*/
public class BeanCacheResult<T> {
public final class BeanCacheResult<T> {
private final List<Entry<T>> list = new ArrayList<>();
@@ -27,7 +27,7 @@ public class BeanCacheResult<T> {
/**
* Bean and cache key pair.
*/
static class Entry<T> {
static final class Entry<T> {
private final T bean;
private final Object key;
@@ -7,7 +7,7 @@ import java.io.IOException;
/**
* Context used to read binary format messages.
*/
public class BinaryReadContext {
public final class BinaryReadContext {
private final DataInputStream in;
@@ -6,10 +6,9 @@ import java.io.IOException;
/**
* Context used to write binary message (like RemoteTransactionEvent).
*/
public class BinaryWriteContext {
public final class BinaryWriteContext {
private final DataOutputStream out;
private long counter;
public BinaryWriteContext(DataOutputStream out) {
@@ -4,11 +4,7 @@ import io.ebeaninternal.server.persist.MultiValueWrapper;
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.Map.Entry;
/**
@@ -17,35 +13,28 @@ import java.util.Map.Entry;
* Supports ordered or named parameters.
* </p>
*/
public class BindParams implements Serializable {
public final class BindParams implements Serializable {
private static final long serialVersionUID = 4541081933302086285L;
private final List<Param> positionedParameters = new ArrayList<>();
private final Map<String, Param> namedParameters = new LinkedHashMap<>();
/**
* 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 ordered by addNamedParamInOrder().
*/
private String preparedSql;
/**
* 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.
*/
private String bindHash;
/**
* Helper to add positioned parameters in order.
*/
private int addPos;
public BindParams() {
}
/**
* Reset positioned parameters (usually due to bind parameter expansion).
*/
@@ -54,12 +43,11 @@ public class BindParams implements Serializable {
positionedParameters.clear();
}
public int queryBindHash() {
int hc = namedParameters.hashCode();
for (Param positionedParameter : positionedParameters) {
hc = hc * 92821 + positionedParameter.hashCode();
public void queryBindHash(BindValuesKey key) {
key.add(positionedParameters.size());
for (Param param : positionedParameters) {
param.queryBindHash(key);
}
return hc;
}
/**
@@ -424,7 +412,14 @@ public class BindParams implements Serializable {
@Override
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.
*/
public class CacheIdLookupMany<T> implements CacheIdLookup<T> {
public final class CacheIdLookupMany<T> implements CacheIdLookup<T> {
private final IdInExpression idInExpression;
private int remaining;
public CacheIdLookupMany(IdInExpression idInExpression) {
@@ -7,7 +7,7 @@ import java.util.List;
/**
* 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 boolean found;
@@ -1,16 +1,12 @@
package io.ebeaninternal.api;
import io.ebean.annotation.Platform;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Helper to indicate that an EbeanServer should come up offline
* typically for DDL generation purposes.
*/
public class DbOffline {
private static final Logger logger = LoggerFactory.getLogger(DbOffline.class);
public final class DbOffline {
private static final String KEY = "ebean.dboffline";
@@ -73,7 +69,6 @@ public class DbOffline {
public static void reset() {
generateMigration = false;
System.clearProperty(KEY);
logger.debug("reset");
}
}
@@ -8,7 +8,7 @@ import io.ebean.metric.TimedMetric;
/**
* Extra metrics collected to measure internal behaviour.
*/
public class ExtraMetrics {
public final class ExtraMetrics {
private final TimedMetric bindCapture;
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.
*/
public class HashQuery {
public final class HashQuery {
private final CQueryPlanKey planHash;
private final int bindHash;
private final BindValuesKey bindValuesKey;
/**
* Create the HashQuery.
*/
public HashQuery(CQueryPlanKey planHash, int bindHash) {
public HashQuery(CQueryPlanKey planHash, BindValuesKey bindValuesKey) {
this.planHash = planHash;
this.bindHash = bindHash;
this.bindValuesKey = bindValuesKey;
}
@Override
@@ -25,7 +24,7 @@ public class HashQuery {
@Override
public int hashCode() {
int hc = 92821 * planHash.hashCode();
hc = 92821 * hc + bindHash;
hc = 92821 * hc + bindValuesKey.hashCode();
return hc;
}
@@ -37,8 +36,7 @@ public class HashQuery {
if (!(obj instanceof HashQuery)) {
return false;
}
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.
*/
public class HelpScopeTrans {
public final class HelpScopeTrans {
private static boolean enabled = true;
/**
@@ -13,16 +13,12 @@ import java.util.Set;
/**
* 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 LoadBeanBuffer loadBuffer;
private final String lazyLoadProperty;
private final boolean loadCache;
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.
*/
public List<Object> getIdList() {
List<Object> idList = new ArrayList<>();
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
for (EntityBeanIntercept ebi : batch) {
idList.add(desc.getId(ebi.getOwner()));
@@ -106,10 +100,8 @@ public class LoadBeanRequest extends LoadRequest {
* Configure the query for lazy loading execution.
*/
public void configureQuery(SpiQuery<?> query, List<Object> idList) {
query.setMode(SpiQuery.Mode.LAZYLOAD_BEAN);
query.setPersistenceContext(loadBuffer.getPersistenceContext());
String mode = isLazy() ? "+lazy" : "+query";
query.setLoadDescription(mode, getDescription());
@@ -117,9 +109,7 @@ public class LoadBeanRequest extends LoadRequest {
// cascade the batch size (if set) for further lazy loading
query.setLazyLoadBatchSize(getBatchSize());
}
loadBuffer.configureQuery(query, lazyLoadProperty);
if (idList.size() == 1) {
query.where().idEq(idList.get(0));
} 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.
*/
public void postLoad(List<?> list) {
Set<Object> loadedIds = new HashSet<>();
BeanDescriptor<?> desc = loadBuffer.getBeanDescriptor();
// collect Ids and maybe load bean cache
for (Object aList : list) {
EntityBean loadedBean = (EntityBean) aList;
for (Object bean : list) {
EntityBean loadedBean = (EntityBean) bean;
loadedIds.add(desc.getId(loadedBean));
}
if (isLoadCache()) {
desc.cacheBeanPutAll(list);
}
if (lazyLoadProperty != null) {
for (EntityBeanIntercept ebi : batch) {
// 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.
*/
public class LoadManyRequest extends LoadRequest {
public final class LoadManyRequest extends LoadRequest {
private static final Logger logger = LoggerFactory.getLogger(LoadManyRequest.class);
private final List<BeanCollection<?>> batch;
private final LoadManyBuffer loadContext;
private final boolean onlyIds;
private final boolean loadCache;
/**
@@ -17,16 +17,13 @@ import java.util.TreeSet;
* Holds the joins needs to support the many where predicates.
* 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 final TreeMap<String, PropertyJoin> joins = new TreeMap<>();
private List<String> formulaJoinProperties;
private boolean aggregation;
/**
* '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.
*/
class NaturalKeyEntryBasic implements NaturalKeyEntry {
final class NaturalKeyEntryBasic implements NaturalKeyEntry {
private final Map<String,Object> map = new HashMap<>();
private final String key;
@@ -1,6 +1,6 @@
package io.ebeaninternal.api;
class NaturalKeyEntrySimple implements NaturalKeyEntry {
final class NaturalKeyEntrySimple implements NaturalKeyEntry {
private final String key;
private final Object val;
@@ -3,7 +3,7 @@ package io.ebeaninternal.api;
/**
* A property value pair in a natural key lookup.
*/
public class NaturalKeyEq {
public final class NaturalKeyEq {
final String property;
final Object value;
@@ -11,28 +11,22 @@ import java.util.Set;
/**
* Collects the data for processing the natural key cache processing.
*/
public class NaturalKeyQueryData<T> {
public final class NaturalKeyQueryData<T> {
private final BeanNaturalKey naturalKey;
/**
* Only one of IN or IN PAIRS is allowed.
*/
private boolean hasIn;
// IN Pairs clause - only one allowed
private String inProperty0, inProperty1;
private List<Pairs.Entry> inPairs;
// IN clause - only one allowed
private List<Object> inValues;
private String inProperty;
// normal EQ expressions
private List<NaturalKeyEq> eqList;
private NaturalKeySet set;
private int hitCount;
public NaturalKeyQueryData(BeanNaturalKey naturalKey) {
@@ -4,8 +4,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
public class NaturalKeySet {
public final class NaturalKeySet {
private final Map<Object, NaturalKeyEntry> map = new LinkedHashMap<>();
@@ -2,7 +2,7 @@ package io.ebeaninternal.api;
import io.ebeaninternal.server.type.bindcapture.BindCapture;
class NoopQueryBindCapture implements SpiQueryBindCapture {
final class NoopQueryBindCapture implements SpiQueryBindCapture {
@Override
public boolean collectFor(long timeMicros) {
@@ -6,7 +6,7 @@ import io.ebean.meta.QueryPlanRequest;
import java.util.Collections;
import java.util.List;
class NoopQueryPlanManager implements QueryPlanManager {
final class NoopQueryPlanManager implements QueryPlanManager {
@Override
public void setDefaultThreshold(long thresholdMicros) {
@@ -3,7 +3,7 @@ package io.ebeaninternal.api;
import io.ebean.annotation.Platform;
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.
@@ -15,7 +15,6 @@ public class PlatformMatch {
if (platforms == null || platforms.trim().isEmpty()) {
return true;
}
// match on base platform name and platform name
for (String name : StringHelper.splitNames(platforms)) {
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.
*/
public class PropertyJoin {
public final class PropertyJoin {
/**
* The property name.
*/
private final String property;
/**
* Set to true if the property needs to be an outer join.
*/
private final 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.
*/
public class ScopeTrans {
public final class ScopeTrans {
private static final int OPCODE_ATHROW = 191;
@@ -15,43 +15,32 @@ public class ScopeTrans {
* The transaction in scope (can be null).
*/
private final SpiTransaction transaction;
/**
* If true by default rollback on Checked exceptions.
*/
private final boolean rollbackOnChecked;
/**
* True if the transaction was created and hence should be committed
* on finally if it hasn't already been rolled back.
*/
private final boolean created;
/**
* Explicit set of Exceptions that DO NOT cause a rollback to occur.
*/
private final ArrayList<Class<? extends Throwable>> noRollbackFor;
/**
* Explicit set of Exceptions that DO cause a rollback to occur.
*/
private final ArrayList<Class<? extends Throwable>> rollbackFor;
private Boolean restoreBatch;
private Boolean restoreBatchOnCascade;
private int restoreBatchSize;
private Boolean restoreBatchGeneratedKeys;
private boolean restoreBatchFlushOnQuery;
/**
* Flag set when a rollback has occurred.
*/
private boolean rolledBack;
/**
* 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.
*/
public class ScopedTransaction extends SpiTransactionProxy {
public final class ScopedTransaction extends SpiTransactionProxy {
private final TransactionScopeManager manager;
/**
* Stack of 'nested' transactions.
*/
private final ArrayStack<ScopeTrans> stack = new ArrayStack<>();
private ScopeTrans current;
/**
@@ -8,6 +8,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.core.SpiResultSet;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -149,7 +150,7 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollect
/**
* 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.
@@ -54,9 +54,9 @@ public interface SpiExpression extends Expression {
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.
@@ -8,10 +8,9 @@ import java.util.Set;
/**
* Property expression validation request for a given root bean type.
*/
public class SpiExpressionValidation {
public final class SpiExpressionValidation {
private final BeanType<?> desc;
private final LinkedHashSet<String> unknown = new LinkedHashSet<>();
public SpiExpressionValidation(BeanType<?> desc) {
@@ -84,7 +84,7 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
/**
* Find single attribute.
*/
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute"),
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false),
/**
* Find rowCount.
@@ -92,9 +92,14 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
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.
@@ -107,17 +112,21 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
UPDATE(FIND_UPDATE, "update", true);
private final boolean update;
private final boolean defaultSelect;
private final String profileEventId;
private final String label;
Type(String profileEventId, String label) {
this(profileEventId, label, false);
this(profileEventId, label, false, true);
}
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.label = label;
this.update = update;
this.defaultSelect = defaultSelect;
}
/**
@@ -127,6 +136,13 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
return update;
}
/**
* Return true if this allows default select clause.
*/
public boolean defaultSelect() {
return defaultSelect;
}
public String profileEventId() {
return profileEventId;
}
@@ -629,13 +645,11 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
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>
* Combined with queryPlanHash() to return getQueryHash (a unique hash for a
* query).
* </p>
* Combined with queryPlanHash() to return queryHash (a unique key for a query).
*/
int queryBindHash();
void queryBindKey(BindValuesKey key);
/**
* Identifies queries that are exactly the same including bind variables.
@@ -18,7 +18,7 @@ public interface SpiQueryPlan {
String getName();
/**
* The hash for the query plan.
* The hash of the sql.
*/
String getHash();
@@ -20,7 +20,7 @@ import java.util.List;
* to the TransactionEventManager.
* </p>
*/
public class TransactionEvent implements Serializable {
public final class TransactionEvent implements Serializable {
private static final long serialVersionUID = 7230903304106097120L;
@@ -29,13 +29,9 @@ public class TransactionEvent implements Serializable {
* the cluster).
*/
private final transient boolean local;
private TransactionEventTable eventTables;
private transient List<PersistRequestBean<?>> listenerNotify;
private transient DeleteByIdMap deleteByIdMap;
private transient CacheChangeSet changeSet;
/**
@@ -110,11 +106,9 @@ public class TransactionEvent implements Serializable {
* Build and return the cache changeSet.
*/
public CacheChangeSet buildCacheChanges(TransactionManager manager) {
if (changeSet == null && deleteByIdMap == null && eventTables == null) {
return null;
}
if (changeSet == null) {
changeSet = new CacheChangeSet();
}
@@ -28,20 +28,17 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
}
public void add(TransactionEventTable table) {
for (TableIUD iud : table.values()) {
add(iud);
}
}
public void add(String table, boolean insert, boolean update, boolean delete) {
table = table.toUpperCase();
add(new TableIUD(table, insert, update, delete));
}
public void add(TableIUD newTableIUD) {
TableIUD existingTableIUD = map.put(newTableIUD.getTableName(), newTableIUD);
if (existingTableIUD != null) {
newTableIUD.add(existingTableIUD);
@@ -56,7 +53,7 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
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;
@@ -73,12 +70,10 @@ public final class TransactionEventTable implements Serializable, BinaryWritable
}
public static TableIUD readBinaryMessage(BinaryReadContext dataInput) throws IOException {
String table = dataInput.readUTF();
boolean insert = dataInput.readBoolean();
boolean update = dataInput.readBoolean();
boolean delete = dataInput.readBoolean();
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.
*/
public class DJsonService implements SpiJsonService {
public final class DJsonService implements SpiJsonService {
/**
* Write the nested Map/List as json.
@@ -14,7 +14,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
class EJsonReader {
final class EJsonReader {
static final JsonFactory json = new JsonFactory();
@@ -14,7 +14,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
class EJsonWriter {
final class EJsonWriter {
/**
* 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).
*/
public class ModifyAwareFlag implements ModifyAwareType, Serializable {
public final class ModifyAwareFlag implements ModifyAwareType, Serializable {
private static final long serialVersionUID = 1;
@@ -7,10 +7,9 @@ import java.util.Iterator;
/**
* 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 Iterator<E> it;
/**
@@ -13,12 +13,11 @@ import java.util.Objects;
/**
* 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;
final List<E> list;
final ModifyAwareType owner;
public ModifyAwareList(List<E> list) {
@@ -7,10 +7,9 @@ import java.util.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 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.
*/
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;
final ModifyAwareType owner;
/**
* The underlying map.
*/
final Map<K, V> map;
public ModifyAwareMap(Map<K, V> underlying) {
@@ -11,13 +11,12 @@ import java.util.Set;
/**
* 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;
protected final ModifyAwareType owner;
protected final Set<E> set;
private final ModifyAwareType owner;
private final Set<E> 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.
*/
public class DContainerFactory implements SpiContainerFactory {
public final class DContainerFactory implements SpiContainerFactory {
@Override
public SpiContainer create(ContainerConfig containerConfig) {
@@ -5,7 +5,7 @@ import io.ebeaninternal.api.SpiQuery;
/**
* Noop service when AutoTuneService is not available.
*/
public class NoAutoTuneService implements AutoTuneService {
public final class NoAutoTuneService implements AutoTuneService {
@Override
public void startup() {
@@ -8,10 +8,9 @@ import java.util.Collection;
/**
* Change to remove bean from L2 cache.
*/
class CacheChangeBeanRemove implements CacheChange {
final class CacheChangeBeanRemove implements CacheChange {
private final BeanDescriptor<?> descriptor;
private final Collection<Object> ids;
CacheChangeBeanRemove(Object id, BeanDescriptor<?> descriptor) {
@@ -7,7 +7,7 @@ import java.util.Map;
/**
* Put a new bean entry into the cache.
*/
class CacheChangeBeanUpdate implements CacheChange {
final class CacheChangeBeanUpdate implements CacheChange {
private final BeanDescriptor<?> desc;
private final String key;
@@ -5,7 +5,7 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
/**
* Change the natural key mapping for a bean.
*/
class CacheChangeNaturalKeyPut implements CacheChange {
final class CacheChangeNaturalKeyPut implements CacheChange {
private final BeanDescriptor<?> descriptor;
private final String key;
@@ -14,18 +14,13 @@ import java.util.Set;
/**
* 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 Set<String> touchedTables = new HashSet<>();
private final Set<BeanDescriptor<?>> queryCaches = new HashSet<>();
private final Set<BeanDescriptor<?>> beanCaches = new HashSet<>();
private final Map<BeanDescriptor<?>, CacheChangeBeanRemove> beanRemoveMap = new HashMap<>();
private final Map<ManyKey, ManyChange> manyChangeMap = new HashMap<>();
/**
@@ -173,14 +168,11 @@ public class CacheChangeSet {
/**
* Changes for a specific many property.
*/
private static class ManyChange implements CacheChange {
private static final class ManyChange implements CacheChange {
final ManyKey key;
final Set<Object> removes = new HashSet<>();
final Map<Object, CachedManyIds> puts = new LinkedHashMap<>();
boolean clear;
ManyChange(ManyKey key) {
@@ -229,10 +221,9 @@ public class CacheChangeSet {
/**
* Key for changes on a many property.
*/
private static class ManyKey {
private static final class ManyKey {
private final BeanDescriptor<?> desc;
private final 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.
*/
public class CacheManagerOptions {
public final class CacheManagerOptions {
private final ClusterManager clusterManager;
private final DatabaseConfig databaseConfig;
private final boolean localL2Caching;
private CurrentTenantProvider currentTenantProvider;
private QueryCacheEntryValidate queryCacheEntryValidate;
private ServerCacheFactory cacheFactory = new DefaultServerCacheFactory();
private ServerCacheOptions beanDefault = new ServerCacheOptions();
private ServerCacheOptions queryDefault = new ServerCacheOptions();
@@ -11,13 +11,12 @@ import java.util.Map;
/**
* 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 version;
private String discValue;
private Map<String, Object> data;
/**
* 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.Map;
public class CachedBeanDataFromBean {
public final class CachedBeanDataFromBean {
public static CachedBeanData extract(BeanDescriptor<?> desc, EntityBean bean) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
Map<String, Object> data = new LinkedHashMap<>();
@@ -46,7 +45,6 @@ public class CachedBeanDataFromBean {
}
private static EntityBean createSharableBean(BeanDescriptor<?> desc, EntityBean bean, EntityBeanIntercept beanEbi) {
if (!desc.isCacheSharableBeans() || !beanEbi.isFullyLoadedBean()) {
return null;
}
@@ -7,30 +7,24 @@ import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.deploy.BeanProperty;
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) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
// any future lazy loading skips L2 bean cache
ebi.setLoadedFromCache(true);
BeanProperty idProperty = desc.getIdProperty();
if (desc.getInheritInfo() != null) {
desc = desc.getInheritInfo().readType(bean.getClass()).desc();
}
if (idProperty != null) {
// load the id property
loadProperty(bean, cacheBeanData, ebi, idProperty, context);
}
// load the non-many properties
for (BeanProperty prop : desc.propertiesNonMany()) {
loadProperty(bean, cacheBeanData, ebi, prop, context);
}
for (BeanPropertyAssocMany<?> prop : desc.propertiesMany()) {
if (prop.isElementCollection()) {
loadProperty(bean, cacheBeanData, ebi, prop, context);
@@ -38,12 +32,10 @@ public class CachedBeanDataToBean {
prop.createReferenceIfNull(bean);
}
}
ebi.setLoadedLazy();
}
private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop, PersistenceContext context) {
if (cacheBeanData.isLoaded(prop.getName())) {
if (!ebi.isLoadedProperty(prop.getPropertyIndex())) {
Object value = cacheBeanData.getData(prop.getName());
@@ -10,7 +10,7 @@ import java.io.ObjectOutput;
* <p>
* 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 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.
* </p>
*/
public class CachedManyIds implements Externalizable {
public final class CachedManyIds implements Externalizable {
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.
* </p>
*/
public class DefaultCacheAdapter implements ServerCacheManager {
public final class DefaultCacheAdapter implements ServerCacheManager {
private final SpiCacheManager cacheManager;
@@ -23,14 +23,13 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the construction of caches.
*/
class DefaultCacheHolder {
final class DefaultCacheHolder {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
private final ReentrantLock lock = new ReentrantLock();
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
private final ServerCacheFactory cacheFactory;
private final ServerCacheOptions beanDefault;
private final ServerCacheOptions queryDefault;
@@ -76,7 +75,6 @@ class DefaultCacheHolder {
* Return the cache for a given bean type.
*/
private ServerCache getCacheInternal(Class<?> beanType, ServerCacheType type, String collectionProperty) {
String shortName = key(beanType.getSimpleName(), collectionProperty, type);
String fullKey = key(beanType.getName(), collectionProperty, type);
return allCaches.computeIfAbsent(fullKey, s -> createCache(beanType, type, fullKey, shortName));
@@ -143,10 +141,8 @@ class DefaultCacheHolder {
}
private ServerCacheOptions getBeanOptions(Class<?> cls) {
Cache cache = cls.getAnnotation(Cache.class);
boolean nearCache = (cache != null && cache.nearCache());
CacheBeanTuning tuning = cls.getAnnotation(CacheBeanTuning.class);
if (tuning != null) {
return new ServerCacheOptions(nearCache, tuning).applyDefaults(beanDefault);
@@ -11,6 +11,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
@@ -37,8 +38,7 @@ public class DefaultServerCache implements ServerCache {
/**
* 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 missCount;
protected final CountMetric putCount;
@@ -48,16 +48,11 @@ public class DefaultServerCache implements ServerCache {
protected final String name;
protected final String shortName;
private int maxSize;
private final int maxSize;
private final int trimFrequency;
private int maxIdleSecs;
private int maxSecsToLive;
private TenantAwareKey tenantAwareKey;
private final int maxIdleSecs;
private final int maxSecsToLive;
private final TenantAwareKey tenantAwareKey;
public DefaultServerCache(DefaultServerCacheConfig config) {
this.name = config.getName();
@@ -70,7 +65,6 @@ public class DefaultServerCache implements ServerCache {
this.trimFrequency = config.determineTrimFrequency();
MetricFactory factory = MetricFactory.get();
String prefix = "l2n.";
this.hitCount = factory.createCountMetric(prefix + shortName + ".hit");
this.missCount = factory.createCountMetric(prefix + shortName + ".miss");
@@ -81,9 +75,7 @@ public class DefaultServerCache implements ServerCache {
}
public void periodicTrim(BackgroundExecutor executor) {
EvictionRunnable trim = new EvictionRunnable();
// default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
@@ -101,11 +93,9 @@ public class DefaultServerCache implements ServerCache {
@Override
public ServerCacheStatistics getStatistics(boolean reset) {
ServerCacheStatistics cacheStats = new ServerCacheStatistics();
cacheStats.setCacheName(name);
cacheStats.setMaxSize(maxSize);
cacheStats.setSize(size());
cacheStats.setHitCount(hitCount.get(reset));
cacheStats.setMissCount(missCount.get(reset));
@@ -113,7 +103,6 @@ public class DefaultServerCache implements ServerCache {
cacheStats.setRemoveCount(removeCount.get(reset));
cacheStats.setClearCount(clearCount.get(reset));
cacheStats.setEvictCount(evictCount.get(reset));
return cacheStats;
}
@@ -133,10 +122,8 @@ public class DefaultServerCache implements ServerCache {
@Override
public int getHitRatio() {
long mc = missCount.get(false);
long hc = hitCount.get(false);
long totalCount = hc + mc;
if (totalCount == 0) {
return 0;
@@ -177,7 +164,6 @@ public class DefaultServerCache implements ServerCache {
*/
@Override
public Object get(Object id) {
CacheEntry entry = getCacheEntry(id);
if (entry == null) {
missCount.increment();
@@ -199,7 +185,8 @@ public class DefaultServerCache implements ServerCache {
* Get the cache entry - override for query cache to validate dependent tables.
*/
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
@@ -213,7 +200,7 @@ public class DefaultServerCache implements ServerCache {
@Override
public void put(Object id, Object value) {
Object key = key(id);
map.put(key, new CacheEntry(key, value));
map.put(key, new SoftReference<>(new CacheEntry(key, value)));
putCount.increment();
}
@@ -222,8 +209,8 @@ public class DefaultServerCache implements ServerCache {
*/
@Override
public void remove(Object id) {
CacheEntry entry = map.remove(key(id));
if (entry != null) {
SoftReference<CacheEntry> entry = map.remove(key(id));
if (entry != null && entry.get() != null) {
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.
*/
public void runEviction() {
long trimForMaxSize;
if (maxSize == 0) {
trimForMaxSize = 0;
} else {
trimForMaxSize = size() - maxSize;
}
if (maxIdleSecs == 0 && maxSecsToLive == 0 && trimForMaxSize < 0) {
// nothing to trim on this cache
return;
}
long startNanos = System.nanoTime();
long trimmedByIdle = 0;
long trimmedByGC = 0;
long trimmedByTTL = 0;
long trimmedByLRU = 0;
List<CacheEntry> activeList = new ArrayList<>(map.size());
long idleExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxIdleSecs);
long ttlExpireNano = startNanos - TimeUnit.SECONDS.toNanos(maxSecsToLive);
Iterator<CacheEntry> it = map.values().iterator();
Iterator<SoftReference<CacheEntry>> it = map.values().iterator();
while (it.hasNext()) {
CacheEntry cacheEntry = it.next();
if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) {
SoftReference<CacheEntry> ref = it.next();
final CacheEntry cacheEntry = ref.get();
if (cacheEntry == null) {
it.remove();
trimmedByGC++;
} else if (maxIdleSecs > 0 && idleExpireNano > cacheEntry.getLastAccessTime()) {
it.remove();
trimmedByIdle++;
} else if (maxSecsToLive > 0 && ttlExpireNano > cacheEntry.getCreateTime()) {
it.remove();
trimmedByTTL++;
} else if (trimForMaxSize > 0) {
activeList.add(cacheEntry);
}
}
if (trimForMaxSize > 0) {
trimmedByLRU = activeList.size() - maxSize;
if (trimmedByLRU > 0) {
// sort into last access time ascending
activeList.sort(BY_LAST_ACCESS);
int trimSize = getTrimSize();
for (int i = trimSize; i < activeList.size(); i++) {
// remove if still in the cache
map.remove(activeList.get(i).getKey());
if (trimForMaxSize > 0 && activeList.size() > maxSize) {
// sort into last access time ascending
activeList.sort(BY_LAST_ACCESS);
int trimSize = getTrimSize();
for (int i = trimSize; i < activeList.size(); i++) {
// remove if still in the cache
if (map.remove(activeList.get(i).getKey()) != null) {
trimmedByLRU++;
}
}
}
evictCount.add(trimmedByIdle);
evictCount.add(trimmedByGC);
evictCount.add(trimmedByTTL);
evictCount.add(trimmedByLRU);
if (logger.isTraceEnabled()) {
long exeMicros = TimeUnit.MICROSECONDS.convert(System.nanoTime() - startNanos, TimeUnit.NANOSECONDS);
logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}]"
, name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU);
logger.trace("Executed trim of cache {} in [{}]millis idle[{}] timeToLive[{}] accessTime[{}] gc[{}]",
name, exeMicros, trimmedByIdle, trimmedByTTL, trimmedByLRU, trimmedByGC);
}
}
/**
* Runnable that calls the eviction routine.
*/
public class EvictionRunnable implements Runnable {
public final class EvictionRunnable implements Runnable {
@Override
public void run() {
@@ -328,7 +310,7 @@ public class DefaultServerCache implements ServerCache {
/**
* 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;
@@ -341,7 +323,7 @@ public class DefaultServerCache implements ServerCache {
/**
* 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 value;
@@ -4,26 +4,26 @@ import io.ebean.cache.QueryCacheEntryValidate;
import io.ebean.cache.ServerCacheConfig;
import io.ebean.cache.ServerCacheOptions;
import io.ebean.config.CurrentTenantProvider;
import io.ebeaninternal.server.cache.DefaultServerCache.CacheEntry;
import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class DefaultServerCacheConfig {
public final class DefaultServerCacheConfig {
private final ServerCacheConfig config;
private int maxSize;
private int maxIdleSecs;
private int maxSecsToLive;
private int trimFrequency;
private Map<Object, DefaultServerCache.CacheEntry> map;
private final int maxSize;
private final int maxIdleSecs;
private final int maxSecsToLive;
private final int trimFrequency;
private final Map<Object, SoftReference<CacheEntry>> map;
public DefaultServerCacheConfig(ServerCacheConfig config) {
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.map = map;
@@ -50,7 +50,7 @@ public class DefaultServerCacheConfig {
return config.getShortName();
}
public Map<Object, DefaultServerCache.CacheEntry> getMap() {
public Map<Object, SoftReference<CacheEntry>> getMap() {
return map;
}
@@ -11,7 +11,7 @@ import io.ebean.cache.ServerCacheNotify;
/**
* Default implementation of ServerCacheFactory.
*/
class DefaultServerCacheFactory implements ServerCacheFactory {
final class DefaultServerCacheFactory implements ServerCacheFactory {
private final BackgroundExecutor executor;
@@ -31,7 +31,6 @@ class DefaultServerCacheFactory implements ServerCacheFactory {
@Override
public ServerCache createCache(ServerCacheConfig config) {
DefaultServerCache cache;
if (config.isQueryCache()) {
// use a server cache aware of extra validation and QueryCacheEntry
@@ -19,18 +19,14 @@ import java.util.Map;
/**
* 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 final Map<String, SpiCacheRegion> regionMap = new HashMap<>();
private final ClusterManager clusterManager;
private final DefaultCacheHolder cacheHolder;
private final boolean localL2Caching;
private final String serverName;
/**
@@ -8,7 +8,7 @@ import io.ebean.config.DatabaseConfig;
/**
* Default implementation of ServerCachePlugin.
*/
public class DefaultServerCachePlugin implements ServerCachePlugin {
public final class DefaultServerCachePlugin implements ServerCachePlugin {
/**
* Creates the default ServerCacheFactory.
@@ -3,6 +3,8 @@ package io.ebeaninternal.server.cache;
import io.ebean.cache.QueryCacheEntry;
import io.ebean.cache.QueryCacheEntryValidate;
import java.lang.ref.SoftReference;
/**
* Server cache for query caching.
* <p>
@@ -27,7 +29,8 @@ public class DefaultServerQueryCache extends DefaultServerCache {
@Override
protected CacheEntry getCacheEntry(Object 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) {
return null;
}
@@ -12,11 +12,10 @@ import java.util.List;
/**
* Cache events broadcast across the cluster.
*/
public class RemoteCacheEvent implements BinaryWritable {
public final class RemoteCacheEvent implements BinaryWritable {
private boolean clearAll;
private List<String> clearCaches;
private final boolean clearAll;
private final List<String> clearCaches;
/**
* Clear all the caches.
@@ -57,10 +56,8 @@ public class RemoteCacheEvent implements BinaryWritable {
}
public static RemoteCacheEvent readBinaryMessage(BinaryReadContext dataInput) throws IOException {
boolean clearAll = dataInput.readBoolean();
int size = dataInput.readInt();
List<String> clearCache = null;
if (size > 0) {
clearCache = new ArrayList<>(size);
@@ -68,7 +65,6 @@ public class RemoteCacheEvent implements BinaryWritable {
clearCache.add(dataInput.readUTF());
}
}
return new RemoteCacheEvent(clearAll, clearCache);
}
@@ -14,21 +14,14 @@ import java.util.Map;
/**
* Builds JSON document for a bean change.
*/
class ChangeJsonBuilder {
final class ChangeJsonBuilder {
protected final JsonFactory jsonFactory = new JsonFactory();
protected final JsonContext json;
ChangeJsonBuilder(JsonContext json) {
this.json = json;
}
private final JsonFactory jsonFactory = new JsonFactory();
/**
* Write the bean change as JSON.
*/
void writeBeanJson(Writer writer, BeanChange bean, ChangeSet changeSet) throws IOException {
try (JsonGenerator generator = jsonFactory.createGenerator(writer)) {
writeBeanChange(generator, bean, changeSet);
generator.flush();
@@ -39,9 +32,7 @@ class ChangeJsonBuilder {
* Write the bean change as JSON document containing the transaction header details.
*/
private void writeBeanChange(JsonGenerator gen, BeanChange bean, ChangeSet changeSet) throws IOException {
gen.writeStartObject();
gen.writeNumberField("ts", bean.getEventTime());
gen.writeStringField("change", bean.getEvent().getCode());
gen.writeStringField("type", bean.getType());
@@ -49,9 +40,7 @@ class ChangeJsonBuilder {
if (bean.getTenantId() != null) {
gen.writeStringField("tenantId", bean.getTenantId().toString());
}
writeBeanTransactionDetails(gen, changeSet);
writeBeanValues(gen, bean);
gen.writeEndObject();
}
@@ -60,7 +49,6 @@ class ChangeJsonBuilder {
* Denormalise by writing the transaction header details.
*/
private void writeBeanTransactionDetails(JsonGenerator gen, ChangeSet changeSet) throws IOException {
String source = changeSet.getSource();
if (source != null) {
gen.writeStringField("source", source);
@@ -87,12 +75,10 @@ class ChangeJsonBuilder {
* For insert and update write the new/old values.
*/
private void writeBeanValues(JsonGenerator gen, BeanChange bean) throws IOException {
if (bean.getEvent() != ChangeType.DELETE) {
gen.writeFieldName("data");
gen.writeRaw(":");
gen.writeRaw(bean.getData());
String oldData = bean.getOldData();
if (oldData != null) {
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>.
*/
public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
public final class DefaultChangeLogListener implements ChangeLogListener, Plugin {
/**
* 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.
@@ -45,8 +45,7 @@ public class DefaultChangeLogListener implements ChangeLogListener, Plugin {
*/
@Override
public void configure(SpiServer server) {
jsonBuilder = new ChangeJsonBuilder(server.json());
jsonBuilder = new ChangeJsonBuilder();
Properties properties = server.getServerConfig().getProperties();
if (properties != null) {
String bufferSize = properties.getProperty("ebean.changeLog.bufferSize");
@@ -11,7 +11,7 @@ import io.ebean.event.changelog.ChangeSet;
* on the changeSet.
* </p>
*/
public class DefaultChangeLogPrepare implements ChangeLogPrepare {
public final class DefaultChangeLogPrepare implements ChangeLogPrepare {
/**
* Just return true to send change set through to the logger.
@@ -14,10 +14,9 @@ import java.util.Set;
/**
* 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 EXCLUDE_INSERTS = new BasicFilter(false);
private final boolean defaultInsertsInclude;
@@ -31,20 +30,16 @@ public class DefaultChangeLogRegister implements ChangeLogRegister {
@Override
public ChangeLogFilter getChangeFilter(Class<?> beanType) {
ChangeLog changeLog = getChangeLog(beanType);
if (changeLog == null) {
return null;
}
String[] updatesThatInclude = changeLog.updatesThatInclude();
if (updatesThatInclude.length == 0) {
return insertModeInclude(changeLog.inserts()) ? INCLUDE_INSERTS : EXCLUDE_INSERTS;
}
Set<String> updateProps = new HashSet<>();
Collections.addAll(updateProps, updatesThatInclude);
return new UpdateFilter(insertModeInclude(changeLog.inserts()), updateProps);
}
@@ -23,25 +23,16 @@ import javax.persistence.PersistenceException;
public abstract class AbstractSqlQueryRequest implements CancelableQuery {
protected final SpiSqlBinding query;
protected final SpiEbeanServer server;
protected SpiTransaction transaction;
private boolean createdTransaction;
protected String sql;
protected ResultSet resultSet;
protected String bindLog = "";
protected PreparedStatement pstmt;
protected long startNano;
private final ReentrantLock lock = new ReentrantLock();
/**
* Create the BeanFindRequest.
*/
@@ -161,7 +152,8 @@ public abstract class AbstractSqlQueryRequest implements CancelableQuery {
this.bindLog = binder.bind(bindParams, pstmt, conn);
}
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 {
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.
*/
static int padding(int size) {
if (size == 1) {
if (size <= 1) {
return 0;
}
if (size <= 5) {
@@ -17,7 +17,7 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
class DScriptRunner implements ScriptRunner {
final class DScriptRunner implements ScriptRunner {
private static final String NEWLINE = "\n";
@@ -36,9 +36,8 @@ import java.sql.SQLException;
/**
* Create a DatabasePlatform from the configuration.
* <p>
* Will used platform name or use the meta data from the JDBC driver to
* Will used platform name or use the metadata from the JDBC driver to
* determine the platform automatically.
* </p>
*/
public class DatabasePlatformFactory {
@@ -54,14 +53,12 @@ public class DatabasePlatformFactory {
logger.info("offline platform [{}]", offlinePlatform);
return byDatabaseName(offlinePlatform);
}
if (config.getDatabasePlatformName() != null) {
// choose based on dbName
return byDatabaseName(config.getDatabasePlatformName());
}
if (config.getDataSourceConfig().isOffline()) {
throw new PersistenceException("You must specify a DatabasePlatformName when you are offline");
throw new PersistenceException("DatabasePlatformName must be specified with offline mode");
}
// guess using meta data from driver
return byDataSource(config.getDataSource());
@@ -142,10 +139,10 @@ public class DatabasePlatformFactory {
* Find the platform by the metaData.getDatabaseProductName().
*/
private DatabasePlatform byDatabaseMeta(DatabaseMetaData metaData, Connection connection) throws SQLException {
String dbProductName = metaData.getDatabaseProductName().toLowerCase();
final int majorVersion = metaData.getDatabaseMajorVersion();
final int minorVersion = metaData.getDatabaseMinorVersion();
logger.debug("platform for productName[{}] version[{}.{}]", dbProductName, majorVersion, minorVersion);
if (dbProductName.contains("oracle")) {
return oracleVersion(majorVersion);
@@ -206,7 +203,6 @@ public class DatabasePlatformFactory {
} catch (SQLException e) {
logger.warn("Error running detection query on Postgres", e);
}
if (majorVersion <= 9) {
return new Postgres9Platform();
}
@@ -26,12 +26,11 @@ import java.util.List;
/**
* Helper to handle lazy loading and refreshing of beans.
*/
class DefaultBeanLoader {
final class DefaultBeanLoader {
private static final Logger logger = LoggerFactory.getLogger(DefaultBeanLoader.class);
private final DefaultServer server;
private final boolean onIterateUseExtraTxn;
DefaultBeanLoader(DefaultServer server) {
@@ -40,17 +39,14 @@ class DefaultBeanLoader {
}
void loadMany(LoadManyRequest loadRequest) {
SpiQuery<?> query = loadRequest.createQuery(server);
executeQuery(loadRequest, query);
loadRequest.postLoad();
}
void loadMany(BeanCollection<?> bc, boolean onlyIds) {
EntityBean parentBean = bc.getOwnerBean();
String propertyName = bc.getPropertyName();
loadManyInternal(parentBean, propertyName, null, false, onlyIds);
}
@@ -59,13 +55,10 @@ class DefaultBeanLoader {
}
private void loadManyInternal(EntityBean parentBean, String propertyName, Transaction t, boolean refresh, boolean onlyIds) {
EntityBeanIntercept ebi = parentBean._ebean_getIntercept();
PersistenceContext pc = ebi.getPersistenceContext();
BeanDescriptor<?> parentDesc = server.getBeanDescriptor(parentBean.getClass());
BeanPropertyAssocMany<?> many = (BeanPropertyAssocMany<?>) parentDesc.getBeanProperty(propertyName);
BeanCollection<?> beanCollection = null;
ExpressionList<?> filterMany = null;
@@ -126,7 +119,6 @@ class DefaultBeanLoader {
}
server.findOne(query, t);
if (beanCollection != null) {
if (beanCollection.checkEmptyLazyLoad()) {
if (logger.isDebugEnabled()) {
@@ -142,7 +134,6 @@ class DefaultBeanLoader {
* Load a batch of beans for +query or +lazy loading.
*/
void loadBean(LoadBeanRequest loadRequest) {
List<EntityBeanIntercept> batch = loadRequest.getBatch();
if (batch.isEmpty()) {
throw new RuntimeException("Nothing in batch?");
@@ -190,7 +181,6 @@ class DefaultBeanLoader {
}
private void refreshBeanInternal(EntityBean bean, SpiQuery.Mode mode, int embeddedOwnerIndex) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
PersistenceContext pc = ebi.getPersistenceContext();
if (Mode.REFRESH_BEAN == mode) {
@@ -203,12 +193,10 @@ class DefaultBeanLoader {
// lazy loading on an embedded bean property
EntityBean embeddedOwner = (EntityBean) ebi.getEmbeddedOwner();
int ownerIndex = ebi.getEmbeddedOwnerIndex();
refreshBeanInternal(embeddedOwner, mode, ownerIndex);
}
Object id = desc.getId(bean);
if (pc == null) {
// a reference with no existing persistenceContext
pc = new DefaultPersistenceContext();
@@ -216,7 +204,6 @@ class DefaultBeanLoader {
ebi.setPersistenceContext(pc);
}
boolean draft = desc.isDraftInstance(bean);
if (embeddedOwnerIndex == -1) {
if (desc.lazyLoadMany(ebi)) {
return;
@@ -246,16 +233,13 @@ class DefaultBeanLoader {
query.setPersistenceContext(pc);
query.setMode(mode);
query.setId(id);
if (embeddedOwnerIndex > -1 || mode == Mode.REFRESH_BEAN) {
// make sure the query doesn't use the cache
query.setUseCache(false);
}
if (ebi.isReadOnly()) {
query.setReadOnly(true);
}
if (Mode.REFRESH_BEAN == mode) {
// explicitly state to load all properties on REFRESH.
// Lobs default to fetch lazy so this forces lobs to be
@@ -268,7 +252,6 @@ class DefaultBeanLoader {
String msg = "Bean not found during lazy load or refresh." + " id[" + id + "] type[" + desc.getBeanType() + "]";
throw new EntityNotFoundException(msg);
}
desc.resetManyProperties(dbBean);
}
}
@@ -11,7 +11,7 @@ import java.util.Set;
/**
* Default implementation of BeanState.
*/
public class DefaultBeanState implements BeanState {
public final class DefaultBeanState implements BeanState {
private final EntityBeanIntercept intercept;
@@ -8,7 +8,7 @@ import java.util.Arrays;
/**
* Default CallStackFactory where the Hash function for StackTraceElement includes the line number.
*/
public class DefaultCallOriginFactory implements CallOriginFactory {
public final class DefaultCallOriginFactory implements CallOriginFactory {
private static final int IGNORE_LEADING_ELEMENTS = 5;
@@ -12,7 +12,7 @@ import java.sql.CallableStatement;
import java.sql.SQLException;
public class DefaultCallableSql implements Serializable, SpiCallableSql {
public final class DefaultCallableSql implements Serializable, SpiCallableSql {
private static final long serialVersionUID = 8984272253185424701L;
@@ -32,9 +32,9 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Default Server side implementation of ServerFactory.
*/
public class DefaultContainer implements SpiContainer {
public final class DefaultContainer implements SpiContainer {
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
private static final Logger logger = LoggerFactory.getLogger("io.ebean.DB");
private final ReentrantLock lock = new ReentrantLock();
private final ClusterManager clusterManager;
@@ -77,9 +77,10 @@ public class DefaultContainer implements SpiContainer {
public SpiEbeanServer createServer(DatabaseConfig config) {
lock.lock();
try {
long start = System.currentTimeMillis();
applyConfigServices(config);
setNamingConvention(config);
BootupClasses bootupClasses = getBootupClasses(config);
BootupClasses bootupClasses = bootupClasses(config);
boolean online = true;
if (config.isDocStoreOnly()) {
@@ -101,22 +102,18 @@ public class DefaultContainer implements SpiContainer {
// use a configured DbEncrypt rather than the platform default
config.getDatabasePlatform().setDbEncrypt(config.getDbEncrypt());
}
// inform the NamingConvention of the associated DatabasePlatform
config.getNamingConvention().setDatabasePlatform(config.getDatabasePlatform());
// executor and l2 caching service setup early (used during server construction)
SpiBackgroundExecutor executor = createBackgroundExecutor(config);
InternalConfiguration c = new InternalConfiguration(online, clusterManager, executor, config, bootupClasses);
DefaultServer server = new DefaultServer(c, c.cacheManager());
// generate and run DDL if required
// if there are any other tasks requiring action in their plugins, do them as well
// generate and run DDL if required plus other plugins
if (!DbOffline.isGenerateMigration()) {
startServer(online, server);
}
DbOffline.reset();
logger.info("started database[{}] platform[{}] in {}ms", config.getName(), config.getDatabasePlatform().getPlatform(), System.currentTimeMillis() - start);
return server;
} finally {
lock.unlock();
@@ -161,9 +158,8 @@ public class DefaultContainer implements SpiContainer {
* Get the entities, scalarTypes, Listeners etc combining the class registered
* ones with the already created instances.
*/
private BootupClasses getBootupClasses(DatabaseConfig config) {
BootupClasses bootup = getBootupClasses1(config);
private BootupClasses bootupClasses(DatabaseConfig config) {
BootupClasses bootup = bootupClasses1(config);
bootup.addIdGenerators(config.getIdGenerators());
bootup.addPersistControllers(config.getPersistControllers());
bootup.addPostLoaders(config.getPostLoaders());
@@ -173,7 +169,6 @@ public class DefaultContainer implements SpiContainer {
bootup.addQueryAdapters(config.getQueryAdapters());
bootup.addServerConfigStartup(config.getServerConfigStartupListeners());
bootup.addChangeLogInstances(config);
bootup.runServerConfigStartup(config);
return bootup;
}
@@ -181,14 +176,12 @@ public class DefaultContainer implements SpiContainer {
/**
* Get the class based entities, scalarTypes, Listeners etc.
*/
private BootupClasses getBootupClasses1(DatabaseConfig config) {
private BootupClasses bootupClasses1(DatabaseConfig config) {
List<Class<?>> entityClasses = config.getClasses();
if (config.isDisableClasspathSearch() || (entityClasses != null && !entityClasses.isEmpty())) {
// use classes we explicitly added via configuration
return new BootupClasses(entityClasses);
}
return BootupClassPathSearch.search(config);
}
@@ -205,7 +198,6 @@ public class DefaultContainer implements SpiContainer {
* Set the DatabasePlatform if it has not already been set.
*/
private void setDatabasePlatform(DatabaseConfig config) {
DatabasePlatform platform = config.getDatabasePlatform();
if (platform == null) {
if (config.getTenantMode().isDynamicDataSource()) {
@@ -215,7 +207,6 @@ public class DefaultContainer implements SpiContainer {
platform = new DatabasePlatformFactory().create(config);
config.setDatabasePlatform(platform);
}
logger.info("DatabasePlatform name:{} platform:{}", config.getName(), platform.getName());
platform.configure(config.getPlatformConfig());
}
@@ -255,6 +246,9 @@ public class DefaultContainer implements SpiContainer {
}
throw new RuntimeException("DataSource not set?");
}
if (config.skipDataSourceCheck()) {
return true;
}
try (Connection connection = config.getDataSource().getConnection()) {
if (connection.getAutoCommit()) {
logger.warn("DataSource [{}] has autoCommit defaulting to true!", config.getName());
@@ -19,7 +19,7 @@ import java.util.List;
/**
* DefaultServer based implementation of MetaInfoManager.
*/
public class DefaultMetaInfoManager implements MetaInfoManager {
final class DefaultMetaInfoManager implements MetaInfoManager {
private final DefaultServer server;
@@ -6,7 +6,7 @@ import io.ebean.meta.MetaQueryPlan;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class DefaultQueryPlanListener implements QueryPlanListener {
final class DefaultQueryPlanListener implements QueryPlanListener {
static final QueryPlanListener INSTANT = new DefaultQueryPlanListener();
@@ -18,8 +18,8 @@ class DefaultQueryPlanListener implements QueryPlanListener {
String dbName = capture.getDatabase().getName();
for (MetaQueryPlan plan : capture.getPlans()) {
log.info("queryPlan db:{} label:{} queryTimeMicros:{} loc:{} sql:{} bind:{} plan:{}",
dbName, plan.getLabel(), plan.getQueryTimeMicros(), plan.getProfileLocation(),
plan.getSql(), plan.getBind(), plan.getPlan());
dbName, plan.label(), plan.queryTimeMicros(), plan.profileLocation(),
plan.sql(), plan.bind(), plan.plan());
}
}
}
@@ -397,6 +397,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (dbSchema != null) {
migrationRunner.setDefaultDbSchema(dbSchema);
}
migrationRunner.setPlatform(config.getDatabasePlatform().getPlatform().base().name().toLowerCase());
migrationRunner.loadProperties(config.getProperties());
migrationRunner.run(config.getDataSource());
}
@@ -415,8 +416,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private void collectQueryPlans() {
QueryPlanRequest request = new QueryPlanRequest();
request.setMaxCount(config.getQueryPlanCaptureMaxCount());
request.setMaxTimeMillis(config.getQueryPlanCaptureMaxTimeMillis());
request.maxCount(config.getQueryPlanCaptureMaxCount());
request.maxTimeMillis(config.getQueryPlanCaptureMaxTimeMillis());
// obtains query explain plans ...
List<MetaQueryPlan> plans = metaInfoManager.queryPlanCollectNow(request);
@@ -489,6 +490,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
}
@Override
public String toString() {
return "Database{" + serverName + "}";
}
/**
* Return the server name.
*/
@@ -525,8 +531,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Compile a query. Only valid for ORM queries.
*/
@Override
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> qr = createQueryRequest(Type.SUBQUERY, query, t);
public <T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> qr = createQueryRequest(type, query, t);
OrmQueryRequest<T> orm = (OrmQueryRequest<T>) qr;
return cqueryEngine.buildQuery(orm);
}
@@ -2054,17 +2060,15 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return transactionManager;
}
public void register(BeanPersistController c) {
List<BeanDescriptor<?>> list = beanDescriptorManager.getBeanDescriptorList();
for (BeanDescriptor<?> aList : list) {
aList.register(c);
public void register(BeanPersistController controller) {
for (BeanDescriptor<?> desc : beanDescriptorManager.getBeanDescriptorList()) {
desc.register(controller);
}
}
public void deregister(BeanPersistController c) {
List<BeanDescriptor<?>> list = beanDescriptorManager.getBeanDescriptorList();
for (BeanDescriptor<?> aList : list) {
aList.deregister(c);
for (BeanDescriptor<?> desc : beanDescriptorManager.getBeanDescriptorList()) {
desc.deregister(c);
}
}
@@ -2327,13 +2331,13 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void visitMetrics(MetricVisitor visitor) {
visitor.visitStart();
if (visitor.isCollectTransactionMetrics()) {
if (visitor.collectTransactionMetrics()) {
transactionManager.visitMetrics(visitor);
}
if (visitor.isCollectL2Metrics()) {
if (visitor.collectL2Metrics()) {
serverCacheManager.visitMetrics(visitor);
}
if (visitor.isCollectQueryMetrics()) {
if (visitor.collectQueryMetrics()) {
beanDescriptorManager.visitMetrics(visitor);
dtoBeanManager.visitMetrics(visitor);
relationalQueryEngine.visitMetrics(visitor);
@@ -2350,7 +2354,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
List<MetaQueryPlan> queryPlanInit(QueryPlanInit initRequest) {
if (initRequest.isAll()) {
queryPlanManager.setDefaultThreshold(initRequest.getThresholdMicros());
queryPlanManager.setDefaultThreshold(initRequest.thresholdMicros());
}
return beanDescriptorManager.queryPlanInit(initRequest);
}
@@ -9,13 +9,12 @@ import org.slf4j.LoggerFactory;
/**
* Default slow query listener implementation that logs a warning message.
*/
class DefaultSlowQueryListener implements SlowQueryListener {
final class DefaultSlowQueryListener implements SlowQueryListener {
private static final Logger log = LoggerFactory.getLogger("io.ebean.SlowQuery");
@Override
public void process(SlowQueryEvent event) {
String firstStack = "";
ObjectGraphNode node = event.getOriginNode();
if (node != null) {
@@ -12,7 +12,7 @@ import java.util.Map;
* This intentionally does not include any OneToMany or ManyToMany properties.
* </p>
*/
public class DiffHelp {
public final class DiffHelp {
private DiffHelp() {
}
@@ -28,11 +28,9 @@ public class DiffHelp {
* </p>
*/
public static Map<String, ValuePair> diff(Object newBean, Object oldBean, BeanDescriptor<?> desc) {
if (!(newBean instanceof EntityBean)) {
throw new IllegalArgumentException("First bean expected to be an enhanced EntityBean? bean:" + newBean);
}
if (oldBean != null) {
if (!(oldBean instanceof EntityBean)) {
throw new IllegalArgumentException("Second bean expected to be an enhanced EntityBean? bean:" + oldBean);
@@ -41,11 +39,9 @@ public class DiffHelp {
throw new IllegalArgumentException("Second bean not assignable to the first bean?");
}
}
if (oldBean == null) {
return ((EntityBean) newBean)._ebean_getIntercept().getDirtyValues();
}
return desc.diff((EntityBean) newBean, (EntityBean) oldBean);
}
@@ -28,11 +28,8 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
private static final String ENC_PREFIX_UPPER = EncryptAlias.PREFIX.toUpperCase();
private final SpiDtoQuery<T> query;
private final DtoQueryEngine queryEngine;
private DtoQueryPlan plan;
private DataReader dataReader;
DtoQueryRequest(SpiEbeanServer server, DtoQueryEngine engine, SpiDtoQuery<T> query) {
@@ -10,14 +10,12 @@ import io.ebeaninternal.api.SpiEbeanServer;
import java.util.Comparator;
import java.util.List;
class DumpMetrics {
final class DumpMetrics {
private final SpiEbeanServer server;
private final String options;
private final String nameFormat;
private final String nameFormatTimed;
private boolean dumpHash;
private boolean dumpSql;
private boolean dumpLoc;
@@ -78,11 +76,11 @@ class DumpMetrics {
out("-- Dumping metrics for " + server.getName() + " -- ");
ServerMetrics serverMetrics = server.getMetaInfoManager().collectMetrics();
for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
for (MetaTimedMetric metric : serverMetrics.timedMetrics()) {
log(metric);
}
List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
List<MetaCountMetric> countMetrics = serverMetrics.countMetrics();
if (!countMetrics.isEmpty()) {
out("\n-- Counters --");
countMetrics.sort(SortMetric.COUNT_NAME);
@@ -91,7 +89,7 @@ class DumpMetrics {
}
}
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
List<MetaQueryMetric> queryMetrics = serverMetrics.queryMetrics();
if (!queryMetrics.isEmpty()) {
out("\n-- Queries --");
queryMetrics.sort(sortBy);
@@ -104,8 +102,8 @@ class DumpMetrics {
private void logCount(MetaCountMetric metric) {
StringBuilder sb = new StringBuilder();
sb.append(padNameTimed(metric.getName())).append(" ");
sb.append(" count:").append(pad(metric.getCount()));
sb.append(padNameTimed(metric.name())).append(" ");
sb.append(" count:").append(pad(metric.count()));
out(sb.toString());
}
@@ -120,38 +118,38 @@ class DumpMetrics {
appendQueryName(metric, sb);
appendCounters(metric, sb);
if (dumpHash) {
sb.append("\n hash:").append(metric.getHash());
sb.append("\n hash:").append(metric.hash());
}
appendProfileAndSql(metric, sb);
out(sb.toString());
}
private void appendQueryName(MetaQueryMetric metric, StringBuilder sb) {
sb.append("query:").append(padName(metric.getName())).append(" ");
sb.append("query:").append(padName(metric.name())).append(" ");
}
private void appendProfileAndSql(MetaQueryMetric metric, StringBuilder sb) {
String location = metric.getLocation();
String location = metric.location();
if (dumpLoc && location != null) {
sb.append("\n loc:").append(location);
}
if (dumpSql) {
sb.append(" \n\n sql:").append(metric.getSql()).append("\n\n");
sb.append(" \n\n sql:").append(metric.sql()).append("\n\n");
}
}
private void log(MetaTimedMetric metric) {
StringBuilder sb = new StringBuilder();
sb.append(padNameTimed(metric.getName())).append(" ");
sb.append(padNameTimed(metric.name())).append(" ");
appendCounters(metric, sb);
out(sb.toString());
}
private void appendCounters(MetaTimedMetric timedMetric, StringBuilder sb) {
sb.append(" count:").append(pad(timedMetric.getCount()))
.append(" total:").append(pad(timedMetric.getTotal()))
.append(" mean:").append(pad(timedMetric.getMean()))
.append(" max:").append(pad(timedMetric.getMax()));
sb.append(" count:").append(pad(timedMetric.count()))
.append(" total:").append(pad(timedMetric.total()))
.append(" mean:").append(pad(timedMetric.mean()))
.append(" max:").append(pad(timedMetric.max()));
}
private String padName(String name) {
@@ -14,10 +14,9 @@ import java.util.List;
/**
* Dump the metrics into a list of MetricData.
*/
class DumpMetricsData {
final class DumpMetricsData {
private final Database database;
private final List<MetricData> list = new ArrayList<>();
DumpMetricsData(Database database) {
@@ -30,10 +29,9 @@ class DumpMetricsData {
}
private void collect(ServerMetrics serverMetrics) {
final List<MetaTimedMetric> timedMetrics = serverMetrics.getTimedMetrics();
final List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
final List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
final List<MetaTimedMetric> timedMetrics = serverMetrics.timedMetrics();
final List<MetaCountMetric> countMetrics = serverMetrics.countMetrics();
final List<MetaQueryMetric> queryMetrics = serverMetrics.queryMetrics();
for (MetaTimedMetric metric : timedMetrics) {
add(metric);
@@ -47,7 +45,7 @@ class DumpMetricsData {
}
private MetricData create(MetaMetric metric) {
MetricData data = new MetricData(metric.getName());
MetricData data = new MetricData(metric.name());
list.add(data);
return data;
}
@@ -55,30 +53,30 @@ class DumpMetricsData {
private void add(MetaTimedMetric metric) {
final MetricData data = create(metric);
appendCounters(data, metric);
data.setLoc(metric.getLocation());
data.setLoc(metric.location());
}
private void addCount(MetaCountMetric metric) {
final MetricData data = create(metric);
data.setCount(metric.getCount());
data.setCount(metric.count());
}
private void addQuery(MetaQueryMetric metric) {
final MetricData data = create(metric);
appendCounters(data, metric);
appendLocationAndSql(data, metric);
data.setHash(metric.getHash());
data.setHash(metric.hash());
}
private void appendLocationAndSql(MetricData data, MetaQueryMetric metric) {
data.setLoc(metric.getLocation());
data.setSql(metric.getSql());
data.setLoc(metric.location());
data.setSql(metric.sql());
}
private void appendCounters(MetricData data, MetaTimedMetric timedMetric) {
data.setCount(timedMetric.getCount());
data.setTotal(timedMetric.getTotal());
data.setMean(timedMetric.getMean());
data.setMax(timedMetric.getMax());
data.setCount(timedMetric.count());
data.setTotal(timedMetric.total());
data.setMean(timedMetric.mean());
data.setMax(timedMetric.max());
}
}
@@ -14,23 +14,18 @@ import java.io.StringWriter;
import java.util.Comparator;
import java.util.List;
class DumpMetricsJson implements ServerMetricsAsJson {
final class DumpMetricsJson implements ServerMetricsAsJson {
private final Database database;
private Appendable writer;
/**
* By default include sql and location attributes for the initial collection only.
*/
private int includeExtraAttributes = 1;
private boolean withHeader = true;
private boolean withHash = true;
private String newLine = "\n";
private Comparator<MetaTimedMetric> sortBy = SortMetric.NAME;
private int listCounter;
private int objKeyCounter;
@@ -84,11 +79,11 @@ class DumpMetricsJson implements ServerMetricsAsJson {
private void collect(ServerMetrics serverMetrics) {
try {
start();
for (MetaTimedMetric metric : serverMetrics.getTimedMetrics()) {
for (MetaTimedMetric metric : serverMetrics.timedMetrics()) {
logTimed(metric);
}
List<MetaCountMetric> countMetrics = serverMetrics.getCountMetrics();
List<MetaCountMetric> countMetrics = serverMetrics.countMetrics();
if (!countMetrics.isEmpty()) {
if (sortBy != null) {
countMetrics.sort(SortMetric.COUNT_NAME);
@@ -98,7 +93,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
}
}
List<MetaQueryMetric> queryMetrics = serverMetrics.getQueryMetrics();
List<MetaQueryMetric> queryMetrics = serverMetrics.queryMetrics();
if (!queryMetrics.isEmpty()) {
if (sortBy != null) {
queryMetrics.sort(sortBy);
@@ -170,7 +165,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
}
objStart();
key("name");
val(metric.getName());
val(metric.name());
}
private void metricEnd() throws IOException {
@@ -180,7 +175,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
private void logCount(MetaCountMetric metric) throws IOException {
metricStart(metric);
key("count");
val(metric.getCount());
val(metric.count());
metricEnd();
}
@@ -188,7 +183,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
metricStart(metric);
appendTiming(metric);
if (isIncludeDetail(metric)) {
appendExtra("loc", metric.getLocation());
append("loc", metric.location());
}
metricEnd();
}
@@ -197,11 +192,11 @@ class DumpMetricsJson implements ServerMetricsAsJson {
metricStart(metric);
appendTiming(metric);
if (withHash) {
appendExtra("hash", metric.getHash());
append("hash", metric.hash());
}
if (isIncludeDetail(metric)) {
appendExtra("loc", metric.getLocation());
appendExtra("sql", metric.getSql());
append("loc", metric.location());
append("sql", metric.sql());
}
metricEnd();
}
@@ -210,7 +205,7 @@ class DumpMetricsJson implements ServerMetricsAsJson {
return includeExtraAttributes == 2 || includeExtraAttributes == 1 && metric.initialCollection();
}
private void appendExtra(String key, String val) throws IOException {
private void append(String key, String val) throws IOException {
if (val != null) {
key(key);
val(val);
@@ -218,13 +213,14 @@ class DumpMetricsJson implements ServerMetricsAsJson {
}
private void appendTiming(MetaTimedMetric timedMetric) throws IOException {
key("count");
val(timedMetric.getCount());
key("total");
val(timedMetric.getTotal());
key("mean");
val(timedMetric.getMean());
key("max");
val(timedMetric.getMax());
append("count", timedMetric.count());
append("total", timedMetric.total());
append("mean", timedMetric.mean());
append("max", timedMetric.max());
}
private void append(String key, long value) throws IOException {
key(key);
val(value);
}
}
@@ -12,10 +12,9 @@ import javax.sql.DataSource;
/**
* Initialise the main DataSource and read-only DataSource.
*/
class InitDataSource {
final class InitDataSource {
private final JndiDataSourceLookup jndiDataSourceFactory = new JndiDataSourceLookup();
private final DatabaseConfig config;
/**
@@ -14,7 +14,7 @@ import java.util.Map;
/**
* Reads the Xml deployment information.
*/
class InternalConfigXmlMap {
final class InternalConfigXmlMap {
private static final Logger log = LoggerFactory.getLogger(InternalConfigXmlMap.class);
@@ -113,7 +113,7 @@ import java.util.ServiceLoader;
* Used to extend the DatabaseConfig with additional objects used to configure and
* construct an Database.
*/
public class InternalConfiguration {
public final class InternalConfiguration {
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
@@ -9,10 +9,7 @@ import javax.sql.DataSource;
/**
* Helper to lookup a DataSource from JNDI.
*/
public class JndiDataSourceLookup {
public JndiDataSourceLookup() {
}
class JndiDataSourceLookup {
/**
* Return the DataSource by JNDI lookup.
@@ -21,7 +18,6 @@ public class JndiDataSourceLookup {
* </p>
*/
public DataSource lookup(String jndiName) {
try {
Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup(jndiName);
@@ -15,11 +15,10 @@ import java.util.logging.Logger;
/**
* DataSource supplier that changes DB catalog based on current Tenant Id.
*/
public class MultiTenantDbCatalogSupplier implements DataSourceSupplier {
final class MultiTenantDbCatalogSupplier implements DataSourceSupplier {
private final DataSource dataSource;
private final DataSource readOnlyDataSource;
private final CatalogDataSource catalogDataSource;
private final CatalogDataSource readOnly;
@@ -15,11 +15,10 @@ import java.util.logging.Logger;
/**
* DataSource supplier that changes DB schema based on current Tenant Id.
*/
class MultiTenantDbSchemaSupplier implements DataSourceSupplier {
final class MultiTenantDbSchemaSupplier implements DataSourceSupplier {
private final DataSource dataSource;
private final DataSource readOnlyDataSource;
private final SchemaDataSource schemaDataSource;
private final SchemaDataSource readOnly;
@@ -11,10 +11,9 @@ import java.sql.SQLException;
/**
* DataSource supplier based on DataSource per Tenant.
*/
class MultiTenantDbSupplier implements DataSourceSupplier {
final class MultiTenantDbSupplier implements DataSourceSupplier {
private final CurrentTenantProvider tenantProvider;
private final TenantDataSourceProvider dataSourceProvider;
MultiTenantDbSupplier(CurrentTenantProvider tenantProvider, TenantDataSourceProvider dataSourceProvider) {
@@ -6,7 +6,7 @@ import io.ebean.bean.CallStack;
/**
* A CallOriginFactory we can use when we don't use AutoTune.
*/
class NoopCallOriginFactory implements CallOriginFactory {
final class NoopCallOriginFactory implements CallOriginFactory {
private static final StackTraceElement E0 = new StackTraceElement("none", "none", "none", 0);
@@ -11,7 +11,7 @@ import io.ebeaninternal.server.deploy.id.ImportedId;
* Deferred update of a relationship where an Id value is not initially available
* so instead we execute this later as a SqlUpdate statement.
*/
public class PersistDeferredRelationship {
public final class PersistDeferredRelationship {
private final SpiEbeanServer ebeanServer;
private final BeanDescriptor<?> beanDescriptor;
@@ -1,215 +0,0 @@
package io.ebeaninternal.server.core;
/**
* Helper for performing a 'refresh' on an Entity bean.
* <p>
* Note that this does not 'refresh' any OnetoMany or ManyToMany properties. It
* refreshes all the other properties though.
* </p>
*/
public class RefreshHelp {
//
// /**
// * Helper for debug of lazy loading.
// */
// private final DebugLazyLoad debugLazyLoad;
//
// private final MAdminLoggingMBean logControl;
//
// public RefreshHelp(MAdminLoggingMBean logControl, boolean debugLazyLoad){
// this.logControl = logControl;
// this.debugLazyLoad = new DebugLazyLoad(debugLazyLoad);
// }
//
// /**
// * Refresh the bean from property values in dbBean.
// */
// public void refresh(Object o, Object dbBean, BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, boolean isLazyLoad) {
//
// Object originalOldValues = null;
// boolean setOriginalOldValues = false;
//
// // set of properties to exclude from the refresh because it is
// // not a refresh but rather a lazyLoading event.
// Set<String> excludes = null;
//
// // turn off intercepting so lazy loading is
// // not invoked when populating the bean
// // with PropertyChangeSupport
// ebi.setIntercepting(false);
//
// boolean readOnly = ebi.isReadOnly();
// boolean sharedInstance = ebi.isSharedInstance();
//
// if (isLazyLoad){
// excludes = ebi.getLoadedProps();
// if (excludes != null){
// // lazy loading a "Partial Object"... which already
// // contains some properties and perhaps some oldValues
// // and these will need to be maintained...
// originalOldValues = ebi.getOldValues();
// setOriginalOldValues = originalOldValues != null;
// }
//
// if (logControl.isDebugLazyLoad()){
// debug(desc, ebi, id, excludes);
// }
// }
//
//
// BeanProperty[] props = desc.propertiesBaseScalar();
// for (int i = 0; i < props.length; i++) {
// BeanProperty prop = props[i];
// if (excludes != null && excludes.contains(prop.getName())){
// // ignore this property (partial bean lazy loading)
//
// } else {
// Object dbVal = prop.getValue(dbBean);
// if (isLazyLoad) {
// prop.setValue(o, dbVal);
// } else {
// prop.setValueIntercept(o, dbVal);
// }
// if (setOriginalOldValues){
// // maintain original oldValues for partially loaded bean
// prop.setValue(originalOldValues, dbVal);
// }
// }
// }
//
// BeanPropertyAssocOne<?>[] ones = desc.propertiesOne();
// for (int i = 0; i < ones.length; i++) {
// BeanProperty prop = ones[i];
// if (excludes != null && excludes.contains(prop.getName())){
// // ignore this property (partial bean lazy loading)
//
// } else {
// Object dbVal = prop.getValue(dbBean);
// if (isLazyLoad){
// prop.setValue(o, dbVal);
// } else {
// prop.setValueIntercept(o, dbVal);
// }
// if (setOriginalOldValues){
// // maintain original oldValues for partially loaded bean
// prop.setValue(originalOldValues, dbVal);
// }
// if (dbVal != null){
// if (sharedInstance){
// // propagate sharedInstance status to associated beans
// ((EntityBean)dbVal)._ebean_getIntercept().setSharedInstance();
// } else if (readOnly) {
// // propagate readOnly status to associated beans
// ((EntityBean)dbVal)._ebean_getIntercept().setReadOnly(true);
// }
// }
//
// }
// }
//
// refreshEmbedded(o, dbBean, desc, excludes, readOnly);
//
// // set a lazy loading many proxy if required
// BeanPropertyAssocMany<?>[] manys = desc.propertiesMany();
// for (int i = 0; i < manys.length; i++) {
// BeanPropertyAssocMany<?> prop = manys[i];
// if (excludes != null && excludes.contains(prop.getName())){
// // the many already existed on the bean
//
// } else {
// // set a lazy loading proxy
// prop.createReference(o, null, readOnly, sharedInstance);
// }
// }
//
// // the refreshed/lazy loaded bean is always fully
// // populated so set loadedProps to null
// ebi.setLoadedProps(null);
//
//
// // reset the loaded status
// ebi.setLoaded();
// }
//
// /**
// * Refresh the Embedded beans.
// */
// private void refreshEmbedded(Object o, Object dbBean, BeanDescriptor<?> desc, Set<String> excludes, boolean propagateReadOnly) {
//
// BeanPropertyAssocOne<?>[] embeds = desc.propertiesEmbedded();
// for (int i = 0; i < embeds.length; i++) {
// BeanPropertyAssocOne<?> prop = embeds[i];
// if (excludes != null && excludes.contains(prop.getName())){
// // ignore this property
// } else {
// // the original embedded bean
// Object oEmb = prop.getValue(o);
//
// // the new one from the database
// Object dbEmb = prop.getValue(dbBean);
//
// if (oEmb == null){
// // original embedded bean was null
// // so just replace the entire embedded bean
// prop.setValueIntercept(o, dbEmb);
// if (propagateReadOnly && dbEmb != null){
// // propagate readOnly status to embedded beans
// ((EntityBean)dbEmb)._ebean_getIntercept().setReadOnly(true);
// }
//
// } else {
// // refresh each property of the original
// // embedded bean
// if (oEmb instanceof EntityBean){
// // turn off interception to stop invoking lazy loading
// // but allow PropertyChangeSupport
// ((EntityBean) oEmb)._ebean_getIntercept().setIntercepting(false);
// }
//
// BeanProperty[] props = prop.getProperties();
// for (int j = 0; j < props.length; j++) {
// Object v = props[j].getValue(dbEmb);
// props[j].setValueIntercept(oEmb, v);
// }
//
// // No longer calling setLoaded() on embedded bean
// // as the EntityBean itself
// // .. calls setEmbeddedLoaded() on each of
// // .. its embedded beans itself.
// }
// }
// }
// }
//
//
// /**
// * Output some debug to describe the lazy loading event.
// */
// private void debug(BeanDescriptor<?> desc, EntityBeanIntercept ebi, Object id, Set<String> excludes) {
//
//
// Class<?> beanType = desc.getBeanType();
//
// StackTraceElement cause = debugLazyLoad.getStackTraceElement(beanType);
//
// String lazyLoadProperty = ebi.getLazyLoadProperty();
// String msg = "debug.lazyLoad ["+desc+"] id["+id+"] lazyLoadProperty["+lazyLoadProperty+"]";
// if (excludes != null){
// msg += " partialProps"+excludes;
// }
// if (cause != null){
// String causeLine = cause.toString();
// if (causeLine.indexOf(".groovy:") > -1){
// // eclipse console does not like finding groovy source at the moment
// causeLine = StringHelper.replaceString(causeLine, ".groovy:", ".groovy :");
// }
// msg += " at: "+causeLine;
// }
// System.err.println(msg);
// }
//
//
//
}
@@ -18,11 +18,8 @@ import java.util.function.Predicate;
public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
private final RelationalQueryEngine queryEngine;
private String[] propertyNames;
private int estimateCapacity;
private int rows;
/**
@@ -10,10 +10,9 @@ import java.sql.SQLException;
/**
* Simple DataSource supplier when no multi-tenancy used.
*/
class SimpleDataSourceProvider implements DataSourceSupplier {
final class SimpleDataSourceProvider implements DataSourceSupplier {
private final DataSource dataSource;
private final DataSource readOnlyDataSource;
SimpleDataSourceProvider(DataSource dataSource, DataSource readOnlyDataSource) {
@@ -8,7 +8,7 @@ import java.sql.ResultSet;
*
* These both must be closed properly when done.
*/
public class SpiResultSet {
public final class SpiResultSet {
private final PreparedStatement statement;
@@ -1,6 +1,5 @@
package io.ebeaninternal.server.core.bootup;
import io.avaje.classpath.scanner.ClassFilter;
import io.ebean.annotation.DocStore;
import io.ebean.config.DatabaseConfig;
import io.ebean.config.IdGenerator;
@@ -27,27 +26,23 @@ import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
/**
* Interesting classes for a EbeanServer such as Embeddable, Entity,
* ScalarTypes, Finders, Listeners and Controllers.
*/
public class BootupClasses implements ClassFilter {
public class BootupClasses implements Predicate<Class<?>> {
private static final Logger logger = LoggerFactory.getLogger(BootupClasses.class);
private final List<Class<?>> embeddableList = new ArrayList<>();
private final List<Class<?>> entityList = new ArrayList<>();
private final List<Class<? extends ScalarType<?>>> scalarTypeList = new ArrayList<>();
private final List<Class<? extends ScalarTypeConverter<?, ?>>> scalarConverterList = new ArrayList<>();
private final List<Class<? extends AttributeConverter<?, ?>>> attributeConverterList = new ArrayList<>();
// The following objects are instantiated on first request
@@ -55,19 +50,12 @@ public class BootupClasses implements ClassFilter {
// instance list, that holds the instance. Once a class is instantiated
// (or added) it will get removed from the candidate list
private final List<Class<? extends IdGenerator>> idGeneratorCandidates = new ArrayList<>();
private final List<Class<? extends BeanPersistController>> beanPersistControllerCandidates = new ArrayList<>();
private final List<Class<? extends BeanPostLoad>> beanPostLoadCandidates = new ArrayList<>();
private final List<Class<? extends BeanPostConstructListener>> beanPostConstructListenerCandidates = new ArrayList<>();
private final List<Class<? extends BeanFindController>> beanFindControllerCandidates = new ArrayList<>();
private final List<Class<? extends BeanPersistListener>> beanPersistListenerCandidates = new ArrayList<>();
private final List<Class<? extends BeanQueryAdapter>> beanQueryAdapterCandidates = new ArrayList<>();
private final List<Class<? extends ServerConfigStartup>> serverConfigStartupCandidates = new ArrayList<>();
private final List<IdGenerator> idGeneratorInstances = new ArrayList<>();
@@ -98,7 +86,7 @@ public class BootupClasses implements ClassFilter {
public BootupClasses(List<Class<?>> list) {
if (list != null) {
for (Class<?> cls : list) {
isMatch(cls);
test(cls);
}
}
}
@@ -188,13 +176,11 @@ public class BootupClasses implements ClassFilter {
}
public void addChangeLogInstances(DatabaseConfig config) {
readAuditPrepare = config.getReadAuditPrepare();
readAuditLogger = config.getReadAuditLogger();
changeLogPrepare = config.getChangeLogPrepare();
changeLogListener = config.getChangeLogListener();
changeLogRegister = config.getChangeLogRegister();
// if not already set create the implementations found
// via classpath scanning
if (readAuditPrepare == null && readAuditPrepareClass != null) {
@@ -341,18 +327,14 @@ public class BootupClasses implements ClassFilter {
}
@Override
public boolean isMatch(Class<?> cls) {
public boolean test(Class<?> cls) {
if (isEmbeddable(cls)) {
embeddableList.add(cls);
} else if (isEntity(cls)) {
entityList.add(cls);
} else {
return isInterestingInterface(cls);
}
return true;
}
@@ -364,7 +346,6 @@ public class BootupClasses implements ClassFilter {
*/
@SuppressWarnings("unchecked")
private boolean isInterestingInterface(Class<?> cls) {
if (Modifier.isAbstract(cls.getModifiers())) {
// do not include abstract classes as we can
// not instantiate them
@@ -5,7 +5,7 @@ import io.ebeaninternal.server.query.SqlJoinType;
/**
* Helper for BeanPropertyAssocOne for OneToOne exported reference - not so common.
*/
class AssocOneHelpRefExported extends AssocOneHelp {
final class AssocOneHelpRefExported extends AssocOneHelp {
private final boolean softDelete;

Some files were not shown because too many files have changed in this diff Show More