mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
501f8111fe | ||
|
|
d8f4503d98 | ||
|
|
0d83978c58 | ||
|
|
69e56be459 | ||
|
|
35a721039d | ||
|
|
98b4ac5029 | ||
|
|
fe874c946d | ||
|
|
53386e9bf4 | ||
|
|
5435055f5c | ||
|
|
583e10f5c6 | ||
|
|
5393d709a3 | ||
|
|
fc1c9392aa | ||
|
|
6b2c48d4f6 | ||
|
|
400ae3cf4b | ||
|
|
f22a322104 | ||
|
|
e98ff952bf | ||
|
|
573e1b553c | ||
|
|
a674d0d696 | ||
|
|
5393161c16 | ||
|
|
1bdc6d8f7f | ||
|
|
e9081a176f | ||
|
|
3e7db2887f | ||
|
|
fcf14ac222 | ||
|
|
55324653a5 | ||
|
|
a132f09b03 | ||
|
|
48eac84930 | ||
|
|
948619a125 | ||
|
|
0cd0741f18 | ||
|
|
01a3455ecb | ||
|
|
610f7db1cb | ||
|
|
373ef6d1eb | ||
|
|
f1b1cee2fd | ||
|
|
a73e4f23ff | ||
|
|
9a5d3498c1 | ||
|
|
0b24d635ad | ||
|
|
b623e19dae | ||
|
|
7389a8b344 | ||
|
|
d68f477e8e | ||
|
|
dbe273bb56 | ||
|
|
1a4377da29 | ||
|
|
c3cdecaa60 | ||
|
|
9d706056c6 | ||
|
|
cb0100f02a | ||
|
|
9c6dd0989a | ||
|
|
a23a179bbf | ||
|
|
365b7c4600 | ||
|
|
ed2455f460 | ||
|
|
046033627a | ||
|
|
786444a6b9 | ||
|
|
9ab26cfb9d | ||
|
|
aa1e3ea1bc | ||
|
|
c66875449b | ||
|
|
f6c4024ae5 | ||
|
|
2c8cc793ab | ||
|
|
66454d2e61 | ||
|
|
e7b13cf2d9 |
+1
-4
@@ -1,6 +1,4 @@
|
||||
*.autofetch
|
||||
*create-all.sql
|
||||
*drop-all.sql
|
||||
*.orig
|
||||
.classpath
|
||||
.project
|
||||
@@ -12,7 +10,6 @@ ebean-autotune.xml
|
||||
ebean-profiling*.xml
|
||||
/db
|
||||
/mydb.db
|
||||
!src/test/ddl-review/*.sql
|
||||
profiling/
|
||||
|
||||
# Intellij project files
|
||||
@@ -20,4 +17,4 @@ profiling/
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
*uuid.state
|
||||
*uuid.state
|
||||
|
||||
+3
-3
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean api</name>
|
||||
@@ -32,7 +32,7 @@
|
||||
<dependency>
|
||||
<groupId>io.avaje</groupId>
|
||||
<artifactId>avaje-config</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>1.3</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -55,7 +55,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-annotation</artifactId>
|
||||
<version>6.13</version>
|
||||
<version>6.15</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
@@ -1,33 +1,43 @@
|
||||
package io.ebean;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Background thread pool service for executing of tasks asynchronously.
|
||||
* Background executor service for executing of tasks asynchronously.
|
||||
* <p>
|
||||
* This service is used internally by Ebean for executing background tasks such
|
||||
* as the {@link Query#findFutureList()} and also for executing background tasks
|
||||
* periodically.
|
||||
* </p>
|
||||
* This service can be used to execute tasks in the background.
|
||||
* <p>
|
||||
* This service has been made available so you can use it for your application
|
||||
* code if you want. It can be useful for some server caching implementations
|
||||
* (background population and trimming of the cache etc).
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
* This service is managed by Ebean and will perform a clean shutdown
|
||||
* waiting for background tasks to complete with a default 30 second
|
||||
* timeout. Shutdown occurs prior to DataSource shutdown.
|
||||
* <p>
|
||||
* This also propagates MDC context from the current thread to the
|
||||
* background task if defined.
|
||||
*/
|
||||
public interface BackgroundExecutor {
|
||||
|
||||
/**
|
||||
* Execute a task in the background.
|
||||
* Execute a callable task in the background returning the Future.
|
||||
*/
|
||||
void execute(Runnable r);
|
||||
<T> Future<T> submit(Callable<T> task);
|
||||
|
||||
/**
|
||||
* Execute a runnable task in the background returning the Future.
|
||||
*/
|
||||
Future<?> submit(Runnable task);
|
||||
|
||||
/**
|
||||
* Execute a task in the background. Effectively the same as
|
||||
* {@link BackgroundExecutor#submit(Runnable)} but returns void.
|
||||
*/
|
||||
void execute(Runnable task);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically with a fixed delay between each execution.
|
||||
* <p>
|
||||
* For example, execute a runnable every minute.
|
||||
@@ -36,27 +46,64 @@ public interface BackgroundExecutor {
|
||||
* That is, this method has the same behaviour characteristics as
|
||||
* {@link ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)}
|
||||
*/
|
||||
void executePeriodically(Runnable r, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to scheduleWithFixedDelay().
|
||||
* Execute a task periodically additionally with an initial delay different from delay.
|
||||
*/
|
||||
void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit);
|
||||
@Deprecated
|
||||
void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given delay.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param delay the delay between the termination of one
|
||||
* execution and the commencement of the next
|
||||
* @param unit the time unit of the initialDelay and delay parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Execute a task periodically with a given period.
|
||||
*
|
||||
* <p>If any execution of this task takes longer than its period, then
|
||||
* subsequent executions may start late, but will not concurrently
|
||||
* execute.
|
||||
*
|
||||
* @param task the task to execute
|
||||
* @param initialDelay the time to delay first execution
|
||||
* @param period the period between successive executions
|
||||
* @param unit the time unit of the initialDelay and period parameters
|
||||
* @return a ScheduledFuture representing pending completion of
|
||||
* the series of repeated tasks. The future's {@link
|
||||
* Future#get() get()} method will never return normally,
|
||||
* and will throw an exception upon task cancellation or
|
||||
* abnormal termination of a task execution.
|
||||
*/
|
||||
ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Runnable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture representing pending completion of the task and
|
||||
* whose get() method will return null upon completion
|
||||
* whose get() method will return null upon completion
|
||||
*/
|
||||
ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit);
|
||||
ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit);
|
||||
|
||||
/**
|
||||
* Schedules a Callable for one-shot action that becomes enabled after the given delay.
|
||||
*
|
||||
* @return a ScheduledFuture that can be used to extract result or cancel
|
||||
*/
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit);
|
||||
|
||||
<V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public class DatabaseFactory {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static SpiContainer container;
|
||||
|
||||
static {
|
||||
|
||||
@@ -27,7 +27,7 @@ final class DbContext {
|
||||
|
||||
private final HashMap<String, Database> syncMap = new HashMap<>();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The 'default' Database.
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
class DbPrimary {
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static String defaultServerName;
|
||||
private static boolean skip;
|
||||
|
||||
|
||||
@@ -169,14 +169,38 @@ public interface ExpressionList<T> {
|
||||
*/
|
||||
UpdateQuery<T> asUpdate();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdate(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
@@ -188,8 +212,10 @@ public interface ExpressionList<T> {
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateNoWait(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
@@ -201,8 +227,10 @@ public interface ExpressionList<T> {
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Deprecated - migrate to withLock().
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateSkipLocked(Query.LockType lockType);
|
||||
|
||||
/**
|
||||
|
||||
@@ -184,7 +184,8 @@ public interface Query<T> {
|
||||
*/
|
||||
enum LockType {
|
||||
/**
|
||||
* The default lock type - See PlatformConfig.forUpdateNoKey option.
|
||||
* The default lock type being either UPDATE or NO_KEY_UPDATE based on
|
||||
* PlatformConfig.forUpdateNoKey configuration (Postgres option).
|
||||
*/
|
||||
DEFAULT,
|
||||
|
||||
@@ -194,17 +195,17 @@ public interface Query<T> {
|
||||
UPDATE,
|
||||
|
||||
/**
|
||||
* FOR NO KEY UPDATE.
|
||||
* FOR NO KEY UPDATE (Postgres only).
|
||||
*/
|
||||
NO_KEY_UPDATE,
|
||||
|
||||
/**
|
||||
* FOR SHARE UPDATE.
|
||||
* FOR SHARE (Postgres only).
|
||||
*/
|
||||
SHARE,
|
||||
|
||||
/**
|
||||
* FOR KEY SHARE UPDATE.
|
||||
* FOR KEY SHARE (Postgres only).
|
||||
*/
|
||||
KEY_SHARE
|
||||
}
|
||||
@@ -1643,40 +1644,69 @@ public interface Query<T> {
|
||||
*/
|
||||
String getGeneratedSql();
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and WAIT.
|
||||
* <p>
|
||||
* Note that <code>forUpdate()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute the query with the given lock type and lock wait.
|
||||
* <p>
|
||||
* Note that <code>forUpdateNoWait()</code> is the same as
|
||||
* <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
* <p>
|
||||
* Provides us with the ability to explicitly use Postgres
|
||||
* SHARE, KEY SHARE, NO KEY UPDATE and UPDATE row locks.
|
||||
*/
|
||||
Query<T> withLock(LockType lockType, LockWait lockWait);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause which results in the DB locking the record.
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.WAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdate();
|
||||
|
||||
/**
|
||||
* Execute using "for update" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdate(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "no wait" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.NOWAIT)</code>.
|
||||
*/
|
||||
Query<T> forUpdateNoWait();
|
||||
|
||||
/**
|
||||
* Execute using "for update nowait" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateNoWait(LockType lockType);
|
||||
|
||||
/**
|
||||
* Execute using "for update" clause with "skip locked" option.
|
||||
* <p>
|
||||
* This is typically a Postgres and Oracle only option at this stage.
|
||||
* </p>
|
||||
* <p>
|
||||
* The same as <code>withLock(LockType.UPDATE, LockWait.SKIPLOCKED)</code>.
|
||||
*/
|
||||
Query<T> forUpdateSkipLocked();
|
||||
|
||||
/**
|
||||
* Execute using "for update skip locked" with given lock type (currently Postgres only).
|
||||
*/
|
||||
@Deprecated
|
||||
Query<T> forUpdateSkipLocked(LockType lockType);
|
||||
|
||||
/**
|
||||
|
||||
@@ -519,11 +519,11 @@ public interface Transaction extends AutoCloseable {
|
||||
void flush() throws PersistenceException;
|
||||
|
||||
/**
|
||||
* This is a synonym for flush() and will be deprecated.
|
||||
* Deprecated - migrate to flush().
|
||||
* <p>
|
||||
* flush() is preferred as it matches the JPA flush() method.
|
||||
* </p>
|
||||
*/
|
||||
@Deprecated
|
||||
void flushBatch() throws PersistenceException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ public final class EntityBeanIntercept implements Serializable {
|
||||
private static final int STATE_REFERENCE = 1;
|
||||
private static final int STATE_LOADED = 2;
|
||||
|
||||
private transient final ReentrantLock lock = new ReentrantLock(false);
|
||||
private transient final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private transient NodeUsageCollector nodeUsageCollector;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public abstract class SingleBeanLoader implements BeanLoader {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected final Database database;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ abstract class AbstractBeanCollection<E> implements BeanCollection<E> {
|
||||
|
||||
private static final long serialVersionUID = 3365725236140187588L;
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected boolean readOnly;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public final class CopyOnFirstWriteList<E> extends AbstractList<E> implements Li
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The underlying List implementation.
|
||||
|
||||
@@ -26,9 +26,7 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final ReentrantLock loadLock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The actual sequence name.
|
||||
|
||||
@@ -23,7 +23,7 @@ public final class ShutdownManager {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final List<Database> databases = new ArrayList<>();
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</parent>
|
||||
<!-- <parent>-->
|
||||
<!-- <groupId>org.avaje</groupId>-->
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.6.1</tag>
|
||||
<tag>ebean-parent-12.6.5</tag>
|
||||
</scm>
|
||||
|
||||
<name>ebean autotune</name>
|
||||
@@ -26,7 +26,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
<configuration>
|
||||
<tiles>
|
||||
<!-- other tiles ... -->
|
||||
<tile>io.ebean.tile:enhancement:12.5.0</tile>
|
||||
<tile>io.ebean.tile:enhancement:12.6.0</tile>
|
||||
</tiles>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
+2
-2
@@ -23,7 +23,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoTuneService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final SpiEbeanServer server;
|
||||
|
||||
@@ -77,7 +77,7 @@ public class DefaultAutoTuneService implements AutoTuneService {
|
||||
loadTuningFile();
|
||||
if (isRuntimeTuningUpdates()) {
|
||||
// periodically gather and update query tuning
|
||||
server.getBackgroundExecutor().executePeriodically(new ProfilingUpdate(), profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
server.getBackgroundExecutor().scheduleWithFixedDelay(new ProfilingUpdate(), profilingUpdateFrequency, profilingUpdateFrequency, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
public class ProfileManager implements ProfilingListener {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final boolean queryTuningAddVersion;
|
||||
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class ProfileOrigin {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final long RESET_COUNT = -1000000000L;
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ public class ProfileOriginNodeUsage {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ProfileOriginNodeUsage.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final String path;
|
||||
|
||||
|
||||
+34
-16
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</parent>
|
||||
|
||||
<name>ebean bom</name>
|
||||
@@ -15,11 +15,11 @@
|
||||
<properties>
|
||||
<ebean-ddl-runner.version>1.0</ebean-ddl-runner.version>
|
||||
<ebean-migration-auto.version>1.0</ebean-migration-auto.version>
|
||||
<ebean-migration.version>12.2.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.0</ebean-test-docker.version>
|
||||
<ebean-migration.version>12.4.0</ebean-migration.version>
|
||||
<ebean-test-docker.version>4.1</ebean-test-docker.version>
|
||||
<ebean-datasource.version>7.0</ebean-datasource.version>
|
||||
<ebean-agent.version>12.6.0</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.6.0</ebean-maven-plugin.version>
|
||||
<ebean-agent.version>12.6.2</ebean-agent.version>
|
||||
<ebean-maven-plugin.version>12.6.2</ebean-maven-plugin.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
@@ -81,72 +81,90 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-xml</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-autotune</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-querybean</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>querybean-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>kotlin-querybean-generator</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-postgis</artifactId>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-redis</artifactId>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<name>ebean core type</name>
|
||||
<description>ebean scalar types api</description>
|
||||
|
||||
<properties>
|
||||
<jackson-core.version>2.11.3</jackson-core.version>
|
||||
@@ -19,7 +21,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
||||
+8
-8
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<artifactId>ebean-parent</artifactId>
|
||||
<groupId>io.ebean</groupId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>ebean-core</artifactId>
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<scm>
|
||||
<developerConnection>scm:git:git@github.com:ebean-orm/ebean.git</developerConnection>
|
||||
<tag>ebean-parent-12.6.1</tag>
|
||||
<tag>ebean-parent-12.6.5</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
@@ -70,14 +70,14 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-migration</artifactId>
|
||||
<version>12.2.0</version>
|
||||
<version>12.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-ddl-generator</artifactId>
|
||||
<version>12.6.1.PreRelease.0</version>
|
||||
<version>12.6.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -92,19 +92,19 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-core-type</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-externalmapping-api</artifactId>
|
||||
<version>12.6.1</version>
|
||||
<version>12.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -202,7 +202,7 @@
|
||||
<dependency>
|
||||
<groupId>io.ebean</groupId>
|
||||
<artifactId>ebean-test-docker</artifactId>
|
||||
<version>4.0</version>
|
||||
<version>4.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -318,4 +318,20 @@ public interface SpiTransaction extends Transaction {
|
||||
* Return true if explicitly set to skip cache (ignores skipOnWrite).
|
||||
*/
|
||||
boolean isSkipCacheExplicit();
|
||||
|
||||
/**
|
||||
* Fire pre commit processing/listeners.
|
||||
*/
|
||||
void preCommit();
|
||||
|
||||
/**
|
||||
* Fire post commit events and listeners.
|
||||
*/
|
||||
void postCommit();
|
||||
|
||||
/**
|
||||
* Fire post rollback events and listeners.
|
||||
*/
|
||||
void postRollback(Throwable cause);
|
||||
|
||||
}
|
||||
|
||||
@@ -418,4 +418,18 @@ public abstract class SpiTransactionProxy implements SpiTransaction {
|
||||
transaction.flushBatchOnCollection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
transaction.preCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCommit() {
|
||||
transaction.postCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRollback(Throwable cause) {
|
||||
transaction.postRollback(cause);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ class DefaultCacheHolder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final ConcurrentHashMap<String, ServerCache> allCaches = new ConcurrentHashMap<>();
|
||||
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class DefaultServerCache implements ServerCache {
|
||||
|
||||
// default to trimming the cache every 60 seconds
|
||||
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
|
||||
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
|
||||
executor.scheduleWithFixedDelay(trim, trimFreqSecs, trimFreqSecs, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,7 @@ public class ClusterManager implements ServerLookup {
|
||||
|
||||
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final ConcurrentHashMap<String, EbeanServer> serverMap = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
+14
-22
@@ -27,7 +27,7 @@ public abstract class AbstractSqlQueryRequest {
|
||||
|
||||
protected final SpiEbeanServer server;
|
||||
|
||||
protected SpiTransaction trans;
|
||||
protected SpiTransaction transaction;
|
||||
|
||||
private boolean createdTransaction;
|
||||
|
||||
@@ -47,18 +47,18 @@ public abstract class AbstractSqlQueryRequest {
|
||||
AbstractSqlQueryRequest(SpiEbeanServer server, SpiSqlBinding query, Transaction t) {
|
||||
this.server = server;
|
||||
this.query = query;
|
||||
this.trans = (SpiTransaction) t;
|
||||
this.transaction = (SpiTransaction) t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a transaction if none currently exists.
|
||||
*/
|
||||
public void initTransIfRequired() {
|
||||
if (trans == null) {
|
||||
trans = server.currentServerTransaction();
|
||||
if (trans == null || !trans.isActive()) {
|
||||
if (transaction == null) {
|
||||
transaction = server.currentServerTransaction();
|
||||
if (transaction == null || !transaction.isActive()) {
|
||||
// create a local readOnly transaction
|
||||
trans = server.createReadOnlyTransaction(null);
|
||||
transaction = server.createReadOnlyTransaction(null);
|
||||
createdTransaction = true;
|
||||
}
|
||||
}
|
||||
@@ -69,20 +69,18 @@ public abstract class AbstractSqlQueryRequest {
|
||||
*/
|
||||
public void endTransIfRequired() {
|
||||
if (createdTransaction) {
|
||||
trans.commit();
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
public EbeanServer getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public SpiTransaction getTransaction() {
|
||||
return trans;
|
||||
protected void flushJdbcBatchOnQuery() {
|
||||
if (transaction.isFlushOnQuery()) {
|
||||
transaction.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isLogSql() {
|
||||
return trans.isLogSql();
|
||||
return transaction.isLogSql();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +118,6 @@ public abstract class AbstractSqlQueryRequest {
|
||||
* Prepare the SQL taking into account named bind parameters.
|
||||
*/
|
||||
private void prepareSql() {
|
||||
|
||||
String sql = query.getQuery();
|
||||
BindParams bindParams = query.getBindParams();
|
||||
if (!bindParams.isEmpty()) {
|
||||
@@ -131,7 +128,6 @@ public abstract class AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
private String limitOffset(String sql) {
|
||||
|
||||
int firstRow = query.getFirstRow();
|
||||
int maxRows = query.getMaxRows();
|
||||
if (firstRow > 0 || maxRows > 0) {
|
||||
@@ -149,10 +145,8 @@ public abstract class AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
protected void executeAsSql(Binder binder) throws SQLException {
|
||||
|
||||
prepareSql();
|
||||
Connection conn = trans.getInternalConnection();
|
||||
|
||||
Connection conn = transaction.getInternalConnection();
|
||||
pstmt = conn.prepareStatement(sql);
|
||||
if (query.getTimeout() > 0) {
|
||||
pstmt.setQueryTimeout(query.getTimeout());
|
||||
@@ -160,14 +154,12 @@ public abstract class AbstractSqlQueryRequest {
|
||||
if (query.getBufferFetchSizeHint() > 0) {
|
||||
pstmt.setFetchSize(query.getBufferFetchSizeHint());
|
||||
}
|
||||
|
||||
BindParams bindParams = query.getBindParams();
|
||||
if (!bindParams.isEmpty()) {
|
||||
this.bindLog = binder.bind(bindParams, pstmt, conn);
|
||||
}
|
||||
|
||||
if (isLogSql()) {
|
||||
trans.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
|
||||
transaction.logSql(Str.add(TrimLogSql.trim(sql), "; --bind(", bindLog, ")"));
|
||||
}
|
||||
|
||||
setResultSet(pstmt.executeQuery(), null);
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.server.lib.DaemonExecutorService;
|
||||
import io.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
private final DaemonExecutorService pool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonExecutorService(shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix + "-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
@Override
|
||||
public void execute(Runnable r) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
pool.execute(r);
|
||||
} else {
|
||||
pool.execute(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
executePeriodically(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable r, long initialDelay, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
schedulePool.scheduleWithFixedDelay(r, initialDelay, delay, unit);
|
||||
} else {
|
||||
schedulePool.scheduleWithFixedDelay(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, initialDelay, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable r, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return schedulePool.schedule(r, delay, unit);
|
||||
} else {
|
||||
return schedulePool.schedule(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
r.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> c, long delay, TimeUnit unit) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return schedulePool.schedule(c, delay, unit);
|
||||
} else {
|
||||
return schedulePool.schedule(() -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return c.call();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
}, delay, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,14 +10,15 @@ import io.ebean.config.TenantMode;
|
||||
import io.ebean.config.UnderscoreNamingConvention;
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.config.dbplatform.h2.H2Platform;
|
||||
import io.ebean.event.ShutdownManager;
|
||||
import io.ebean.service.SpiContainer;
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import io.ebeaninternal.api.SpiEbeanServer;
|
||||
import io.ebeaninternal.api.DbOffline;
|
||||
import io.ebeaninternal.server.cluster.ClusterManager;
|
||||
import io.ebeaninternal.server.core.bootup.BootupClassPathSearch;
|
||||
import io.ebeaninternal.server.core.bootup.BootupClasses;
|
||||
import io.ebean.event.ShutdownManager;
|
||||
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -35,7 +36,7 @@ public class DefaultContainer implements SpiContainer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger("io.ebean.internal.DefaultContainer");
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
public DefaultContainer(ContainerConfig containerConfig) {
|
||||
|
||||
@@ -161,7 +161,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultServer.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final DatabaseConfig config;
|
||||
private final String serverName;
|
||||
private final DatabasePlatform databasePlatform;
|
||||
@@ -451,16 +451,20 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
|
||||
backgroundExecutor.shutdown();
|
||||
// shutdown DataSource (if its an Ebean one)
|
||||
transactionManager.shutdown(shutdownDataSource, deregisterDriver);
|
||||
dumpMetrics();
|
||||
shutdown = true;
|
||||
if (shutdownDataSource) {
|
||||
config.setDataSource(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdownPlugins() {
|
||||
private void dumpMetrics() {
|
||||
if (config.isDumpMetricsOnShutdown()) {
|
||||
new DumpMetrics(this, config.getDumpMetricsOptions()).dump();
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdownPlugins() {
|
||||
for (Plugin plugin : serverPlugins) {
|
||||
try {
|
||||
plugin.shutdown();
|
||||
|
||||
@@ -50,7 +50,7 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
ormQuery.setManualId();
|
||||
|
||||
// execute the underlying ORM query returning the ResultSet
|
||||
SpiResultSet result = server.findResultSet(ormQuery, trans);
|
||||
SpiResultSet result = server.findResultSet(ormQuery, transaction);
|
||||
this.pstmt = result.getStatement();
|
||||
this.sql = ormQuery.getGeneratedSql();
|
||||
setResultSet(result.getResultSet(), ormQuery.getQueryPlanKey());
|
||||
@@ -88,14 +88,17 @@ public final class DtoQueryRequest<T> extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public void findEach(Consumer<T> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public void findEachWhile(Predicate<T> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEachWhile(this, consumer);
|
||||
}
|
||||
|
||||
public List<T> findList() {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findList(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public final class InternString {
|
||||
|
||||
private static final HashMap<String, String> map = new HashMap<>();
|
||||
|
||||
private static final ReentrantLock lock = new ReentrantLock(false);
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Return the shared instance of this string.
|
||||
|
||||
@@ -388,7 +388,7 @@ public final class PersistRequestBean<T> extends PersistRequest implements BeanP
|
||||
@Override
|
||||
public void preGetterTrigger(int propertyIndex) {
|
||||
if (flushBatchOnGetter(propertyIndex)) {
|
||||
transaction.flushBatch();
|
||||
transaction.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,13 +73,13 @@ public final class PersistRequestUpdateSql extends PersistRequest {
|
||||
/**
|
||||
* Add this request to BatchControl to flush later.
|
||||
*/
|
||||
public void addToFlushQueue(boolean early) {
|
||||
public void addToFlushQueue(int pos) {
|
||||
BatchControl control = transaction.getBatchControl();
|
||||
if (control == null) {
|
||||
control = persistExecute.createBatchControl(transaction);
|
||||
}
|
||||
flushQueue = true;
|
||||
control.addToFlushQueue(this, early);
|
||||
control.addToFlushQueue(this, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -104,18 +104,14 @@ public interface Persister {
|
||||
void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue);
|
||||
|
||||
/**
|
||||
* Queue the SqlUpdate for early execution (with JDBC batch).
|
||||
* Queue the SqlUpdate for execution with position 0, 1 or 2 defining
|
||||
* when it executes relative to the flush of beans .
|
||||
*/
|
||||
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t);
|
||||
void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, int pos);
|
||||
|
||||
/**
|
||||
* Queue the SqlUpdate for late execution (with JDBC batch).
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
*/
|
||||
void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t);
|
||||
|
||||
/**
|
||||
* Add the statement to JDBC batch for later execution via executeBatch.
|
||||
*/
|
||||
void addBatch(SpiSqlUpdate sqlUpdate, SpiTransaction transaction);
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,35 +56,43 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
boolean findEachRow(RowConsumer mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEachRow(this, mapper);
|
||||
return true;
|
||||
}
|
||||
|
||||
<T> List<T> findListMapper(RowMapper<T> mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findListMapper(this, mapper);
|
||||
}
|
||||
|
||||
<T> T findOneMapper(RowMapper<T> mapper) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findOneMapper(this, mapper);
|
||||
}
|
||||
|
||||
public <T> List<T> findSingleAttributeList(Class<T> cls) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findSingleAttributeList(this, cls);
|
||||
}
|
||||
|
||||
public <T> T findSingleAttribute(Class<T> cls) {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findSingleAttribute(this, cls);
|
||||
}
|
||||
|
||||
public void findEach(Consumer<SqlRow> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public void findEachWhile(Predicate<SqlRow> consumer) {
|
||||
flushJdbcBatchOnQuery();
|
||||
queryEngine.findEach(this, consumer);
|
||||
}
|
||||
|
||||
public List<SqlRow> findList() {
|
||||
flushJdbcBatchOnQuery();
|
||||
return queryEngine.findList(this);
|
||||
}
|
||||
|
||||
@@ -92,9 +100,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
* Build the list of property names.
|
||||
*/
|
||||
private String[] getPropertyNames() throws SQLException {
|
||||
|
||||
ResultSetMetaData metaData = resultSet.getMetaData();
|
||||
|
||||
int columnsPlusOne = metaData.getColumnCount() + 1;
|
||||
ArrayList<String> propNames = new ArrayList<>(columnsPlusOne - 1);
|
||||
for (int i = 1; i < columnsPlusOne; i++) {
|
||||
@@ -107,9 +113,7 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
* Read and return the next SqlRow.
|
||||
*/
|
||||
public SqlRow createNewRow() throws SQLException {
|
||||
|
||||
rows++;
|
||||
|
||||
SqlRow sqlRow = queryEngine.createSqlRow(estimateCapacity);
|
||||
int index = 0;
|
||||
for (String propertyName : propertyNames) {
|
||||
@@ -121,9 +125,9 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public void logSummary() {
|
||||
if (trans.isLogSummary()) {
|
||||
if (transaction.isLogSummary()) {
|
||||
long micros = (System.nanoTime() - startNano) / 1000L;
|
||||
trans.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
|
||||
transaction.logSummary("SqlQuery rows[" + rows + "] micros[" + micros + "] bind[" + bindLog + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +140,6 @@ public final class RelationalQueryRequest extends AbstractSqlQueryRequest {
|
||||
}
|
||||
|
||||
public <T> List<T> mapList(RowMapper<T> mapper) throws SQLException {
|
||||
|
||||
List<T> list = new ArrayList<>();
|
||||
while (next()) {
|
||||
list.add(mapper.map(resultSet, rows++));
|
||||
|
||||
@@ -223,12 +223,9 @@ public class BootupClasses implements ClassFilter {
|
||||
*/
|
||||
private <T> T create(Class<T> cls, boolean logOnException) {
|
||||
try {
|
||||
// instantiate via found class
|
||||
Constructor<T> constructor = cls.getConstructor();
|
||||
return constructor.newInstance();
|
||||
|
||||
return cls.getConstructor().newInstance();
|
||||
} catch (NoSuchMethodException e) {
|
||||
logger.debug("Ignore/expected - no default constructor", e);
|
||||
logger.debug("Ignore/expected - no default constructor: " +e.getMessage());
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -522,7 +522,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return (EntityBean) beanType.newInstance();
|
||||
return (EntityBean) beanType.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Error trying to create the prototypeEntityBean for " + beanType, e);
|
||||
}
|
||||
@@ -814,7 +814,6 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
int propertyLength = toEbi.getPropertyLength();
|
||||
String[] names = getProperties();
|
||||
for (int i = 0; i < propertyLength; i++) {
|
||||
|
||||
if (fromEbi.isLoadedProperty(i)) {
|
||||
BeanProperty property = getBeanProperty(names[i]);
|
||||
if (!toEbi.isLoadedProperty(i)) {
|
||||
@@ -1865,17 +1864,12 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
}
|
||||
|
||||
/**
|
||||
* We actually need to do a query because we don't know the type without the discriminator
|
||||
* value, just select the id property and discriminator column (auto added)
|
||||
* We actually need to do a query because we don't know the type without the discriminator value.
|
||||
*/
|
||||
private T findReferenceBean(Object id, PersistenceContext pc) {
|
||||
DefaultOrmQuery<T> query = new DefaultOrmQuery<>(this, ebeanServer, ebeanServer.getExpressionFactory());
|
||||
query.setPersistenceContext(pc);
|
||||
return query
|
||||
// .select(getIdProperty().getName())
|
||||
// we do not select the id because we
|
||||
// probably have to load the entire bean
|
||||
.setId(id).findOne();
|
||||
return query.setId(id).findOne();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2087,6 +2081,13 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the simple name of the entity bean.
|
||||
*/
|
||||
public String getSimpleName() {
|
||||
return beanType.getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Summary description.
|
||||
*/
|
||||
@@ -2271,8 +2272,7 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType {
|
||||
*/
|
||||
public void lazyLoadRegister(String prefix, EntityBeanIntercept ebi, EntityBean bean, LoadContext loadContext) {
|
||||
// load the List/Set/Map proxy objects (deferred fetching of lists)
|
||||
BeanPropertyAssocMany<?>[] manys = propertiesMany();
|
||||
for (BeanPropertyAssocMany<?> many : manys) {
|
||||
for (BeanPropertyAssocMany<?> many : propertiesMany()) {
|
||||
if (!ebi.isLoadedProperty(many.getPropertyIndex())) {
|
||||
BeanCollection<?> ref = many.createReferenceIfNull(bean);
|
||||
if (ref != null && !ref.isRegisteredWithLoadContext()) {
|
||||
|
||||
@@ -14,13 +14,32 @@ import java.util.Arrays;
|
||||
*/
|
||||
abstract class BeanDescriptorElement<T> extends BeanDescriptor<T> {
|
||||
|
||||
private final String simpleName;
|
||||
|
||||
final ElementHelp elementHelp;
|
||||
|
||||
BeanDescriptorElement(BeanDescriptorMap owner, DeployBeanDescriptor<T> deploy, ElementHelp elementHelp) {
|
||||
super(owner, deploy);
|
||||
this.simpleName = shortName(deploy.getName());
|
||||
this.elementHelp = elementHelp;
|
||||
}
|
||||
|
||||
private String shortName(String name) {
|
||||
int pos = name.lastIndexOf('.');
|
||||
if (pos > 1) {
|
||||
pos = name.lastIndexOf('.', pos - 1);
|
||||
if (pos > 1) {
|
||||
return name.substring(pos + 1);
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSimpleName() {
|
||||
return simpleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJsonReadCollection() {
|
||||
return true;
|
||||
|
||||
+16
-107
@@ -117,6 +117,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
private final TypeManager typeManager;
|
||||
private final BootupClasses bootupClasses;
|
||||
private final String serverName;
|
||||
private final List<BeanDescriptor<?>> elementDescriptors = new ArrayList<>();
|
||||
private final Map<Class<?>, BeanTable> beanTableMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descMap = new HashMap<>();
|
||||
private final Map<String, BeanDescriptor<?>> descQueueMap = new HashMap<>();
|
||||
@@ -202,7 +203,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Run periodic trim of query plans.
|
||||
*/
|
||||
public void scheduleBackgroundTrim() {
|
||||
backgroundExecutor.executePeriodically(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
|
||||
backgroundExecutor.scheduleWithFixedDelay(this::trimQueryPlans, 117L, 60L, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void trimQueryPlans() {
|
||||
@@ -237,7 +238,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return the versions between timestamp suffix based on the DbHistorySupport.
|
||||
*/
|
||||
private String getVersionsBetweenSuffix(DatabasePlatform databasePlatform, DatabaseConfig serverConfig) {
|
||||
|
||||
DbHistorySupport historySupport = databasePlatform.getHistorySupport();
|
||||
// with historySupport returns a simple view suffix or the sql2011 versions between timestamp suffix
|
||||
return (historySupport == null) ? serverConfig.getAsOfViewSuffix() : historySupport.getVersionsBetweenSuffix(serverConfig.getAsOfViewSuffix());
|
||||
@@ -361,7 +361,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void readEntityMapping(ClassLoader classLoader, XmapEntity entityDeploy) {
|
||||
|
||||
String entityClassName = entityDeploy.getClazz();
|
||||
Class<?> entityClass;
|
||||
try {
|
||||
@@ -411,7 +410,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* For SQL based modifications we need to invalidate appropriate parts of the cache.
|
||||
*/
|
||||
public void cacheNotify(TransactionEventTable.TableIUD tableIUD, CacheChangeSet changeSet) {
|
||||
|
||||
String tableName = tableIUD.getTableName().toLowerCase();
|
||||
List<BeanDescriptor<?>> normalBeanTypes = tableToDescMap.get(tableName);
|
||||
if (normalBeanTypes != null) {
|
||||
@@ -447,7 +445,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Invalidate entity beans based on views via their dependent tables.
|
||||
*/
|
||||
public void processViewInvalidation(Set<String> viewInvalidation) {
|
||||
|
||||
for (String depTable : viewInvalidation) {
|
||||
List<BeanDescriptor<?>> list = tableToViewDescMap.get(depTable.toLowerCase());
|
||||
if (list != null) {
|
||||
@@ -460,12 +457,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
/**
|
||||
* Build a map of table names to BeanDescriptors.
|
||||
* <p>
|
||||
* This is generally used to maintain caches from table names.
|
||||
* </p>
|
||||
*/
|
||||
private void readTableToDescriptor() {
|
||||
|
||||
for (BeanDescriptor<?> desc : descMap.values()) {
|
||||
String baseTable = desc.getBaseTable();
|
||||
if (baseTable != null) {
|
||||
@@ -489,7 +482,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void readForeignKeys() {
|
||||
|
||||
for (BeanDescriptor<?> d : descMap.values()) {
|
||||
d.initialiseFkeys();
|
||||
}
|
||||
@@ -500,18 +492,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* This occurs after all the BeanDescriptors have been created. This resolves
|
||||
* circular relationships between BeanDescriptors.
|
||||
* </p>
|
||||
* <p>
|
||||
* Also responsible for creating all the BeanManagers which contain the
|
||||
* persister, listener etc.
|
||||
* </p>
|
||||
*/
|
||||
private void initialiseAll() {
|
||||
|
||||
// now that all the BeanDescriptors are in their map
|
||||
// we can initialise them which sorts out circular
|
||||
// dependencies for OneToMany and ManyToOne etc
|
||||
|
||||
BeanDescriptorInitContext initContext = new BeanDescriptorInitContext(asOfTableMap, draftTableMap, asOfViewSuffix);
|
||||
|
||||
// PASS 1:
|
||||
@@ -569,7 +557,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void checkMissingHashCodeOrEquals(Exception source, Class<?> idType, Class<?> beanType) {
|
||||
|
||||
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
|
||||
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
|
||||
throw new PersistenceException(msg, source);
|
||||
@@ -603,7 +590,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> BeanManager<T> getBeanManager(Class<T> entityType) {
|
||||
|
||||
return (BeanManager<T>) getBeanManager(entityType.getName());
|
||||
}
|
||||
|
||||
@@ -615,14 +601,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanControllers, BeanFinders and BeanListeners.
|
||||
*/
|
||||
private void createListeners() {
|
||||
|
||||
int qa = beanQueryAdapterManager.getRegisterCount();
|
||||
int cc = persistControllerManager.getRegisterCount();
|
||||
int pl = postLoadManager.getRegisterCount();
|
||||
int pc = postConstructManager.getRegisterCount();
|
||||
int lc = persistListenerManager.getRegisterCount();
|
||||
int fc = beanFinderManager.getRegisterCount();
|
||||
|
||||
logger.debug("BeanPersistControllers[{}] BeanFinders[{}] BeanPersistListeners[{}] BeanQueryAdapters[{}] BeanPostLoaders[{}] BeanPostConstructors[{}]", cc, fc, lc, qa, pl, pc);
|
||||
}
|
||||
|
||||
@@ -639,11 +623,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void registerBeanDescriptor(DeployBeanInfo<?> info) {
|
||||
BeanDescriptor desc = new BeanDescriptor<>(this, info.getDescriptor());
|
||||
BeanDescriptor<?> desc = new BeanDescriptor<>(this, info.getDescriptor());
|
||||
descMap.put(desc.getBeanType().getName(), desc);
|
||||
if (desc.isDocStoreMapped()) {
|
||||
descQueueMap.put(desc.getDocStoreQueueId(), desc);
|
||||
}
|
||||
for (BeanPropertyAssocMany<?> many : desc.propertiesMany()) {
|
||||
if (many.isElementCollection()) {
|
||||
elementDescriptors.add(many.getElementDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -651,10 +640,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* This stops short of reading relationship meta data until after the
|
||||
* BeanTables have all been created.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityDeploymentInitial() {
|
||||
|
||||
for (Class<?> entityClass : bootupClasses.getEntities()) {
|
||||
DeployBeanInfo<?> info = createDeployBeanInfo(entityClass);
|
||||
deployInfoMap.put(entityClass, info);
|
||||
@@ -687,15 +674,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable information which has the base table and id.
|
||||
* <p>
|
||||
* This is determined prior to resolving relationship information.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityBeanTable() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
BeanTable beanTable = createBeanTable(info);
|
||||
beanTableMap.put(beanTable.getBeanType(), beanTable);
|
||||
}
|
||||
|
||||
// register non-id embedded beans (after bean tables are created)
|
||||
for (DeployBeanInfo<?> info : embeddedBeans) {
|
||||
registerEmbeddedBean(info);
|
||||
@@ -706,17 +690,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable information which has the base table and id.
|
||||
* <p>
|
||||
* This is determined prior to resolving relationship information.
|
||||
* </p>
|
||||
*/
|
||||
private void readEntityDeploymentAssociations() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
readDeployAssociations(info);
|
||||
}
|
||||
}
|
||||
|
||||
private void readInheritedIdGenerators() {
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
|
||||
InheritInfo inheritInfo = descriptor.getInheritInfo();
|
||||
@@ -734,17 +715,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create the BeanTable from the deployment information gathered so far.
|
||||
*/
|
||||
private BeanTable createBeanTable(DeployBeanInfo<?> info) {
|
||||
|
||||
DeployBeanDescriptor<?> deployDescriptor = info.getDescriptor();
|
||||
DeployBeanTable beanTable = deployDescriptor.createDeployBeanTable();
|
||||
return new BeanTable(beanTable, this);
|
||||
}
|
||||
|
||||
private void readEntityRelationships() {
|
||||
|
||||
// We only perform 'circular' checks etc after we have
|
||||
// all the DeployBeanDescriptors created and in the map.
|
||||
|
||||
List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck = new ArrayList<>();
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
checkMappedBy(info, primaryKeyJoinCheck);
|
||||
@@ -752,15 +730,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (DeployBeanPropertyAssocOne<?> prop : primaryKeyJoinCheck) {
|
||||
checkUniDirectionalPrimaryKeyJoin(prop);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
secondaryPropsJoins(info);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
setInheritanceInfo(info);
|
||||
}
|
||||
|
||||
for (DeployBeanInfo<?> info : deployInfoMap.values()) {
|
||||
if (!info.isEmbedded()) {
|
||||
registerBeanDescriptor(info);
|
||||
@@ -769,12 +744,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the inheritance info. ~EMG fix for join problem
|
||||
*
|
||||
* @param info the new inheritance info
|
||||
* Sets the inheritance info.
|
||||
*/
|
||||
private void setInheritanceInfo(DeployBeanInfo<?> info) {
|
||||
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(oneProp.getTargetType());
|
||||
@@ -783,7 +755,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (DeployBeanPropertyAssocMany<?> manyProp : info.getDescriptor().propertiesAssocMany()) {
|
||||
if (!manyProp.isTransient()) {
|
||||
DeployBeanInfo<?> assoc = deployInfoMap.get(manyProp.getTargetType());
|
||||
@@ -795,7 +766,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void secondaryPropsJoins(DeployBeanInfo<?> info) {
|
||||
|
||||
DeployBeanDescriptor<?> descriptor = info.getDescriptor();
|
||||
for (DeployBeanProperty prop : descriptor.propertiesBase()) {
|
||||
if (prop.isSecondaryTable()) {
|
||||
@@ -819,10 +789,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* This will read join information defined on the 'owning/other' side of the
|
||||
* relationship. It also does some extra work for unidirectional
|
||||
* relationships.
|
||||
* </p>
|
||||
*/
|
||||
private void checkMappedBy(DeployBeanInfo<?> info, List<DeployBeanPropertyAssocOne<?>> primaryKeyJoinCheck) {
|
||||
|
||||
for (DeployBeanPropertyAssocOne<?> oneProp : info.getDescriptor().propertiesAssocOne()) {
|
||||
if (!oneProp.isTransient()) {
|
||||
if (oneProp.getMappedBy() != null) {
|
||||
@@ -845,14 +813,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private DeployBeanDescriptor<?> getTargetDescriptor(DeployBeanPropertyAssoc<?> prop) {
|
||||
|
||||
Class<?> targetType = prop.getTargetType();
|
||||
DeployBeanInfo<?> info = deployInfoMap.get(targetType);
|
||||
if (info == null) {
|
||||
String msg = "Can not find descriptor [" + targetType + "] for " + prop.getFullBeanName();
|
||||
throw new PersistenceException(msg);
|
||||
}
|
||||
|
||||
return info.getDescriptor();
|
||||
}
|
||||
|
||||
@@ -861,10 +827,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* mark it as unidirectional.
|
||||
*/
|
||||
private boolean findMappedBy(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// this is the entity bean type - that owns this property
|
||||
Class<?> owningType = prop.getOwningType();
|
||||
|
||||
Set<String> matchSet = new HashSet<>();
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
@@ -918,7 +882,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
// multiple options so should specify mappedBy property
|
||||
@@ -930,12 +893,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void makeOrderColumn(DeployBeanPropertyAssocMany<?> oneToMany) {
|
||||
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
|
||||
|
||||
DeployOrderColumn orderColumn = oneToMany.getOrderColumn();
|
||||
DeployBeanProperty orderProperty = new DeployBeanProperty(targetDesc, Integer.class, ScalarTypeInteger.INSTANCE, null);
|
||||
|
||||
orderProperty.setName(DeployOrderColumn.LOGICAL_NAME);
|
||||
orderProperty.setDbColumn(orderColumn.getName());
|
||||
orderProperty.setNullable(orderColumn.isNullable());
|
||||
@@ -943,7 +903,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
orderProperty.setDbUpdateable(orderColumn.isUpdatable());
|
||||
orderProperty.setDbRead(true);
|
||||
orderProperty.setOwningType(targetDesc.getBeanType());
|
||||
|
||||
final InheritInfo targetInheritInfo = targetDesc.getInheritInfo();
|
||||
if (targetInheritInfo != null) {
|
||||
for (InheritInfo child : targetInheritInfo.getChildren()) {
|
||||
@@ -951,7 +910,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
childDescriptor.setOrderColumn(orderProperty);
|
||||
}
|
||||
}
|
||||
|
||||
targetDesc.setOrderColumn(orderProperty);
|
||||
}
|
||||
|
||||
@@ -960,19 +918,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* unidirectional.
|
||||
* <p>
|
||||
* This means that inserts MUST cascade for this property.
|
||||
* </p>
|
||||
* <p>
|
||||
* Create a "Shadow"/Unidirectional property on the target. It is used with
|
||||
* inserts to set the foreign key value (e.g. inserts the foreign key value
|
||||
* into the order_id column on the order_lines table).
|
||||
* </p>
|
||||
*/
|
||||
private void makeUnidirectional(DeployBeanPropertyAssocMany<?> oneToMany) {
|
||||
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(oneToMany);
|
||||
|
||||
Class<?> owningType = oneToMany.getOwningType();
|
||||
|
||||
if (!oneToMany.getCascadeInfo().isSave()) {
|
||||
// The property MUST have persist cascading so that inserts work.
|
||||
|
||||
@@ -1020,11 +973,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void checkMappedByOneToOne(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
// check that the mappedBy property is valid and read
|
||||
// its associated join information if it is available
|
||||
String mappedBy = prop.getMappedBy();
|
||||
|
||||
// get the mappedBy property
|
||||
DeployBeanDescriptor<?> targetDesc = getTargetDescriptor(prop);
|
||||
DeployBeanProperty mappedProp = targetDesc.getBeanProperty(mappedBy);
|
||||
@@ -1077,10 +1028,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* We can use the join information from the mappedBy property and reverse it
|
||||
* for using in the OneToMany direction.
|
||||
* </p>
|
||||
*/
|
||||
private void checkMappedByOneToMany(DeployBeanInfo<?> info, DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
if (prop.isElementCollection()) {
|
||||
// skip mapping check
|
||||
return;
|
||||
@@ -1161,7 +1110,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* For mappedBy copy the joins from the other side.
|
||||
*/
|
||||
private void checkMappedByManyToMany(DeployBeanPropertyAssocMany<?> prop) {
|
||||
|
||||
// get the bean descriptor that holds the mappedBy property
|
||||
String mappedBy = prop.getMappedBy();
|
||||
if (mappedBy == null) {
|
||||
@@ -1222,50 +1170,40 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private <T> void setBeanControllerFinderListener(DeployBeanDescriptor<T> descriptor) {
|
||||
|
||||
persistControllerManager.addPersistControllers(descriptor);
|
||||
postLoadManager.addPostLoad(descriptor);
|
||||
postConstructManager.addPostConstructListeners(descriptor);
|
||||
persistListenerManager.addPersistListeners(descriptor);
|
||||
beanQueryAdapterManager.addQueryAdapter(descriptor);
|
||||
beanFinderManager.addFindControllers(descriptor);
|
||||
|
||||
if (changeLogRegister != null) {
|
||||
ChangeLogFilter changeFilter = changeLogRegister.getChangeFilter(descriptor.getBeanType());
|
||||
if (changeFilter != null) {
|
||||
descriptor.setChangeLogFilter(changeFilter);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the initial deployment information for a given bean type.
|
||||
*/
|
||||
private <T> DeployBeanInfo<T> createDeployBeanInfo(Class<T> beanClass) {
|
||||
|
||||
DeployBeanDescriptor<T> desc = new DeployBeanDescriptor<>(this, beanClass, config);
|
||||
beanLifecycleAdapterFactory.addLifecycleMethods(desc);
|
||||
|
||||
// set bean controller, finder and listener
|
||||
setBeanControllerFinderListener(desc);
|
||||
deplyInherit.process(desc);
|
||||
desc.checkInheritanceMapping();
|
||||
|
||||
createProperties.createProperties(desc);
|
||||
|
||||
DeployBeanInfo<T> info = new DeployBeanInfo<>(deployUtil, desc);
|
||||
|
||||
readAnnotations.readInitial(info);
|
||||
return info;
|
||||
}
|
||||
|
||||
private <T> void readDeployAssociations(DeployBeanInfo<T> info) {
|
||||
|
||||
DeployBeanDescriptor<T> desc = info.getDescriptor();
|
||||
|
||||
readAnnotations.readAssociations(info, this);
|
||||
|
||||
if (EntityType.SQL == desc.getEntityType()) {
|
||||
desc.setBaseTable(null, null, null);
|
||||
}
|
||||
@@ -1273,15 +1211,12 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
// mark transient properties
|
||||
transientProperties.process(desc);
|
||||
setScalarType(desc);
|
||||
|
||||
if (!desc.isEmbedded()) {
|
||||
// Set IdGenerator or use DB Identity
|
||||
setIdGeneration(desc);
|
||||
|
||||
// find the appropriate default concurrency mode
|
||||
setConcurrencyMode(desc);
|
||||
}
|
||||
|
||||
// generate the byte code
|
||||
createByteCode(desc);
|
||||
}
|
||||
@@ -1290,7 +1225,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Set the Identity generation mechanism.
|
||||
*/
|
||||
private <T> void setIdGeneration(DeployBeanDescriptor<T> desc) {
|
||||
|
||||
if (desc.getIdGenerator() != null) {
|
||||
// already assigned (So custom or UUID)
|
||||
return;
|
||||
@@ -1298,7 +1232,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
if (desc.idProperty() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final DeployIdentityMode identityMode = desc.getIdentityMode();
|
||||
if (identityMode.isSequence() && !dbIdentity.isSupportsSequence()) {
|
||||
// explicit sequence but not supported by the DatabasePlatform
|
||||
@@ -1355,11 +1288,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void createByteCode(DeployBeanDescriptor<?> deploy) {
|
||||
|
||||
// check to see if the bean supports EntityBean interface
|
||||
// generate a subclass if required
|
||||
setEntityBeanClass(deploy);
|
||||
|
||||
// use Code generation or Standard reflection to support
|
||||
// getter and setter methods
|
||||
setBeanReflect(deploy);
|
||||
@@ -1373,10 +1304,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* <p>
|
||||
* Enums are treated a bit differently in that they always have a ScalarType
|
||||
* as one is built for them.
|
||||
* </p>
|
||||
*/
|
||||
private void setScalarType(DeployBeanDescriptor<?> deployDesc) {
|
||||
|
||||
for (DeployBeanProperty prop : deployDesc.propertiesAll()) {
|
||||
if (!(prop instanceof DeployBeanPropertyAssoc<?>)) {
|
||||
deployUtil.setScalarType(prop);
|
||||
@@ -1390,17 +1319,13 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* This sets the implementation of constructing entity beans and the setting
|
||||
* and getting of properties. It is generally faster to use code generation
|
||||
* rather than reflection to do this.
|
||||
* </p>
|
||||
*/
|
||||
private void setBeanReflect(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
// Set the BeanReflectGetter and BeanReflectSetter that typically
|
||||
// use generated code. NB: Due to Bug 166 so now doing this for
|
||||
// abstract classes as well.
|
||||
|
||||
BeanPropertiesReader reflectProps = new BeanPropertiesReader(desc.getBeanType());
|
||||
desc.setProperties(reflectProps.getProperties());
|
||||
|
||||
for (DeployBeanProperty prop : desc.propertiesAll()) {
|
||||
String propName = prop.getName();
|
||||
Integer pos = reflectProps.getPropertyIndex(propName);
|
||||
@@ -1410,7 +1335,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
"If you are running in an IDE with enhancement plugin try a Build -> Rebuild Project to recompile and enhance all entity beans. " +
|
||||
"Error - property " + propName + " not found in " + reflectProps + " for type " + desc.getBeanType());
|
||||
}
|
||||
|
||||
} else {
|
||||
final int propertyIndex = pos;
|
||||
prop.setPropertyIndex(propertyIndex);
|
||||
@@ -1427,7 +1351,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Return true if this is a persistent field (not transient or static).
|
||||
*/
|
||||
private boolean isPersistentField(DeployBeanProperty prop) {
|
||||
|
||||
Field field = prop.getField();
|
||||
if (field == null) {
|
||||
return false;
|
||||
@@ -1442,12 +1365,10 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* which contain version properties.
|
||||
*/
|
||||
private void setConcurrencyMode(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
if (desc.getConcurrencyMode() != null) {
|
||||
// concurrency mode explicitly set during deployment
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkForVersionProperties(desc)) {
|
||||
desc.setConcurrencyMode(ConcurrencyMode.VERSION);
|
||||
} else {
|
||||
@@ -1459,23 +1380,16 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Search for version properties also including embedded beans.
|
||||
*/
|
||||
private boolean checkForVersionProperties(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
boolean hasVersionProperty = false;
|
||||
|
||||
List<DeployBeanProperty> props = desc.propertiesBase();
|
||||
for (DeployBeanProperty prop : props) {
|
||||
for (DeployBeanProperty prop : desc.propertiesBase()) {
|
||||
if (prop.isVersionColumn()) {
|
||||
hasVersionProperty = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasVersionProperty;
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasEntityBeanInterface(Class<?> beanClass) {
|
||||
|
||||
Class<?>[] interfaces = beanClass.getInterfaces();
|
||||
for (Class<?> anInterface : interfaces) {
|
||||
for (Class<?> anInterface : beanClass.getInterfaces()) {
|
||||
if (anInterface.equals(EntityBean.class)) {
|
||||
return true;
|
||||
}
|
||||
@@ -1487,18 +1401,14 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Test the bean type to see if it implements EntityBean interface already.
|
||||
*/
|
||||
private void setEntityBeanClass(DeployBeanDescriptor<?> desc) {
|
||||
|
||||
Class<?> beanClass = desc.getBeanType();
|
||||
|
||||
if (!hasEntityBeanInterface(beanClass)) {
|
||||
String msg = "Bean " + beanClass + " is not enhanced? Check packages specified in ebean.mf. If you are running in IDEA or " +
|
||||
"Eclipse check that the enhancement plugin is installed. See https://ebean.io/docs/trouble-shooting#not-enhanced";
|
||||
throw new BeanNotEnhancedException(msg);
|
||||
}
|
||||
|
||||
// the bean already implements EntityBean
|
||||
checkInheritedClasses(beanClass);
|
||||
|
||||
entityBeanCount++;
|
||||
}
|
||||
|
||||
@@ -1507,7 +1417,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* enhanced or all dynamically subclassed).
|
||||
*/
|
||||
private void checkInheritedClasses(Class<?> beanClass) {
|
||||
|
||||
Class<?> superclass = beanClass.getSuperclass();
|
||||
if (Object.class.equals(superclass)) {
|
||||
// we got to the top of the inheritance
|
||||
@@ -1566,10 +1475,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
}
|
||||
|
||||
private void addPrimaryKeyJoin(DeployBeanPropertyAssocOne<?> prop) {
|
||||
|
||||
String baseTable = prop.getDesc().getBaseTable();
|
||||
DeployTableJoin inverse = prop.getTableJoin().createInverse(baseTable);
|
||||
|
||||
TableJoin inverseJoin = new TableJoin(inverse, prop.getForeignKey());
|
||||
DeployBeanInfo<?> target = deployInfoMap.get(prop.getTargetType());
|
||||
target.setPrimaryKeyJoin(inverseJoin);
|
||||
@@ -1586,7 +1493,6 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
* Create a BeanDescriptor for an ElementCollection target.
|
||||
*/
|
||||
public <A> BeanDescriptor<A> createElementDescriptor(DeployBeanDescriptor<A> elementDescriptor, ManyType manyType, boolean scalar) {
|
||||
|
||||
ElementHelp elementHelp = elementHelper(manyType);
|
||||
if (manyType.isMap()) {
|
||||
if (scalar) {
|
||||
@@ -1619,6 +1525,9 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
for (BeanDescriptor<?> desc : immutableDescriptorList) {
|
||||
desc.visitMetrics(visitor);
|
||||
}
|
||||
for (BeanDescriptor<?> desc : elementDescriptors) {
|
||||
desc.visitMetrics(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
public List<MetaQueryPlan> queryPlanInit(QueryPlanInit request) {
|
||||
|
||||
@@ -569,6 +569,13 @@ public class BeanPropertyAssocMany<T> extends BeanPropertyAssoc<T> implements ST
|
||||
return elementCollection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the element bean descriptor (for an element collection only).
|
||||
*/
|
||||
public BeanDescriptor<T> getElementDescriptor() {
|
||||
return elementDescriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* ManyToMany only, join from local table to intersection table.
|
||||
*/
|
||||
|
||||
@@ -311,19 +311,23 @@ public class AnnotationFields extends AnnotationParser {
|
||||
DbMap dbMap = get(prop, DbMap.class);
|
||||
if (dbMap != null) {
|
||||
util.setDbMap(prop, dbMap);
|
||||
setColumnName(prop, dbMap.name());
|
||||
}
|
||||
DbJson dbJson = get(prop, DbJson.class);
|
||||
if (dbJson != null) {
|
||||
util.setDbJsonType(prop, dbJson);
|
||||
setColumnName(prop, dbJson.name());
|
||||
} else {
|
||||
DbJsonB dbJsonB = get(prop, DbJsonB.class);
|
||||
if (dbJsonB != null) {
|
||||
util.setDbJsonBType(prop, dbJsonB);
|
||||
setColumnName(prop, dbJsonB.name());
|
||||
}
|
||||
}
|
||||
DbArray dbArray = get(prop, DbArray.class);
|
||||
if (dbArray != null) {
|
||||
util.setDbArray(prop, dbArray);
|
||||
setColumnName(prop, dbArray.name());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,11 +99,7 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
}
|
||||
|
||||
void readColumn(Column columnAnn, DeployBeanProperty prop) {
|
||||
|
||||
if (!isEmpty(columnAnn.name())) {
|
||||
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(columnAnn.name()));
|
||||
}
|
||||
|
||||
setColumnName(prop, columnAnn.name());
|
||||
prop.setDbInsertable(columnAnn.insertable());
|
||||
prop.setDbUpdateable(columnAnn.updatable());
|
||||
prop.setNullable(columnAnn.nullable());
|
||||
@@ -125,6 +121,12 @@ public abstract class AnnotationParser extends AnnotationBase {
|
||||
}
|
||||
}
|
||||
|
||||
protected void setColumnName(DeployBeanProperty prop, String name) {
|
||||
if (!isEmpty(name)) {
|
||||
prop.setDbColumn(databasePlatform.convertQuotedIdentifiers(name));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the validation groups are {@link Default} (respectively empty)
|
||||
* can be applied to DDL generation.
|
||||
|
||||
+8
-12
@@ -1,4 +1,4 @@
|
||||
package io.ebeaninternal.server.lib;
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -9,15 +9,12 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Daemon based ScheduleThreadPool.
|
||||
* <p>
|
||||
* Uses Daemon threads and hooks into shutdown event.
|
||||
* </p>
|
||||
*/
|
||||
public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
@@ -35,26 +32,25 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
* This will wait a maximum of shutdownWaitSeconds seconds before
|
||||
* terminating any threads still working.
|
||||
*/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (super.isShutdown()) {
|
||||
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
|
||||
logger.debug("Already shutdown {}", namePrefix);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonScheduleThreadPool {} shutting down...", namePrefix);
|
||||
logger.trace("Shutting down {} ...", namePrefix);
|
||||
super.shutdown();
|
||||
if (!super.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonScheduleThreadPool shut down timeout exceeded. Terminating running threads.");
|
||||
logger.info("Shutdown wait timeout exceeded. Terminating running threads for {}", namePrefix);
|
||||
super.shutdownNow();
|
||||
}
|
||||
|
||||
logger.debug("Shutdown complete for {}", namePrefix);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of " + namePrefix, e);
|
||||
e.printStackTrace();
|
||||
+3
-18
@@ -1,5 +1,4 @@
|
||||
package io.ebeaninternal.server.lib;
|
||||
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -9,42 +8,28 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* <p>
|
||||
* Daemon threads do not stop a JVM stopping. If an application only has Daemon
|
||||
* threads left it will shutdown.
|
||||
* </p>
|
||||
* <p>
|
||||
* In using Daemon threads you need to either not care about being interrupted
|
||||
* on shutdown or register with the JVM shutdown hook to perform a nice shutdown
|
||||
* of the daemon threads etc.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class DaemonThreadFactory implements ThreadFactory {
|
||||
|
||||
private static final AtomicInteger poolNumber = new AtomicInteger(1);
|
||||
|
||||
private final ThreadGroup group;
|
||||
|
||||
private final AtomicInteger threadNumber = new AtomicInteger(1);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
public DaemonThreadFactory(String namePrefix) {
|
||||
SecurityManager s = System.getSecurityManager();
|
||||
this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
|
||||
this.namePrefix = namePrefix != null ? namePrefix : "pool-" + poolNumber.getAndIncrement() + "-thread-";
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
|
||||
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
|
||||
Thread t = new Thread(null, r, namePrefix + threadNumber.getAndIncrement(), 0);
|
||||
t.setDaemon(true);
|
||||
|
||||
if (t.getPriority() != Thread.NORM_PRIORITY) {
|
||||
t.setPriority(Thread.NORM_PRIORITY);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import io.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* The default implementation of the BackgroundExecutor.
|
||||
*/
|
||||
public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.executor = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
<T> Callable<T> wrapMDC(Callable<T> task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
return task.call();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the task with MDC context if defined.
|
||||
*/
|
||||
Runnable wrapMDC(Runnable task) {
|
||||
final Map<String, String> map = MDC.getCopyOfContextMap();
|
||||
if (map == null) {
|
||||
return task;
|
||||
} else {
|
||||
return () -> {
|
||||
MDC.setContextMap(map);
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
MDC.clear();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Future<T> submit(Callable<T> task) {
|
||||
return executor.submit(wrapMDC(task));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
@Override
|
||||
public Future<?> submit(Runnable task) {
|
||||
return executor.submit(wrapMDC(task));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
submit(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable task, long delay, TimeUnit unit) {
|
||||
executor.scheduleWithFixedDelay(wrapMDC(task), delay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executePeriodically(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return executor.scheduleWithFixedDelay(wrapMDC(task), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long delay, TimeUnit unit) {
|
||||
return executor.scheduleAtFixedRate(wrapMDC(task), initialDelay, delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
|
||||
return executor.schedule(wrapMDC(task), delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
|
||||
return executor.schedule(wrapMDC(task), delay, unit);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
executor.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -486,6 +486,16 @@ public class DefaultExpressionList<T> implements SpiExpressionList<T> {
|
||||
return query.filterMany(manyProperty).where(expressions, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(Query.LockType lockType) {
|
||||
return query.withLock(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait) {
|
||||
return query.withLock(lockType, lockWait);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
return query.forUpdate();
|
||||
|
||||
@@ -491,6 +491,16 @@ class JunctionExpression<T> implements SpiJunction<T>, SpiExpression, Expression
|
||||
return exprList.findOneOrEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(Query.LockType lockType) {
|
||||
return exprList.withLock(lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(Query.LockType lockType, Query.LockWait lockWait) {
|
||||
return exprList.withLock(lockType, lockWait);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
return exprList.forUpdate();
|
||||
|
||||
@@ -45,7 +45,7 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
|
||||
|
||||
private AtomicLong nanoToMilliOffset = new AtomicLong(currentUuidTime());
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
package io.ebeaninternal.server.lib;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* A "CachedThreadPool" based on Daemon threads.
|
||||
* <p>
|
||||
* The Threads are created as needed and once idle live for 60 seconds.
|
||||
*/
|
||||
public final class DaemonExecutorService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DaemonExecutorService.class);
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final String namePrefix;
|
||||
|
||||
private final int shutdownWaitSeconds;
|
||||
|
||||
private final ExecutorService service;
|
||||
|
||||
/**
|
||||
* Construct the DaemonThreadPool.
|
||||
*
|
||||
* @param shutdownWaitSeconds the time in seconds allowed for the pool to shutdown nicely. After
|
||||
* this the pool is forced to shutdown.
|
||||
*/
|
||||
public DaemonExecutorService(int shutdownWaitSeconds, String namePrefix) {
|
||||
this.service = Executors.newCachedThreadPool(new DaemonThreadFactory(namePrefix));
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
this.namePrefix = namePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the Runnable.
|
||||
*/
|
||||
public void execute(Runnable runnable) {
|
||||
service.execute(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this thread pool nicely if possible.
|
||||
* <p>
|
||||
* This will wait a maximum of 20 seconds before terminating any threads still
|
||||
* working.
|
||||
* </p>
|
||||
*/
|
||||
public void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
if (service.isShutdown()) {
|
||||
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
logger.debug("DaemonExecutorService[{}] shutting down...", namePrefix);
|
||||
service.shutdown();
|
||||
if (!service.awaitTermination(shutdownWaitSeconds, TimeUnit.SECONDS)) {
|
||||
logger.info("DaemonExecutorService[{}] shut down timeout exceeded. Terminating running threads.", namePrefix);
|
||||
service.shutdownNow();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*/
|
||||
abstract class DLoadBaseContext {
|
||||
|
||||
protected final ReentrantLock lock = new ReentrantLock(false);
|
||||
protected final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
protected final DLoadContext parent;
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
|
||||
*/
|
||||
static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
|
||||
|
||||
private final ReentrantLock bufferLock = new ReentrantLock(false);
|
||||
private final ReentrantLock bufferLock = new ReentrantLock();
|
||||
private final DLoadBeanContext context;
|
||||
private final int batchSize;
|
||||
private final List<EntityBeanIntercept> list;
|
||||
|
||||
@@ -130,7 +130,7 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
|
||||
*/
|
||||
static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final PersistenceContext persistenceContext;
|
||||
private final DLoadManyContext context;
|
||||
private final int batchSize;
|
||||
|
||||
@@ -81,8 +81,7 @@ public final class BatchControl {
|
||||
*/
|
||||
private int bufferMax;
|
||||
|
||||
private Queue earlyQueue;
|
||||
private Queue lateQueue;
|
||||
private Queue[] queues = new Queue[3];
|
||||
|
||||
/**
|
||||
* Create for a given transaction, PersistExecute, default size and getGeneratedKeys.
|
||||
@@ -271,9 +270,10 @@ public final class BatchControl {
|
||||
}
|
||||
|
||||
private void flushBuffer(boolean reset) throws BatchedSqlException {
|
||||
flushQueue(queues[0]);
|
||||
flushInternal(reset);
|
||||
flushQueue(earlyQueue);
|
||||
flushQueue(lateQueue);
|
||||
flushQueue(queues[1]);
|
||||
flushQueue(queues[2]);
|
||||
}
|
||||
|
||||
private void flushQueue(Queue queue) throws BatchedSqlException {
|
||||
@@ -368,20 +368,11 @@ public final class BatchControl {
|
||||
/**
|
||||
* Add a SqlUpdate request to execute after flush.
|
||||
*/
|
||||
public void addToFlushQueue(PersistRequestUpdateSql request, boolean early) {
|
||||
if (early) {
|
||||
// add it to the early queue
|
||||
if (earlyQueue == null) {
|
||||
earlyQueue = new Queue();
|
||||
}
|
||||
earlyQueue.add(request);
|
||||
} else {
|
||||
// add it to the late queue
|
||||
if (lateQueue == null) {
|
||||
lateQueue = new Queue();
|
||||
}
|
||||
lateQueue.add(request);
|
||||
public void addToFlushQueue(PersistRequestUpdateSql request, int pos) {
|
||||
if (queues[pos] == null) {
|
||||
queues[pos] = new Queue();
|
||||
}
|
||||
queues[pos].add(request);
|
||||
}
|
||||
|
||||
private static class Queue {
|
||||
|
||||
@@ -141,24 +141,17 @@ public final class DefaultPersister implements Persister {
|
||||
@Override
|
||||
public void executeOrQueue(SpiSqlUpdate update, SpiTransaction t, boolean queue) {
|
||||
if (queue) {
|
||||
addToFlushQueue(update, t, false);
|
||||
addToFlushQueue(update, t, 2);
|
||||
} else {
|
||||
executeSqlUpdate(update, t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t) {
|
||||
addToFlushQueue(update, t, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToFlushQueueLast(SpiSqlUpdate update, SpiTransaction t) {
|
||||
addToFlushQueue(update, t, false);
|
||||
}
|
||||
|
||||
private void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, boolean early) {
|
||||
new PersistRequestUpdateSql(server, update, t, persistExecute).addToFlushQueue(early);
|
||||
/**
|
||||
* Add to the flush queue in position 0, 1 or 2.
|
||||
*/
|
||||
public void addToFlushQueue(SpiSqlUpdate update, SpiTransaction t, int pos) {
|
||||
new PersistRequestUpdateSql(server, update, t, persistExecute).addToFlushQueue(pos);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -963,7 +956,7 @@ public final class DefaultPersister implements Persister {
|
||||
void deleteManyIntersection(EntityBean bean, BeanPropertyAssocMany<?> many, SpiTransaction t, boolean publish, boolean queue) {
|
||||
SpiSqlUpdate sqlDelete = deleteAllIntersection(bean, many, publish);
|
||||
if (queue) {
|
||||
addToFlushQueue(sqlDelete, t, true);
|
||||
addToFlushQueue(sqlDelete, t, 1);
|
||||
} else {
|
||||
executeSqlUpdate(sqlDelete, t);
|
||||
}
|
||||
@@ -1237,7 +1230,6 @@ public final class DefaultPersister implements Persister {
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private <T> PersistRequestBean<T> createRequest(T bean, Transaction t, Object parentBean, BeanManager<?> mgr,
|
||||
PersistRequest.Type type, int flags) {
|
||||
|
||||
// no delete requests come here
|
||||
return new PersistRequestBean(server, bean, parentBean, mgr, (SpiTransaction) t, persistExecute, type, flags);
|
||||
}
|
||||
@@ -1252,7 +1244,6 @@ public final class DefaultPersister implements Persister {
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private <T> PersistRequestBean<T> createDeleteRequest(Object bean, Transaction t, PersistRequest.Type type, int flags) {
|
||||
|
||||
BeanManager<T> mgr = getBeanManager(bean);
|
||||
if (type == Type.DELETE_PERMANENT) {
|
||||
type = Type.DELETE;
|
||||
@@ -1281,7 +1272,6 @@ public final class DefaultPersister implements Persister {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> BeanManager<T> getBeanManager(Object bean) {
|
||||
|
||||
BeanManager<T> mgr = (BeanManager<T>) beanDescriptorManager.getBeanManager(bean.getClass());
|
||||
if (mgr == null) {
|
||||
throw new PersistenceException(errNotRegistered(bean.getClass()));
|
||||
|
||||
+2
-2
@@ -56,7 +56,7 @@ class MergeNodeAssocManyToMany extends MergeNode {
|
||||
IntersectionTable intersectionTable = many.intersectionTable();
|
||||
|
||||
if (!deletions.isEmpty()) {
|
||||
transaction.flushBatch();
|
||||
transaction.flush();
|
||||
|
||||
SqlUpdate delete = intersectionTable.delete(server, false);
|
||||
for (EntityBean deletion : deletions) {
|
||||
@@ -67,7 +67,7 @@ class MergeNodeAssocManyToMany extends MergeNode {
|
||||
}
|
||||
|
||||
if (!additions.isEmpty()) {
|
||||
transaction.flushBatch();
|
||||
transaction.flush();
|
||||
|
||||
SqlUpdate insert = intersectionTable.insert(server, false);
|
||||
for (EntityBean addition : additions) {
|
||||
|
||||
@@ -49,7 +49,7 @@ abstract class SaveManyBase implements SaveMany {
|
||||
void preElementCollectionUpdate() {
|
||||
if (!insertedParent) {
|
||||
request.preElementCollectionUpdate();
|
||||
persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction);
|
||||
persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
private final boolean saveRecurseSkippable;
|
||||
private final DeleteMode deleteMode;
|
||||
private final boolean untouchedBeanCollection;
|
||||
private Collection<?> collection;
|
||||
private final Collection<?> collection;
|
||||
private int sortOrder;
|
||||
|
||||
SaveManyBeans(DefaultPersister persister, boolean insertedParent, BeanPropertyAssocMany<?> many, EntityBean parentBean, PersistRequestBean<?> request) {
|
||||
@@ -49,6 +49,7 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
this.saveRecurseSkippable = many.isSaveRecurseSkippable();
|
||||
this.deleteMode = targetDescriptor.isSoftDelete() ? DeleteMode.SOFT : DeleteMode.HARD;
|
||||
this.untouchedBeanCollection = untouchedBeanCollection();
|
||||
this.collection = cascade ? BeanCollectionUtil.getActualEntries(value) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +109,6 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
private void saveAssocManyDetails() {
|
||||
// check that the list is not null and if it is a BeanCollection
|
||||
// check that is has been populated (don't trigger lazy loading)
|
||||
collection = BeanCollectionUtil.getActualEntries(value);
|
||||
if (collection != null) {
|
||||
processDetails();
|
||||
}
|
||||
@@ -210,6 +210,18 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasNewOrDirtyBeans() {
|
||||
if (collection == null) {
|
||||
return false;
|
||||
}
|
||||
for (Object bean : collection) {
|
||||
if (bean instanceof EntityBean && ((EntityBean) bean)._ebean_getIntercept().isNewOrDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect the Id values of the details to remove 'missing children' for stateless updates.
|
||||
*/
|
||||
@@ -235,9 +247,6 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
/**
|
||||
* Save the additions and removals from a ManyToMany collection as inserts
|
||||
* and deletes from the intersection table.
|
||||
* <p>
|
||||
* This is done via MapBeans.
|
||||
* </p>
|
||||
*/
|
||||
private void saveAssocManyIntersection() {
|
||||
if (value == null) {
|
||||
@@ -336,9 +345,14 @@ public class SaveManyBeans extends SaveManyBase {
|
||||
}
|
||||
|
||||
private void removeAssocManyOrphans() {
|
||||
// check that the list is not null and if it is a BeanCollection
|
||||
// check that is has been populated (don't trigger lazy loading)
|
||||
if (value instanceof BeanCollection<?>) {
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
if (!(value instanceof BeanCollection<?>)) {
|
||||
// if (!insertedParent && cascade && hasNewOrDirtyBeans()) {
|
||||
// persister.addToFlushQueue(many.deleteByParentId(request.getBeanId(), null), transaction, 0);
|
||||
// }
|
||||
} else {
|
||||
BeanCollection<?> c = (BeanCollection<?>) value;
|
||||
Set<?> modifyRemovals = c.getModifyRemovals();
|
||||
if (insertedParent) {
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ class SaveManyElementCollection extends SaveManyBase {
|
||||
final SpiSqlUpdate sqlInsert = proto.copy();
|
||||
sqlInsert.setParameter(parentId);
|
||||
many.bindElementValue(sqlInsert, value);
|
||||
persister.addToFlushQueueLast(sqlInsert, transaction);
|
||||
persister.addToFlushQueue(sqlInsert, transaction, 2);
|
||||
}
|
||||
resetModifyState();
|
||||
postElementCollectionUpdate();
|
||||
|
||||
+1
-1
@@ -51,7 +51,7 @@ class SaveManyElementCollectionMap extends SaveManyBase {
|
||||
sqlInsert.setParameter(parentId);
|
||||
sqlInsert.setParameter(entry.getKey());
|
||||
many.bindElementValue(sqlInsert, entry.getValue());
|
||||
persister.addToFlushQueueLast(sqlInsert, transaction);
|
||||
persister.addToFlushQueue(sqlInsert, transaction, 2);
|
||||
}
|
||||
resetModifyState();
|
||||
postElementCollectionUpdate();
|
||||
|
||||
@@ -59,7 +59,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
|
||||
private static final CQueryCollectionAddNoop NOOP_ADD = new CQueryCollectionAddNoop();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* The resultSet rows read.
|
||||
|
||||
@@ -11,7 +11,7 @@ class CQueryBindCapture implements SpiQueryBindCapture {
|
||||
|
||||
private static final double multiplier = 1.3d;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final CQueryPlanManager manager;
|
||||
private final SpiQueryPlan queryPlan;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.ebeaninternal.api.SpiQueryBindCapture;
|
||||
import io.ebeaninternal.api.SpiQueryPlan;
|
||||
import io.ebeaninternal.server.core.OrmQueryRequest;
|
||||
import io.ebeaninternal.server.core.timezone.DataTimeZone;
|
||||
import io.ebeaninternal.server.lib.Str;
|
||||
import io.ebeaninternal.server.query.CQueryPlanStats.Snapshot;
|
||||
import io.ebeaninternal.server.type.DataBind;
|
||||
import io.ebeaninternal.server.type.DataBindCapture;
|
||||
@@ -106,7 +107,7 @@ public class CQueryPlan implements SpiQueryPlan {
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
this.label = query.getPlanLabel();
|
||||
this.name = deriveName(label, query.getType());
|
||||
this.name = deriveName(label, query.getType(), request.getBeanDescriptor().getSimpleName());
|
||||
this.location = location();
|
||||
this.asOfTableCount = query.getAsOfTableCount();
|
||||
this.sql = sqlRes.getSql();
|
||||
@@ -130,7 +131,7 @@ public class CQueryPlan implements SpiQueryPlan {
|
||||
SpiQuery<?> query = request.getQuery();
|
||||
this.profileLocation = query.getProfileLocation();
|
||||
this.label = query.getPlanLabel();
|
||||
this.name = deriveName(label, query.getType());
|
||||
this.name = deriveName(label, query.getType(), request.getBeanDescriptor().getSimpleName());
|
||||
this.location = location();
|
||||
this.planKey = buildPlanKey(sql, logWhereSql);
|
||||
this.asOfTableCount = 0;
|
||||
@@ -145,14 +146,19 @@ public class CQueryPlan implements SpiQueryPlan {
|
||||
this.hash = md5Hash();
|
||||
}
|
||||
|
||||
private String deriveName(String label, SpiQuery.Type type) {
|
||||
private String deriveName(String label, SpiQuery.Type type, String simpleName) {
|
||||
if (label == null) {
|
||||
return "orm." + beanType.getSimpleName() + "." + type.label();
|
||||
return Str.add("orm.", simpleName, ".", type.label());
|
||||
}
|
||||
if (label.startsWith(beanType.getSimpleName())) {
|
||||
return "orm." + label;
|
||||
int pos = simpleName.indexOf('.');
|
||||
if (pos > 1) {
|
||||
// element collection and label
|
||||
return Str.add("orm.", simpleName.substring(0, pos), "_", label);
|
||||
}
|
||||
return "orm." + beanType.getSimpleName() + "_" + label;
|
||||
if (label.startsWith(simpleName)) {
|
||||
return Str.add("orm.", label);
|
||||
}
|
||||
return Str.add("orm.", simpleName, "_", label);
|
||||
}
|
||||
|
||||
private SpiQueryBindCapture initBindCapture(SpiQuery<?> query) {
|
||||
|
||||
@@ -544,6 +544,16 @@ class DefaultFetchGroupQuery<T> implements SpiFetchGroupQuery<T> {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(LockType lockType) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(LockType lockType, LockWait lockWait) {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> forUpdate() {
|
||||
throw new RuntimeException("EB102: Only select() and fetch() clause is allowed on FetchGroup");
|
||||
|
||||
@@ -58,7 +58,7 @@ public class DefaultOrmQueryEngine implements OrmQueryEngine {
|
||||
// before we perform a query, we need to flush any
|
||||
// previous persist requests that are queued/batched.
|
||||
// The query may read data affected by those requests.
|
||||
t.flushBatch();
|
||||
t.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
private final transient SpiEbeanServer server;
|
||||
|
||||
private final transient ReentrantLock lock = new ReentrantLock(false);
|
||||
private final transient ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
@@ -963,6 +963,16 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(LockType lockType) {
|
||||
return setForUpdateWithMode(LockWait.WAIT, lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<T> withLock(LockType lockType, LockWait lockWait) {
|
||||
return setForUpdateWithMode(lockWait, lockType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultOrmQuery<T> forUpdate() {
|
||||
return setForUpdateWithMode(LockWait.WAIT, LockType.DEFAULT);
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
*/
|
||||
private final HashMap<Class<?>, ClassContext> typeCache = new HashMap<>();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private int putCount;
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private final File dir;
|
||||
|
||||
|
||||
+15
@@ -586,6 +586,21 @@ class ImplicitReadOnlyTransaction implements SpiTransaction, TxnProfileEventCode
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRollback(Throwable cause) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the transaction is active.
|
||||
*/
|
||||
|
||||
@@ -373,6 +373,9 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
|
||||
private void firePreCommit() {
|
||||
withEachCallback(TransactionCallback::preCommit);
|
||||
if (changeLogHolder != null) {
|
||||
changeLogHolder.preCommit();
|
||||
}
|
||||
}
|
||||
|
||||
private void firePostCommit() {
|
||||
@@ -981,14 +984,23 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
* Batch flush, jdbc commit, trigger registered TransactionCallbacks, notify l2 cache etc.
|
||||
*/
|
||||
private void flushCommitAndNotify() throws SQLException {
|
||||
internalBatchFlush();
|
||||
firePreCommit();
|
||||
// only performCommit can throw an exception
|
||||
preCommit();
|
||||
performCommit();
|
||||
postCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCommit() {
|
||||
firePostCommit();
|
||||
notifyCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
internalBatchFlush();
|
||||
firePreCommit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a commit, fire callbacks and notify l2 cache etc.
|
||||
* <p>
|
||||
@@ -1132,11 +1144,16 @@ class JdbcTransaction implements SpiTransaction, TxnProfileEventCodes {
|
||||
|
||||
} finally {
|
||||
// these will not throw an exception
|
||||
firePostRollback();
|
||||
notifyRollback(cause);
|
||||
postRollback(cause);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRollback(Throwable cause) {
|
||||
firePostRollback();
|
||||
notifyRollback(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the transaction is active then perform rollback.
|
||||
*/
|
||||
|
||||
@@ -13,9 +13,9 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
|
||||
private final UserTransaction userTransaction;
|
||||
|
||||
private boolean commmitted;
|
||||
private final boolean newTransaction;
|
||||
|
||||
private boolean newTransaction;
|
||||
private boolean committed;
|
||||
|
||||
/**
|
||||
* Create the JtaTransaction.
|
||||
@@ -41,7 +41,6 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
if (connection.getAutoCommit()) {
|
||||
connection.setAutoCommit(false);
|
||||
}
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
@@ -52,7 +51,7 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
*/
|
||||
@Override
|
||||
public void commit() {
|
||||
if (commmitted) {
|
||||
if (committed) {
|
||||
throw new PersistenceException("This transaction has already been committed.");
|
||||
}
|
||||
try {
|
||||
@@ -60,14 +59,14 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
if (newTransaction) {
|
||||
userTransaction.commit();
|
||||
}
|
||||
notifyCommit();
|
||||
postCommit();
|
||||
} finally {
|
||||
close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
commmitted = true;
|
||||
committed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,7 +79,7 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
*/
|
||||
@Override
|
||||
public void rollback(Throwable e) {
|
||||
if (!commmitted) {
|
||||
if (!committed) {
|
||||
try {
|
||||
try {
|
||||
if (userTransaction != null) {
|
||||
@@ -90,7 +89,7 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
userTransaction.setRollbackOnly();
|
||||
}
|
||||
}
|
||||
notifyRollback(e);
|
||||
postRollback(e);
|
||||
} finally {
|
||||
closeConnection();
|
||||
}
|
||||
@@ -98,7 +97,6 @@ public class JtaTransaction extends JdbcTransaction {
|
||||
throw new PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
-5
@@ -190,19 +190,17 @@ public class JtaTransactionManager implements ExternalTransactionManager {
|
||||
|
||||
@Override
|
||||
public void beforeCompletion() {
|
||||
// Future note: for JPA2 locking we will
|
||||
// have beforeCommit events to fire
|
||||
transaction.preCommit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(int status) {
|
||||
|
||||
switch (status) {
|
||||
case Status.STATUS_COMMITTED:
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Jta Txn [" + transaction.getId() + "] committed");
|
||||
}
|
||||
transactionManager.notifyOfCommit(transaction);
|
||||
transaction.postCommit();
|
||||
// Remove this transaction object as it is completed
|
||||
transactionManager.scope().clearExternal();
|
||||
break;
|
||||
@@ -211,7 +209,7 @@ public class JtaTransactionManager implements ExternalTransactionManager {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Jta Txn [" + transaction.getId() + "] rollback");
|
||||
}
|
||||
transactionManager.notifyOfRollback(transaction, null);
|
||||
transaction.postRollback(null);
|
||||
// Remove this transaction object as it is completed
|
||||
transactionManager.scope().clearExternal();
|
||||
break;
|
||||
|
||||
@@ -88,6 +88,21 @@ class NoTransaction implements SpiTransaction {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCommit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCommit() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRollback(Throwable cause) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLogPrefix() {
|
||||
return null;
|
||||
|
||||
@@ -56,20 +56,31 @@ public class TChangeLogHolder {
|
||||
* Add a bean change to the change set.
|
||||
*/
|
||||
public void addBeanChange(BeanChange change) {
|
||||
|
||||
changes.addBeanChange(change);
|
||||
if (++count >= batchSize) {
|
||||
// we hit the batch size so send what we have knowing
|
||||
// that the transaction has not completed yet and
|
||||
// reset the changes and count
|
||||
owner.sendChangeLog(changes);
|
||||
changes = new ChangeSet(transactionId, ++batchId);
|
||||
count = 0;
|
||||
sendChanges();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendChanges() {
|
||||
owner.sendChangeLog(changes);
|
||||
changes = new ChangeSet(transactionId, ++batchId);
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* On post commit send the changes we have collected.
|
||||
* Send the changes held prior to transaction commit.
|
||||
*/
|
||||
public void preCommit() {
|
||||
sendChanges();
|
||||
}
|
||||
|
||||
/**
|
||||
* On post commit send the changes we have collected. This should be
|
||||
* only the COMMITTED state and with all changes sent prior to commit.
|
||||
*/
|
||||
public void postCommit() {
|
||||
changes.setTxnState(TxnState.COMMITTED);
|
||||
|
||||
+1
-1
@@ -634,7 +634,7 @@ public class TransactionManager implements SpiTransactionManager {
|
||||
public ScopedTransaction externalBeginTransaction(SpiTransaction transaction, TxScope txScope) {
|
||||
ScopedTransaction scopedTxn = new ScopedTransaction(scopeManager);
|
||||
scopedTxn.push(new ScopeTrans(rollbackOnChecked, false, transaction, txScope));
|
||||
scopeManager.set(scopedTxn);
|
||||
scopeManager.replace(scopedTxn);
|
||||
return scopedTxn;
|
||||
}
|
||||
|
||||
|
||||
@@ -256,7 +256,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* Load custom scalar types registered via ExtraTypeFactory and ServiceLoader.
|
||||
*/
|
||||
private void loadTypesFromProviders(DatabaseConfig config, Object objectMapper) {
|
||||
|
||||
ServiceLoader<ExtraTypeFactory> factories = ServiceLoader.load(ExtraTypeFactory.class);
|
||||
Iterator<ExtraTypeFactory> iterator = factories.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
@@ -291,7 +290,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
@Override
|
||||
public void addEnumType(ScalarType<?> scalarType, Class<? extends Enum> enumClass) {
|
||||
|
||||
Set<Class<?>> mappedClasses = new HashSet<>();
|
||||
mappedClasses.add(enumClass);
|
||||
for (Object value : EnumSet.allOf(enumClass).toArray()) {
|
||||
@@ -360,20 +358,16 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getArrayScalarType(Class<?> type, DbArray dbArray, Type genericType, boolean nullable) {
|
||||
|
||||
Type valueType = getValueType(genericType);
|
||||
if (type.equals(List.class)) {
|
||||
return getArrayScalarTypeList(valueType, nullable);
|
||||
|
||||
} else if (type.equals(Set.class)) {
|
||||
return getArrayScalarTypeSet(valueType, nullable);
|
||||
|
||||
} else {
|
||||
throw new IllegalStateException("Type [" + type + "] not supported for @DbArray");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private ScalarType<?> getArrayScalarTypeSet(Type valueType, boolean nullable) {
|
||||
if (arrayTypeSetFactory != null) {
|
||||
if (isEnumType(valueType)) {
|
||||
@@ -385,7 +379,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return new ScalarTypeJsonSet.Varchar(getDocType(valueType), nullable);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private ScalarType<?> getArrayScalarTypeList(Type valueType, boolean nullable) {
|
||||
if (arrayTypeListFactory != null) {
|
||||
if (isEnumType(valueType)) {
|
||||
@@ -407,10 +400,8 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
@Override
|
||||
public ScalarType<?> getJsonScalarType(DeployBeanProperty prop, int dbType, int dbLength) {
|
||||
|
||||
Class<?> type = prop.getPropertyType();
|
||||
Type genericType = prop.getGenericType();
|
||||
|
||||
boolean hasJacksonAnnotations = objectMapperPresent && checkJacksonAnnotations(prop);
|
||||
|
||||
if (type.equals(List.class)) {
|
||||
@@ -421,7 +412,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals(Set.class)) {
|
||||
DocPropertyType docType = getDocType(genericType);
|
||||
if (!hasJacksonAnnotations && isValueTypeSimple(genericType)) {
|
||||
@@ -430,7 +420,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return createJsonObjectMapperType(prop, dbType, docType);
|
||||
}
|
||||
}
|
||||
|
||||
if (type.equals(Map.class)) {
|
||||
if (!hasJacksonAnnotations && isMapValueTypeObject(genericType)) {
|
||||
return ScalarTypeJsonMap.typeFor(postgres, dbType);
|
||||
@@ -438,7 +427,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT);
|
||||
}
|
||||
}
|
||||
|
||||
if (objectMapperPresent) {
|
||||
if (type.equals(JsonNode.class)) {
|
||||
switch (dbType) {
|
||||
@@ -455,7 +443,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return createJsonObjectMapperType(prop, dbType, DocPropertyType.OBJECT);
|
||||
}
|
||||
|
||||
@@ -510,11 +497,9 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* <p>
|
||||
* Used for java.util.Date and java.util.Calendar which can be mapped to
|
||||
* different jdbcTypes in a single system.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public ScalarType<?> getScalarType(Class<?> type, int jdbcType) {
|
||||
|
||||
// File is a special Lob so check for that first
|
||||
if (File.class.equals(type)) {
|
||||
return fileType;
|
||||
@@ -554,10 +539,8 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* Kind of special case because these map multiple jdbc types to single Java
|
||||
* types - like String - Varchar, LongVarchar, Clob. For this reason I check
|
||||
* for the specific Lob types first before looking for a matching type.
|
||||
* </p>
|
||||
*/
|
||||
private ScalarType<?> getLobTypes(int jdbcType) {
|
||||
|
||||
return getScalarType(jdbcType);
|
||||
}
|
||||
|
||||
@@ -601,14 +584,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* Create the Mapping of Enum fields to DB values using EnumValue annotations.
|
||||
* <p>
|
||||
* Return null if the EnumValue annotations are not present/used.
|
||||
* </p>
|
||||
*/
|
||||
private ScalarTypeEnum<?> createEnumScalarType2(Class<?> enumType) {
|
||||
|
||||
boolean integerType = true;
|
||||
|
||||
Map<String, String> nameValueMap = new LinkedHashMap<>();
|
||||
|
||||
Field[] fields = enumType.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
EnumValue enumValue = AnnotationUtil.get(field, EnumValue.class);
|
||||
@@ -624,8 +603,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
// Not using EnumValue here
|
||||
return null;
|
||||
}
|
||||
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, 0);
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, 0, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -635,17 +613,14 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* such as A,I,N rather than the ACTIVE, INACTIVE, NEW. So there really needs
|
||||
* to be a mapping from the nicely named enumeration values to the typically
|
||||
* much shorter codes used in the DB.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public ScalarType<?> createEnumScalarType(Class<? extends Enum<?>> enumType, EnumType type) {
|
||||
|
||||
ScalarType<?> scalarType = getScalarType(enumType);
|
||||
if (scalarType instanceof ScalarTypeWrapper) {
|
||||
// no override or further mapping required
|
||||
return scalarType;
|
||||
}
|
||||
|
||||
ScalarTypeEnum<?> scalarEnum = (ScalarTypeEnum<?>)scalarType;
|
||||
if (scalarEnum != null && !scalarEnum.isOverrideBy(type)) {
|
||||
if (type != null && !scalarEnum.isCompatible(type)) {
|
||||
@@ -653,7 +628,6 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
}
|
||||
return scalarEnum;
|
||||
}
|
||||
|
||||
scalarEnum = createEnumScalarTypePerExtentions(enumType);
|
||||
if (scalarEnum == null) {
|
||||
// use JPA normal Enum type (without mapping)
|
||||
@@ -665,33 +639,27 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
private ScalarTypeEnum<?> createEnumScalarTypePerSpec(Class<?> enumType, EnumType type) {
|
||||
if (type == null) {
|
||||
|
||||
if(defaultEnumType == EnumType.ORDINAL) {
|
||||
if (defaultEnumType == EnumType.ORDINAL) {
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else {
|
||||
return new ScalarTypeEnumStandard.StringEnum(enumType);
|
||||
}
|
||||
|
||||
} else if (type == EnumType.ORDINAL) {
|
||||
return new ScalarTypeEnumStandard.OrdinalEnum(enumType);
|
||||
|
||||
} else {
|
||||
return new ScalarTypeEnumStandard.StringEnum(enumType);
|
||||
}
|
||||
}
|
||||
|
||||
private ScalarTypeEnum<?> createEnumScalarTypePerExtentions(Class<? extends Enum<?>> enumType) {
|
||||
|
||||
Method[] methods = enumType.getMethods();
|
||||
for (Method method : methods) {
|
||||
DbEnumValue dbValue = AnnotationUtil.get(method, DbEnumValue.class);
|
||||
if (dbValue != null) {
|
||||
boolean integerValues = DbEnumType.INTEGER == dbValue.storage();
|
||||
return createEnumScalarTypeDbValue(enumType, method, integerValues, dbValue.length());
|
||||
return createEnumScalarTypeDbValue(enumType, method, integerValues, dbValue.length(), dbValue.withConstraint());
|
||||
}
|
||||
}
|
||||
|
||||
// look for EnumValue annotations instead
|
||||
return createEnumScalarType2(enumType);
|
||||
}
|
||||
@@ -702,10 +670,8 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* Return null if the EnumValue annotations are not present/used.
|
||||
* </p>
|
||||
*/
|
||||
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType, int length) {
|
||||
|
||||
private ScalarTypeEnum<?> createEnumScalarTypeDbValue(Class<? extends Enum<?>> enumType, Method method, boolean integerType, int length, boolean withConstraint) {
|
||||
Map<String, String> nameValueMap = new LinkedHashMap<>();
|
||||
|
||||
Enum<?>[] enumConstants = enumType.getEnumConstants();
|
||||
for (Enum<?> enumConstant : enumConstants) {
|
||||
try {
|
||||
@@ -719,8 +685,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
// Not using EnumValue here
|
||||
return null;
|
||||
}
|
||||
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, length);
|
||||
return createEnumScalarType(enumType, nameValueMap, integerType, length, withConstraint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,27 +693,20 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* length create the ScalarType for the Enum.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private ScalarTypeEnum<?> createEnumScalarType(Class enumType, Map<String, String> nameValueMap, boolean integerType, int dbColumnLength) {
|
||||
|
||||
private ScalarTypeEnum<?> createEnumScalarType(Class enumType, Map<String, String> nameValueMap, boolean integerType, int dbColumnLength, boolean withConstraint) {
|
||||
EnumToDbValueMap<?> beanDbMap = EnumToDbValueMap.create(integerType);
|
||||
|
||||
int maxValueLen = 0;
|
||||
|
||||
for (Map.Entry<String, String> entry : nameValueMap.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
|
||||
maxValueLen = Math.max(maxValueLen, value.length());
|
||||
|
||||
Object enumValue = Enum.valueOf(enumType, name.trim());
|
||||
beanDbMap.add(enumValue, value, name.trim());
|
||||
}
|
||||
|
||||
if (dbColumnLength == 0 && !integerType) {
|
||||
dbColumnLength = maxValueLen;
|
||||
}
|
||||
|
||||
return new ScalarTypeEnumWithMapping(beanDbMap, enumType, dbColumnLength);
|
||||
return new ScalarTypeEnumWithMapping(beanDbMap, enumType, dbColumnLength, withConstraint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -760,10 +718,8 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
* </p>
|
||||
*/
|
||||
private void initialiseCustomScalarTypes(BootupClasses bootupClasses) {
|
||||
|
||||
for (Class<? extends ScalarType<?>> cls : bootupClasses.getScalarTypes()) {
|
||||
try {
|
||||
|
||||
ScalarType<?> scalarType;
|
||||
if (objectMapper == null) {
|
||||
scalarType = cls.newInstance();
|
||||
@@ -776,9 +732,7 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
scalarType = cls.newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
addCustomType(scalarType);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error loading ScalarType [" + cls.getName() + "]";
|
||||
logger.error(msg, e);
|
||||
@@ -801,30 +755,23 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void initialiseScalarConverters(BootupClasses bootupClasses) {
|
||||
|
||||
List<Class<? extends ScalarTypeConverter<?, ?>>> foundTypes = bootupClasses.getScalarConverters();
|
||||
|
||||
for (Class<? extends ScalarTypeConverter<?, ?>> foundType : foundTypes) {
|
||||
try {
|
||||
|
||||
Class<?>[] paramTypes = TypeReflectHelper.getParams(foundType, ScalarTypeConverter.class);
|
||||
if (paramTypes.length != 2) {
|
||||
throw new IllegalStateException("Expected 2 generics paramtypes but got: " + Arrays.toString(paramTypes));
|
||||
}
|
||||
|
||||
Class<?> logicalType = paramTypes[0];
|
||||
Class<?> persistType = paramTypes[1];
|
||||
|
||||
ScalarType<?> wrappedType = getScalarType(persistType);
|
||||
if (wrappedType == null) {
|
||||
throw new IllegalStateException("Could not find ScalarType for: " + paramTypes[1]);
|
||||
}
|
||||
|
||||
ScalarTypeConverter converter = foundType.newInstance();
|
||||
ScalarTypeWrapper stw = new ScalarTypeWrapper(logicalType, wrappedType, converter);
|
||||
logger.debug("Register ScalarTypeWrapper from {} -> {} using:{}", logicalType, persistType, foundType);
|
||||
add(stw);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error registering ScalarTypeConverter [" + foundType.getName() + "]", e);
|
||||
}
|
||||
@@ -833,30 +780,23 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private void initialiseAttributeConverters(BootupClasses bootupClasses) {
|
||||
|
||||
List<Class<? extends AttributeConverter<?, ?>>> foundTypes = bootupClasses.getAttributeConverters();
|
||||
|
||||
for (Class<? extends AttributeConverter<?, ?>> foundType : foundTypes) {
|
||||
try {
|
||||
|
||||
Class<?>[] paramTypes = TypeReflectHelper.getParams(foundType, AttributeConverter.class);
|
||||
if (paramTypes.length != 2) {
|
||||
throw new IllegalStateException("Expected 2 generics paramtypes but got: " + Arrays.toString(paramTypes));
|
||||
}
|
||||
|
||||
Class<?> logicalType = paramTypes[0];
|
||||
Class<?> persistType = paramTypes[1];
|
||||
|
||||
ScalarType<?> wrappedType = getScalarType(persistType);
|
||||
if (wrappedType == null) {
|
||||
throw new IllegalStateException("Could not find ScalarType for: " + paramTypes[1]);
|
||||
}
|
||||
|
||||
AttributeConverter converter = foundType.newInstance();
|
||||
ScalarTypeWrapper stw = new ScalarTypeWrapper(logicalType, wrappedType, new AttributeConverterAdapter(converter));
|
||||
logger.debug("Register ScalarTypeWrapper from {} -> {} using:{}", logicalType, persistType, foundType);
|
||||
add(stw);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error registering AttributeConverter [" + foundType.getName() + "]", e);
|
||||
}
|
||||
@@ -875,12 +815,10 @@ public final class DefaultTypeManager implements TypeManager {
|
||||
jsonNodeVarchar = new ScalarTypeJsonNode.Varchar(mapper);
|
||||
jsonNodeJson = jsonNodeClob; // Default for non-Postgres databases
|
||||
jsonNodeJsonb = jsonNodeClob; // Default for non-Postgres databases
|
||||
|
||||
if (isPostgres(config.getDatabasePlatform())) {
|
||||
jsonNodeJson = new ScalarTypeJsonNodePostgres.JSON(mapper);
|
||||
jsonNodeJsonb = new ScalarTypeJsonNodePostgres.JSONB(mapper);
|
||||
}
|
||||
|
||||
// add as default mapping for JsonNode (when not annotated with @DbJson etc)
|
||||
typeMap.put(JsonNode.class, jsonNodeJson);
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ScalarTypeArrayList extends ScalarTypeArrayBase<List> implements Sc
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final Map<String, ScalarTypeArrayList> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ class ScalarTypeArrayListH2 extends ScalarTypeArrayList {
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final Map<String, ScalarTypeArrayListH2> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
|
||||
@@ -36,7 +36,7 @@ public class ScalarTypeArraySet extends ScalarTypeArrayBase<Set> implements Scal
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final Map<String, ScalarTypeArraySet> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,7 @@ class ScalarTypeArraySetH2 extends ScalarTypeArraySet {
|
||||
|
||||
static class Factory implements PlatformArrayTypeFactory {
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
private final Map<String, ScalarTypeArraySetH2> cache = new HashMap<>();
|
||||
|
||||
/**
|
||||
|
||||
+11
-4
@@ -20,13 +20,20 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i
|
||||
|
||||
private final int length;
|
||||
|
||||
private final boolean withConstraint;
|
||||
|
||||
/**
|
||||
* Create with an explicit mapping of bean to database values.
|
||||
*/
|
||||
public ScalarTypeEnumWithMapping(EnumToDbValueMap<?> beanDbMap, Class<?> enumType, int length) {
|
||||
public ScalarTypeEnumWithMapping(EnumToDbValueMap<?> beanDbMap, Class<?> enumType, int length, boolean withConstraint) {
|
||||
super(enumType, false, beanDbMap.getDbType());
|
||||
this.beanDbMap = beanDbMap;
|
||||
this.length = length;
|
||||
this.withConstraint = withConstraint;
|
||||
}
|
||||
|
||||
public ScalarTypeEnumWithMapping(EnumToDbValueMap<?> beanDbMap, Class<?> enumType, int length) {
|
||||
this(beanDbMap, enumType, length, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -49,6 +56,9 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getDbCheckConstraintValues() {
|
||||
if (!withConstraint) {
|
||||
return null;
|
||||
}
|
||||
LinkedHashSet values = new LinkedHashSet();
|
||||
Iterator<?> it = beanDbMap.dbValues();
|
||||
while (it.hasNext()) {
|
||||
@@ -64,9 +74,6 @@ public class ScalarTypeEnumWithMapping extends ScalarTypeEnumStandard.EnumBase i
|
||||
|
||||
/**
|
||||
* Return the DB column length for storing the enum value.
|
||||
* <p>
|
||||
* This is for enum's mapped to strings.
|
||||
* </p>
|
||||
*/
|
||||
@Override
|
||||
public int getLength() {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
-56
@@ -1,56 +0,0 @@
|
||||
package io.ebeaninternal.server.core;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultBackgroundExecutorTest {
|
||||
|
||||
@Test
|
||||
@Ignore("test takes long time")
|
||||
public void shutdown_when_running_expect_waitAndNiceShutdown() throws Exception {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 20, "test");
|
||||
|
||||
es.execute(new RunFor(3000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
es.execute(new RunFor(3000, "c"));
|
||||
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("test takes long time")
|
||||
public void shutdown_when_rougeRunnable_expect_InterruptedException() throws Exception {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
|
||||
es.execute(new RunFor(300000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
es.execute(new RunFor(3000, "c"));
|
||||
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
|
||||
class RunFor implements Runnable {
|
||||
|
||||
final long wait;
|
||||
final String id;
|
||||
|
||||
RunFor(long wait, String id) {
|
||||
this.wait = wait;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("start " + id);
|
||||
Thread.sleep(wait);
|
||||
System.out.println("done " + id);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import io.ebeaninternal.server.executor.DefaultBackgroundExecutor;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.MDC;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class DefaultBackgroundExecutorTest {
|
||||
|
||||
@Test
|
||||
public void submit_callable() throws Exception {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 2, "test");
|
||||
|
||||
final Future<String> future0 = es.submit(() -> "Hello");
|
||||
final Future<String> future1 = es.submit(() -> "There");
|
||||
final Future<String> future2 = es.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
return "Slow";
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return "Interrupted";
|
||||
}
|
||||
});
|
||||
|
||||
es.shutdown();
|
||||
|
||||
assertThat(future0.get()).isEqualTo("Hello");
|
||||
assertThat(future1.get(1, TimeUnit.SECONDS)).isEqualTo("There");
|
||||
assertThat(future2.get()).isEqualTo("Slow");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shutdown_slowCallable_expect_interrupted() throws Exception {
|
||||
|
||||
int shutdownWaitSecs = 1;
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, shutdownWaitSecs, "test");
|
||||
|
||||
final Future<String> future2 = es.submit(() -> {
|
||||
try {
|
||||
Thread.sleep(1500); // longer than shutdown wait
|
||||
return "Slow";
|
||||
} catch (InterruptedException e) {
|
||||
// expected for this test
|
||||
Thread.currentThread().interrupt();
|
||||
return "Interrupted";
|
||||
}
|
||||
});
|
||||
|
||||
// shutdown waits max shutdownWaitSecs seconds for active tasks
|
||||
es.shutdown();
|
||||
assertThat(future2.get()).isEqualTo("Interrupted");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("test takes long time")
|
||||
public void shutdown_when_running_expect_waitAndNiceShutdown() {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 20, "test");
|
||||
|
||||
es.execute(new RunFor(3000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
es.execute(new RunFor(3000, "c"));
|
||||
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("test takes long time")
|
||||
public void shutdown_when_rougeRunnable_expect_InterruptedException() {
|
||||
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
|
||||
es.execute(new RunFor(300000, "a"));
|
||||
es.execute(new RunFor(3000, "b"));
|
||||
es.execute(new RunFor(3000, "c"));
|
||||
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapWithNoMDC() {
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
es.wrapMDC(() -> {
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
});
|
||||
es.wrapMDC(() -> {
|
||||
assertThat(MDC.getCopyOfContextMap()).isNull();
|
||||
return "Callable";
|
||||
});
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrapWithMDC_expect_() {
|
||||
DefaultBackgroundExecutor es = new DefaultBackgroundExecutor(1, 10, "test");
|
||||
MDC.clear();
|
||||
MDC.put("hello", "there");
|
||||
es.wrapMDC(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
});
|
||||
es.wrapMDC(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
return "Callable";
|
||||
});
|
||||
es.execute(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
});
|
||||
es.submit(() -> {
|
||||
assertThat(MDC.get("hello")).isEqualTo("there");
|
||||
return "Callable";
|
||||
});
|
||||
MDC.clear();
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
private static class RunFor implements Runnable {
|
||||
|
||||
final long wait;
|
||||
final String id;
|
||||
|
||||
RunFor(long wait, String id) {
|
||||
this.wait = wait;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println("start " + id);
|
||||
Thread.sleep(wait);
|
||||
System.out.println("done " + id);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package io.ebeaninternal.server.executor;
|
||||
|
||||
import io.ebean.BackgroundExecutor;
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Database;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.tests.model.basic.Customer;
|
||||
|
||||
public class TestShutdownWithBackgroundTasks extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void test() {
|
||||
|
||||
Database server = DB.getDefault();
|
||||
final BackgroundExecutor bg = server.getBackgroundExecutor();
|
||||
try {
|
||||
for (int i = 0; i < 12; i++) {
|
||||
bg.execute(new Job(server, 500, i));
|
||||
}
|
||||
|
||||
Thread.sleep(1000);
|
||||
server.shutdown();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static class Job implements Runnable {
|
||||
|
||||
final Database server;
|
||||
final long sleepMillis;
|
||||
final int position;
|
||||
|
||||
Job(Database server, long sleepMillis, int position) {
|
||||
this.server = server;
|
||||
this.sleepMillis = sleepMillis;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println(position + " sleep " + sleepMillis);
|
||||
Thread.sleep(sleepMillis);
|
||||
server.find(Customer.class).findCount();
|
||||
System.out.println(position + " sleep done");
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-67
@@ -1,67 +0,0 @@
|
||||
package io.ebeaninternal.server.lib.sql;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.EbeanServer;
|
||||
import io.ebeaninternal.server.core.DefaultBackgroundExecutor;
|
||||
import org.tests.model.basic.Customer;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestDataSourceMaxWithEntity extends BaseTestCase {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
|
||||
boolean skipThisTest = true;
|
||||
|
||||
if (skipThisTest) {
|
||||
return;
|
||||
}
|
||||
|
||||
EbeanServer server = Ebean.getServer(null);
|
||||
|
||||
|
||||
DefaultBackgroundExecutor bg = new DefaultBackgroundExecutor(1, 30, "testDs");
|
||||
|
||||
try {
|
||||
for (int i = 0; i < 12; i++) {
|
||||
// Thread.sleep(10*i);
|
||||
bg.execute(new ConnRunner(server, 4000, i));
|
||||
}
|
||||
|
||||
Thread.sleep(30000);
|
||||
|
||||
server.shutdown(true, false);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ConnRunner implements Runnable {
|
||||
|
||||
final EbeanServer server;
|
||||
final long sleepMillis;
|
||||
final int position;
|
||||
|
||||
ConnRunner(EbeanServer server, long sleepMillis, int position) {
|
||||
this.server = server;
|
||||
this.sleepMillis = sleepMillis;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
server.find(Customer.class).findCount();
|
||||
try {
|
||||
System.out.println(position + " sleep " + sleepMillis);
|
||||
Thread.sleep(sleepMillis);
|
||||
System.out.println(position + " sleep done");
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user