diff --git a/ebean-api/src/main/java/io/ebean/DbContext.java b/ebean-api/src/main/java/io/ebean/DbContext.java
index f7af636bf..cf09dc7fb 100644
--- a/ebean-api/src/main/java/io/ebean/DbContext.java
+++ b/ebean-api/src/main/java/io/ebean/DbContext.java
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
import javax.persistence.PersistenceException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Holds Database instances.
@@ -22,17 +23,11 @@ final class DbContext {
private static final DbContext INSTANCE = new DbContext();
- /**
- * Cache for fast concurrent read access.
- */
private final ConcurrentHashMap concMap = new ConcurrentHashMap<>();
- /**
- * Cache for synchronized read, creation and put. Protected by the monitor object.
- */
private final HashMap syncMap = new HashMap<>();
- private final Object monitor = new Object();
+ private final ReentrantLock lock = new ReentrantLock(false);
/**
* The 'default' Database.
@@ -91,27 +86,28 @@ final class DbContext {
if (name == null || name.isEmpty()) {
return defaultDatabase;
}
- // non-synchronized read
Database server = concMap.get(name);
if (server != null) {
return server;
}
- // synchronized read, create and put
return getWithCreate(name);
}
/**
- * Synchronized read, create and put of Databases.
+ * Read, create and put of Databases.
*/
private Database getWithCreate(String name) {
- synchronized (monitor) {
+ lock.lock();
+ try {
Database server = syncMap.get(name);
if (server == null) {
// register when creating server this way
- server = EbeanServerFactory.create(name);
+ server = DatabaseFactory.create(name);
register(server, false);
}
return server;
+ } finally {
+ lock.unlock();
}
}
@@ -123,12 +119,15 @@ final class DbContext {
}
private void registerWithName(String name, Database server, boolean isDefault) {
- synchronized (monitor) {
+ lock.lock();
+ try {
concMap.put(name, server);
syncMap.put(name, server);
if (isDefault) {
defaultDatabase = server;
}
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java b/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java
index ed98effd6..a38b6aed9 100644
--- a/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java
+++ b/ebean-api/src/main/java/io/ebean/EbeanServerFactory.java
@@ -39,28 +39,28 @@ public class EbeanServerFactory {
* Call this prior to creating any EbeanServer instances or alternatively set the
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
*/
- public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
+ public static void initialiseContainer(ContainerConfig containerConfig) {
DatabaseFactory.initialiseContainer(containerConfig);
}
/**
* Create using ebean.properties to configure the database.
*/
- public static synchronized EbeanServer create(String name) {
+ public static EbeanServer create(String name) {
return (EbeanServer)DatabaseFactory.create(name);
}
/**
* Create using the ServerConfig object to configure the database.
*/
- public static synchronized EbeanServer create(ServerConfig config) {
+ public static EbeanServer create(ServerConfig config) {
return (EbeanServer)DatabaseFactory.create(config);
}
/**
* Create using the ServerConfig additionally specifying a classLoader to use as the context class loader.
*/
- public static synchronized EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
+ public static EbeanServer createWithContextClassLoader(ServerConfig config, ClassLoader classLoader) {
return (EbeanServer)DatabaseFactory.createWithContextClassLoader(config, classLoader);
}
@@ -70,7 +70,7 @@ public class EbeanServerFactory {
* This is typically invoked via JVM shutdown hook and not explicitly called.
*
*/
- public static synchronized void shutdown() {
+ public static void shutdown() {
DatabaseFactory.shutdown();
}
diff --git a/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java b/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java
index af96a3d01..5bfbfda08 100644
--- a/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java
+++ b/ebean-api/src/main/java/io/ebean/bean/BeanLoader.java
@@ -1,5 +1,7 @@
package io.ebean.bean;
+import java.util.concurrent.locks.Lock;
+
/**
* Loads a entity bean.
*
@@ -18,4 +20,9 @@ public interface BeanLoader {
*/
void loadBean(EntityBeanIntercept ebi);
+ /**
+ * Obtain a lock on the loader.
+ */
+ Lock lock();
+
}
diff --git a/ebean-api/src/main/java/io/ebean/bean/EntityBeanIntercept.java b/ebean-api/src/main/java/io/ebean/bean/EntityBeanIntercept.java
index 090e93149..4bb520a32 100644
--- a/ebean-api/src/main/java/io/ebean/bean/EntityBeanIntercept.java
+++ b/ebean-api/src/main/java/io/ebean/bean/EntityBeanIntercept.java
@@ -14,6 +14,8 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
* This is the object added to every entity bean using byte code enhancement.
@@ -30,6 +32,8 @@ 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 NodeUsageCollector nodeUsageCollector;
private transient PersistenceContext persistenceContext;
@@ -803,7 +807,8 @@ public final class EntityBeanIntercept implements Serializable {
* Load the bean when it is a reference.
*/
protected void loadBean(int loadProperty) {
- synchronized (this) {
+ lock.lock();
+ try {
if (beanLoader == null) {
final Database database = DB.byName(ebeanServerName);
if (database == null) {
@@ -811,14 +816,19 @@ public final class EntityBeanIntercept implements Serializable {
}
// For stand alone reference bean or after deserialisation lazy load
// using the ebeanServer. Synchronise only on the bean.
- loadBeanInternal(loadProperty, database.getPluginApi());
+ loadBeanInternal(loadProperty, database.getPluginApi().beanLoader());
return;
}
+ } finally {
+ lock.unlock();
}
- synchronized (beanLoader) {
+ final Lock lock = beanLoader.lock();
+ try {
// Lazy loading using LoadBeanContext which supports batch loading
// Synchronise on the beanLoader (a 'node' of the LoadBeanContext 'tree')
loadBeanInternal(loadProperty, beanLoader);
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java b/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java
index fd4ce6651..4d84ada39 100644
--- a/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java
+++ b/ebean-api/src/main/java/io/ebean/bean/SingleBeanLoader.java
@@ -2,11 +2,16 @@ package io.ebean.bean;
import io.ebean.Database;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
/**
* BeanLoader used when single beans are loaded (which is usually not ideal / N+1).
*/
public abstract class SingleBeanLoader implements BeanLoader {
+ private final ReentrantLock lock = new ReentrantLock(false);
+
protected final Database database;
SingleBeanLoader(Database database) {
@@ -18,6 +23,12 @@ public abstract class SingleBeanLoader implements BeanLoader {
return database.getName();
}
+ @Override
+ public Lock lock() {
+ lock.lock();
+ return lock;
+ }
+
/**
* Single bean lazy loaded when bean from L2 cache.
*/
@@ -45,4 +56,18 @@ public abstract class SingleBeanLoader implements BeanLoader {
database.getPluginApi().loadBeanRef(ebi);
}
}
+
+ /**
+ * Single bean lazy loaded when a reference bean.
+ */
+ public static class Dflt extends SingleBeanLoader {
+ public Dflt(Database database) {
+ super(database);
+ }
+
+ @Override
+ public void loadBean(EntityBeanIntercept ebi) {
+ database.getPluginApi().loadBean(ebi);
+ }
+ }
}
diff --git a/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java b/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java
index 5790f9d13..297c6fb9d 100644
--- a/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java
+++ b/ebean-api/src/main/java/io/ebean/common/AbstractBeanCollection.java
@@ -7,6 +7,7 @@ import io.ebean.bean.BeanCollectionLoader;
import io.ebean.bean.EntityBean;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Base class for List Set and Map implementations of BeanCollection.
@@ -15,6 +16,8 @@ abstract class AbstractBeanCollection implements BeanCollection {
private static final long serialVersionUID = 3365725236140187588L;
+ protected final ReentrantLock lock = new ReentrantLock(false);
+
protected boolean readOnly;
protected boolean disableLazyLoad;
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanList.java b/ebean-api/src/main/java/io/ebean/common/BeanList.java
index 42d67b993..0aee7f211 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanList.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanList.java
@@ -115,7 +115,8 @@ public final class BeanList extends AbstractBeanCollection implements List
}
private void initClear() {
- synchronized (this) {
+ lock.lock();
+ try {
if (list == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
@@ -123,11 +124,14 @@ public final class BeanList extends AbstractBeanCollection implements List
list = new ArrayList<>();
}
}
+ } finally {
+ lock.unlock();
}
}
private void init() {
- synchronized (this) {
+ lock.lock();
+ try {
if (list == null) {
if (disableLazyLoad) {
list = new ArrayList<>();
@@ -135,6 +139,8 @@ public final class BeanList extends AbstractBeanCollection implements List
lazyLoadCollection(false);
}
}
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanMap.java b/ebean-api/src/main/java/io/ebean/common/BeanMap.java
index 8277223c0..b2ded02c9 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanMap.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanMap.java
@@ -121,7 +121,8 @@ public final class BeanMap extends AbstractBeanCollection implements Ma
}
private void initClear() {
- synchronized (this) {
+ lock.lock();
+ try {
if (map == null) {
if (!disableLazyLoad && modifyListening) {
lazyLoadCollection(true);
@@ -129,11 +130,14 @@ public final class BeanMap extends AbstractBeanCollection implements Ma
map = new LinkedHashMap<>();
}
}
+ } finally {
+ lock.unlock();
}
}
private void init() {
- synchronized (this) {
+ lock.lock();
+ try {
if (map == null) {
if (disableLazyLoad) {
map = new LinkedHashMap<>();
@@ -141,6 +145,8 @@ public final class BeanMap extends AbstractBeanCollection implements Ma
lazyLoadCollection(false);
}
}
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/common/BeanSet.java b/ebean-api/src/main/java/io/ebean/common/BeanSet.java
index 42872ad10..ec4dc3829 100644
--- a/ebean-api/src/main/java/io/ebean/common/BeanSet.java
+++ b/ebean-api/src/main/java/io/ebean/common/BeanSet.java
@@ -114,7 +114,8 @@ public final class BeanSet extends AbstractBeanCollection implements Set extends AbstractBeanCollection implements Set();
}
}
+ } finally {
+ lock.unlock();
}
}
private void init() {
- synchronized (this) {
+ lock.lock();
+ try {
if (set == null) {
if (disableLazyLoad) {
set = new LinkedHashSet<>();
@@ -134,6 +138,8 @@ public final class BeanSet extends AbstractBeanCollection implements Set extends AbstractList implements List, Serializable {
private static final long serialVersionUID = 1L;
+ private final ReentrantLock lock = new ReentrantLock(false);
+
/**
* The underlying List implementation.
*/
private List list;
-
-
+
public CopyOnFirstWriteList(List list) {
super();
this.list = list;
@@ -166,14 +168,17 @@ public final class CopyOnFirstWriteList extends AbstractList implements Li
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
-
+
private void checkCopyOnWrite() {
if (!copied) {
- synchronized (this) {
+ lock.lock();
+ try {
if (!copied) {
list = new ArrayList<>(list);
copied = true;
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git a/ebean-api/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java b/ebean-api/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java
index 703fa7958..4ac975944 100644
--- a/ebean-api/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java
+++ b/ebean-api/src/main/java/io/ebean/config/dbplatform/SequenceIdGenerator.java
@@ -16,6 +16,7 @@ import java.util.Collections;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Database sequence based IdGenerator.
@@ -24,15 +25,9 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
protected static final Logger logger = LoggerFactory.getLogger("io.ebean.SEQ");
- /**
- * Used to synchronise the idList access.
- */
- protected final Object monitor = new Object();
+ private final ReentrantLock lock = new ReentrantLock(false);
- /**
- * Used to synchronise background loading (loadBatchInBackground).
- */
- protected final Object backgroundLoadMonitor = new Object();
+ private final ReentrantLock loadLock = new ReentrantLock(false);
/**
* The actual sequence name.
@@ -97,7 +92,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
*/
@Override
public Object nextId(Transaction t) {
- synchronized (monitor) {
+ lock.lock();
+ try {
int size = idList.size();
if (size > 0) {
maybeLoadMoreInBackground(size);
@@ -105,6 +101,8 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
loadMore(allocationSize);
}
return idList.pollFirst();
+ } finally {
+ lock.unlock();
}
}
@@ -118,8 +116,11 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
private void loadMore(int requestSize) {
List newIds = getMoreIds(requestSize);
- synchronized (monitor) {
+ lock.lock();
+ try {
idList.addAll(newIds);
+ } finally {
+ lock.unlock();
}
}
@@ -127,23 +128,26 @@ public abstract class SequenceIdGenerator implements PlatformIdGenerator {
* Load another batch of Id's using a background thread.
*/
protected void loadInBackground(final int requestSize) {
-
// single threaded processing...
- synchronized (backgroundLoadMonitor) {
+ loadLock.lock();
+ try {
if (currentlyBackgroundLoading) {
// skip as already background loading
logger.debug("... skip background sequence load (another load in progress)");
return;
}
-
currentlyBackgroundLoading = true;
-
backgroundExecutor.execute(() -> {
loadMore(requestSize);
- synchronized (backgroundLoadMonitor) {
+ loadLock.lock();
+ try {
currentlyBackgroundLoading = false;
+ } finally {
+ loadLock.unlock();
}
});
+ } finally {
+ loadLock.lock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java b/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java
index 32ef7b846..f01a22b83 100644
--- a/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java
+++ b/ebean-api/src/main/java/io/ebean/event/ShutdownManager.java
@@ -11,6 +11,7 @@ import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the shutdown of the JVM Runtime.
@@ -22,6 +23,8 @@ public final class ShutdownManager {
private static final Logger logger = LoggerFactory.getLogger(ShutdownManager.class);
+ private static final ReentrantLock lock = new ReentrantLock(false);
+
private static final List databases = new ArrayList<>();
private static final ShutdownHook shutdownHook = new ShutdownHook();
@@ -56,9 +59,11 @@ public final class ShutdownManager {
* Return true if the system is in the process of stopping.
*/
public static boolean isStopping() {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
+ lock.lock();
+ try {
return stopping;
+ } finally {
+ lock.unlock();
}
}
@@ -74,15 +79,15 @@ public final class ShutdownManager {
*
*/
public static void deregisterShutdownHook() {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
- try {
- Runtime.getRuntime().removeShutdownHook(shutdownHook);
- } catch (IllegalStateException ex) {
- if (!ex.getMessage().equals("Shutdown in progress")) {
- throw ex;
- }
+ lock.lock();
+ try {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ } catch (IllegalStateException ex) {
+ if (!ex.getMessage().equals("Shutdown in progress")) {
+ throw ex;
}
+ } finally {
+ lock.unlock();
}
}
@@ -90,18 +95,18 @@ public final class ShutdownManager {
* Register the shutdown hook with the Runtime.
*/
protected static void registerShutdownHook() {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
- try {
- String value = System.getProperty("ebean.registerShutdownHook");
- if (value == null || !value.trim().equalsIgnoreCase("false")) {
- Runtime.getRuntime().addShutdownHook(shutdownHook);
- }
- } catch (IllegalStateException ex) {
- if (!ex.getMessage().equals("Shutdown in progress")) {
- throw ex;
- }
+ lock.lock();
+ try {
+ String value = System.getProperty("ebean.registerShutdownHook");
+ if (value == null || !value.trim().equalsIgnoreCase("false")) {
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
}
+ } catch (IllegalStateException ex) {
+ if (!ex.getMessage().equals("Shutdown in progress")) {
+ throw ex;
+ }
+ } finally {
+ lock.unlock();
}
}
@@ -112,8 +117,8 @@ public final class ShutdownManager {
*
*/
public static void shutdown() {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
+ lock.lock();
+ try {
if (stopping) {
// Already run shutdown...
return;
@@ -157,6 +162,8 @@ public final class ShutdownManager {
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
deregisterAllJdbcDrivers();
}
+ } finally {
+ lock.unlock();
}
}
@@ -178,9 +185,11 @@ public final class ShutdownManager {
* Register an ebeanServer to be shutdown when the JVM is shutdown.
*/
public static void registerDatabase(Database server) {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
+ lock.lock();
+ try {
databases.add(server);
+ } finally {
+ lock.unlock();
}
}
@@ -191,9 +200,11 @@ public final class ShutdownManager {
*
*/
public static void unregisterDatabase(Database server) {
- //noinspection SynchronizationOnStaticField
- synchronized (databases) {
+ lock.lock();
+ try {
databases.remove(server);
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-api/src/main/java/io/ebean/plugin/SpiServer.java b/ebean-api/src/main/java/io/ebean/plugin/SpiServer.java
index b5c833e12..b2028cadc 100644
--- a/ebean-api/src/main/java/io/ebean/plugin/SpiServer.java
+++ b/ebean-api/src/main/java/io/ebean/plugin/SpiServer.java
@@ -12,7 +12,7 @@ import java.util.List;
/**
* Extensions to Database API made available to plugins.
*/
-public interface SpiServer extends EbeanServer, BeanLoader {
+public interface SpiServer extends EbeanServer {
/**
* Return the DatabaseConfig.
@@ -54,6 +54,11 @@ public interface SpiServer extends EbeanServer, BeanLoader {
*/
DataSource getReadOnlyDataSource();
+ /**
+ * Return a BeanLoader.
+ */
+ BeanLoader beanLoader();
+
/**
* Invoke lazy loading on this single bean (reference bean).
*/
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java
index 968c5f788..d2d38e7cf 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cache/DefaultCacheHolder.java
@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the construction of caches.
@@ -26,17 +27,14 @@ class DefaultCacheHolder {
private static final Logger log = LoggerFactory.getLogger("io.ebean.cache.ALL");
+ private final ReentrantLock lock = new ReentrantLock(false);
private final ConcurrentHashMap allCaches = new ConcurrentHashMap<>();
-
private final ConcurrentHashMap> collectIdCaches = new ConcurrentHashMap<>();
private final ServerCacheFactory cacheFactory;
-
private final ServerCacheOptions beanDefault;
private final ServerCacheOptions queryDefault;
-
private final CurrentTenantProvider tenantProvider;
-
private final QueryCacheEntryValidate queryCacheEntryValidate;
DefaultCacheHolder(CacheManagerOptions builder) {
@@ -87,8 +85,11 @@ class DefaultCacheHolder {
private ServerCache createCache(Class> beanType, ServerCacheType type, String key, String shortName) {
ServerCacheOptions options = getCacheOptions(beanType, type);
if (type == ServerCacheType.COLLECTION_IDS) {
- synchronized (this) {
+ lock.lock();
+ try {
collectIdCaches.computeIfAbsent(beanType.getName(), s -> new ConcurrentSkipListSet<>()).add(key);
+ } finally {
+ lock.unlock();
}
}
return cacheFactory.createCache(new ServerCacheConfig(type, key, shortName, options, tenantProvider, queryCacheEntryValidate));
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
index 514331b7c..face12592 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/cluster/ClusterManager.java
@@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory;
import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the cluster service.
@@ -17,6 +18,8 @@ public class ClusterManager implements ServerLookup {
private static final Logger clusterLogger = LoggerFactory.getLogger("io.ebean.Cluster");
+ private final ReentrantLock lock = new ReentrantLock(false);
+
private final ConcurrentHashMap serverMap = new ConcurrentHashMap<>();
private final Object monitor = new Object();
@@ -51,18 +54,24 @@ public class ClusterManager implements ServerLookup {
}
public void registerServer(EbeanServer server) {
- synchronized (monitor) {
+ lock.lock();
+ try {
serverMap.put(server.getName(), server);
if (!started) {
startup();
}
+ } finally {
+ lock.unlock();
}
}
@Override
public EbeanServer getServer(String name) {
- synchronized (monitor) {
+ lock.lock();
+ try {
return serverMap.get(name);
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
index 777af3605..46f9124c0 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultContainer.java
@@ -26,6 +26,7 @@ import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.ServiceLoader;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Default Server side implementation of ServerFactory.
@@ -34,6 +35,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 ClusterManager clusterManager;
public DefaultContainer(ContainerConfig containerConfig) {
@@ -72,7 +74,8 @@ public class DefaultContainer implements SpiContainer {
*/
@Override
public SpiEbeanServer createServer(DatabaseConfig config) {
- synchronized (this) {
+ lock.lock();
+ try {
applyConfigServices(config);
setNamingConvention(config);
BootupClasses bootupClasses = getBootupClasses(config);
@@ -114,6 +117,8 @@ public class DefaultContainer implements SpiContainer {
}
DbOffline.reset();
return server;
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index 6387ce24b..f683538ec 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -36,11 +36,13 @@ import io.ebean.Version;
import io.ebean.annotation.Platform;
import io.ebean.annotation.TxIsolation;
import io.ebean.bean.BeanCollection;
+import io.ebean.bean.BeanLoader;
import io.ebean.bean.CallOrigin;
import io.ebean.bean.EntityBean;
import io.ebean.bean.EntityBeanIntercept;
import io.ebean.bean.PersistenceContext;
import io.ebean.bean.PersistenceContext.WithOption;
+import io.ebean.bean.SingleBeanLoader;
import io.ebean.cache.ServerCacheManager;
import io.ebean.common.CopyOnFirstWriteList;
import io.ebean.config.CurrentTenantProvider;
@@ -142,6 +144,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.concurrent.Callable;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -157,98 +160,47 @@ 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 DatabaseConfig config;
-
private final String serverName;
-
private final DatabasePlatform databasePlatform;
-
private final TransactionManager transactionManager;
-
private final QueryPlanManager queryPlanManager;
-
private final ExtraMetrics extraMetrics;
-
private final DataTimeZone dataTimeZone;
-
- /**
- * Clock to use for WhenModified and WhenCreated.
- */
private final ClockService clockService;
-
private final CallOriginFactory callStackFactory;
-
- /**
- * Handles the save, delete, updateSql CallableSql.
- */
private final Persister persister;
-
private final OrmQueryEngine queryEngine;
-
private final RelationalQueryEngine relationalQueryEngine;
private final DtoQueryEngine dtoQueryEngine;
-
private final ServerCacheManager serverCacheManager;
-
private final DtoBeanManager dtoBeanManager;
private final BeanDescriptorManager beanDescriptorManager;
-
private final AutoTuneService autoTuneService;
-
private final ReadAuditPrepare readAuditPrepare;
-
private final ReadAuditLogger readAuditLogger;
-
private final CQueryEngine cqueryEngine;
-
private final List serverPlugins;
-
private final SpiDdlGenerator ddlGenerator;
-
private final ScriptRunner scriptRunner;
-
private final ExpressionFactory expressionFactory;
-
private final SpiBackgroundExecutor backgroundExecutor;
-
private final DefaultBeanLoader beanLoader;
-
private final EncryptKeyManager encryptKeyManager;
-
private final SpiJsonContext jsonContext;
-
private final DocumentStore documentStore;
-
private final MetaInfoManager metaInfoManager;
-
private final CurrentTenantProvider currentTenantProvider;
-
private final SpiLogManager logManager;
-
- /**
- * The default PersistenceContextScope used if it is not explicitly set on a query.
- */
private final PersistenceContextScope defaultPersistenceContextScope;
-
- /**
- * Flag set when the server has shutdown.
- */
- private boolean shutdown;
-
- /**
- * The default batch size for lazy loading beans or collections.
- */
private final int lazyLoadBatchSize;
-
private final int queryBatchSize;
-
private final boolean updateAllPropertiesInBatch;
-
private final long slowQueryMicros;
-
private final SlowQueryListener slowQueryListener;
-
private final boolean disableL2Cache;
+ private boolean shutdown;
/**
* Create the DefaultServer.
@@ -452,8 +404,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
@Override
public void shutdown() {
- synchronized (this) {
+ lock.lock();
+ try {
shutdownInternal(true, false);
+ } finally {
+ lock.unlock();
}
}
@@ -462,10 +417,12 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
*/
@Override
public void shutdown(boolean shutdownDataSource, boolean deregisterDriver) {
- synchronized (this) {
- // Unregister from JVM Shutdown hook
+ lock.lock();
+ try {
ShutdownManager.unregisterDatabase(this);
shutdownInternal(shutdownDataSource, deregisterDriver);
+ } finally {
+ lock.unlock();
}
}
@@ -575,6 +532,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
beanLoader.loadBean(loadRequest);
}
+ @Override
+ public BeanLoader beanLoader() {
+ return new SingleBeanLoader.Dflt(this);
+ }
+
@Override
public void loadBean(EntityBeanIntercept ebi) {
beanLoader.loadBean(ebi);
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternString.java b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternString.java
index 0e1feacc8..c952f8f2d 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/core/InternString.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/core/InternString.java
@@ -1,6 +1,7 @@
package io.ebeaninternal.server.core;
import java.util.HashMap;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Used to reduce memory consumption of strings used in deployment processing.
@@ -12,6 +13,8 @@ public final class InternString {
private static final HashMap map = new HashMap<>();
+ private static final ReentrantLock lock = new ReentrantLock(false);
+
/**
* Return the shared instance of this string.
*/
@@ -19,8 +22,8 @@ public final class InternString {
if (s == null) {
return null;
}
- //noinspection SynchronizationOnStaticField
- synchronized (map) {
+ lock.lock();
+ try {
String v = map.get(s);
if (v != null) {
return v;
@@ -28,6 +31,8 @@ public final class InternString {
map.put(s, s);
return s;
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/idgen/UuidV1RndIdGenerator.java b/ebean-core/src/main/java/io/ebeaninternal/server/idgen/UuidV1RndIdGenerator.java
index 4db84223d..d9928c422 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/idgen/UuidV1RndIdGenerator.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/idgen/UuidV1RndIdGenerator.java
@@ -7,6 +7,7 @@ import java.security.SecureRandom;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,6 +45,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
private AtomicLong nanoToMilliOffset = new AtomicLong(currentUuidTime());
+ private final ReentrantLock lock = new ReentrantLock(false);
+
/**
* Returns the uuid epoch.
@@ -106,7 +109,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
logger.info("Clock skew of {} ms detected", delta / -10000);
// The clock was adjusted back about 2 seconds, or we were generating a lot of ids too fast
// if so, we try to set the current as last and also increment the clockSeq.
- synchronized (this) {
+ lock.lock();
+ try {
if (clockSeq.compareAndSet(seq, seq + 1)) {
timeStamp.set(current);
saveState();
@@ -114,6 +118,8 @@ public class UuidV1RndIdGenerator implements PlatformIdGenerator {
} else {
continue;
}
+ } finally {
+ lock.unlock();
}
}
// If current is in the future (most of the cases) try to set it.
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonExecutorService.java b/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonExecutorService.java
index c2c0a4370..48883f87f 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonExecutorService.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonExecutorService.java
@@ -6,6 +6,7 @@ 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.
@@ -16,6 +17,8 @@ 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;
@@ -49,7 +52,8 @@ public final class DaemonExecutorService {
*
*/
public void shutdown() {
- synchronized (this) {
+ lock.lock();
+ try {
if (service.isShutdown()) {
logger.debug("DaemonExecutorService[{}] already shut down", namePrefix);
return;
@@ -66,6 +70,8 @@ public final class DaemonExecutorService {
logger.error("Error during shutdown of DaemonThreadPool[" + namePrefix + "]", e);
e.printStackTrace();
}
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonScheduleThreadPool.java b/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonScheduleThreadPool.java
index e3b4e0be0..f3ee018af 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonScheduleThreadPool.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/lib/DaemonScheduleThreadPool.java
@@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Daemon based ScheduleThreadPool.
@@ -16,6 +17,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
private static final Logger logger = LoggerFactory.getLogger(DaemonScheduleThreadPool.class);
+ private final ReentrantLock lock = new ReentrantLock(false);
+
private final String namePrefix;
private final int shutdownWaitSeconds;
@@ -38,7 +41,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
*/
@Override
public void shutdown() {
- synchronized (this) {
+ lock.lock();
+ try {
if (super.isShutdown()) {
logger.debug("DaemonScheduleThreadPool {} already shut down", namePrefix);
return;
@@ -55,6 +59,8 @@ public final class DaemonScheduleThreadPool extends ScheduledThreadPoolExecutor
logger.error("Error during shutdown of " + namePrefix, e);
e.printStackTrace();
}
+ } finally {
+ lock.unlock();
}
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java
index 269890081..fc2213db5 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBaseContext.java
@@ -7,11 +7,15 @@ import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.querydefn.OrmQueryProperties;
+import java.util.concurrent.locks.ReentrantLock;
+
/**
* Base class for Bean and BeanCollection loading (lazy loading and query join loading).
*/
abstract class DLoadBaseContext {
+ protected final ReentrantLock lock = new ReentrantLock(false);
+
protected final DLoadContext parent;
protected final BeanDescriptor> desc;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java
index e2c103bbb..f33d597e8 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadBeanContext.java
@@ -17,6 +17,8 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
/**
* ToOne bean load context.
@@ -86,11 +88,11 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
@Override
public void loadSecondaryQuery(OrmQueryRequest> parentRequest, boolean forEach) {
-
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
}
- synchronized (this) {
+ lock.lock();
+ try {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
@@ -108,6 +110,8 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
}
}
}
+ } finally {
+ lock.unlock();
}
}
@@ -116,6 +120,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
*/
static class LoadBuffer implements BeanLoader, LoadBeanBuffer {
+ private final ReentrantLock bufferLock = new ReentrantLock(false);
private final DLoadBeanContext context;
private final int batchSize;
private final List list;
@@ -127,6 +132,12 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
this.list = new ArrayList<>(batchSize);
}
+ @Override
+ public Lock lock() {
+ bufferLock.lock();
+ return bufferLock;
+ }
+
@Override
public int getBatchSize() {
return batchSize;
@@ -182,7 +193,7 @@ class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContext {
@Override
public void loadBean(EntityBeanIntercept ebi) {
- // A synchronized (this) is effectively held by EntityBeanIntercept.loadBean()
+ // A lock is effectively held by EntityBeanIntercept.loadBean()
if (context.desc.lazyLoadMany(ebi, context)) {
// lazy load property was a Many
return;
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java
index d58bcdcf0..1f1685485 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/loadcontext/DLoadManyContext.java
@@ -16,6 +16,7 @@ import io.ebeaninternal.server.querydefn.OrmQueryProperties;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.locks.ReentrantLock;
/**
* ToMany bean load context.
@@ -94,11 +95,11 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
@Override
public void loadSecondaryQuery(OrmQueryRequest> parentRequest, boolean forEach) {
-
if (!queryFetch) {
throw new IllegalStateException("Not expecting loadSecondaryQuery() to be called?");
}
- synchronized (this) {
+ lock.lock();
+ try {
if (bufferList != null) {
for (LoadBuffer loadBuffer : bufferList) {
if (!loadBuffer.list.isEmpty()) {
@@ -118,6 +119,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
this.bufferList = null;
}
}
+ } finally {
+ lock.unlock();
}
}
@@ -127,6 +130,7 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
*/
static class LoadBuffer implements BeanCollectionLoader, LoadManyBuffer {
+ private final ReentrantLock lock = new ReentrantLock(false);
private final PersistenceContext persistenceContext;
private final DLoadManyContext context;
private final int batchSize;
@@ -208,7 +212,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
@Override
public void loadMany(BeanCollection> bc, boolean onlyIds) {
- synchronized (this) {
+ lock.lock();
+ try {
boolean useCache = !onlyIds && context.hitCache && context.property.isUseCache();
if (useCache) {
EntityBean ownerBean = bc.getOwnerBean();
@@ -231,6 +236,8 @@ class DLoadManyContext extends DLoadBaseContext implements LoadManyContext {
LoadManyRequest req = new LoadManyRequest(this, onlyIds, useCache);
context.parent.getEbeanServer().loadMany(req);
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java
index 379ca4396..3aeac57f5 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQuery.java
@@ -39,6 +39,7 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
/**
* An object that represents a SqlSelect statement.
@@ -58,6 +59,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
private static final CQueryCollectionAddNoop NOOP_ADD = new CQueryCollectionAddNoop();
+ private final ReentrantLock lock = new ReentrantLock(false);
+
/**
* The resultSet rows read.
*/
@@ -288,7 +291,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
@Override
public void cancel() {
- synchronized (this) {
+ lock.lock();
+ try {
this.cancelled = true;
if (pstmt != null) {
try {
@@ -298,6 +302,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
throw new PersistenceException(msg, e);
}
}
+ } finally {
+ lock.unlock();
}
}
@@ -326,8 +332,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
}
ResultSet prepareResultSet(boolean forwardOnlyHint) throws SQLException {
-
- synchronized (this) {
+ lock.lock();
+ try {
if (cancelled || query.isCancelled()) {
// cancelled before we started
cancelled = true;
@@ -370,6 +376,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
// executeQuery
return pstmt.executeQuery();
+ } finally {
+ lock.unlock();
}
}
@@ -524,8 +532,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
}
boolean hasNext() throws SQLException {
-
- synchronized (this) {
+ lock.lock();
+ try {
if (noMoreRows || cancelled) {
return false;
}
@@ -534,6 +542,8 @@ public class CQuery implements DbReadContext, CancelableQuery, SpiProfileTran
}
hasNextCache = readNextBean();
return hasNextCache;
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java
index 30e319ad8..c4e7ab5bc 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/CQueryBindCapture.java
@@ -5,10 +5,13 @@ import io.ebeaninternal.api.SpiQueryBindCapture;
import io.ebeaninternal.api.SpiQueryPlan;
import io.ebeaninternal.server.type.bindcapture.BindCapture;
+import java.util.concurrent.locks.ReentrantLock;
+
class CQueryBindCapture implements SpiQueryBindCapture {
private static final double multiplier = 1.3d;
+ private final ReentrantLock lock = new ReentrantLock(false);
private final CQueryPlanManager manager;
private final SpiQueryPlan queryPlan;
@@ -35,13 +38,16 @@ class CQueryBindCapture implements SpiQueryBindCapture {
@Override
public void setBind(BindCapture bindCapture, long queryTimeMicros, long startNanos) {
- synchronized (this) {
+ lock.lock();
+ try {
this.thresholdMicros = Math.round(queryTimeMicros * multiplier);
this.captureCount++;
this.bindCapture = bindCapture;
this.queryTimeMicros = queryTimeMicros;
lastBindCapture = System.currentTimeMillis();
manager.notifyBindCapture(this, startNanos);
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/query/LimitOffsetPagedList.java b/ebean-core/src/main/java/io/ebeaninternal/server/query/LimitOffsetPagedList.java
index b4496a56e..6aa3ac38b 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/query/LimitOffsetPagedList.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/query/LimitOffsetPagedList.java
@@ -1,31 +1,29 @@
package io.ebeaninternal.server.query;
import io.ebean.PagedList;
-import io.ebeaninternal.api.Monitor;
import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiQuery;
import javax.persistence.PersistenceException;
import java.util.List;
import java.util.concurrent.Future;
+import java.util.concurrent.locks.ReentrantLock;
/**
* PagedList implementation based on limit offset types of queries.
- *
- * @param the entity bean type
*/
public class LimitOffsetPagedList implements PagedList {
private final transient SpiEbeanServer server;
+ private final transient ReentrantLock lock = new ReentrantLock(false);
+
private final SpiQuery query;
private final int firstRow;
private final int maxRows;
- private final Monitor monitor = new Monitor();
-
private int foregroundTotalRowCount = -1;
private Future futureRowCount;
@@ -49,21 +47,27 @@ public class LimitOffsetPagedList implements PagedList {
@Override
public Future getFutureCount() {
- synchronized (monitor) {
+ lock.lock();
+ try {
if (futureRowCount == null) {
futureRowCount = server.findFutureCount(query, null);
}
return futureRowCount;
+ } finally {
+ lock.unlock();
}
}
@Override
public List getList() {
- synchronized (monitor) {
+ lock.lock();
+ try {
if (list == null) {
list = server.findList(query, null);
}
return list;
+ } finally {
+ lock.unlock();
}
}
@@ -77,7 +81,6 @@ public class LimitOffsetPagedList implements PagedList {
@Override
public int getTotalPageCount() {
-
int rowCount = getTotalCount();
if (rowCount == 0) {
return 0;
@@ -88,7 +91,8 @@ public class LimitOffsetPagedList implements PagedList {
@Override
public int getTotalCount() {
- synchronized (monitor) {
+ lock.lock();
+ try {
if (futureRowCount != null) {
try {
// background query already initiated so get it with a wait
@@ -103,6 +107,8 @@ public class LimitOffsetPagedList implements PagedList {
// just using foreground thread
foregroundTotalRowCount = server.findCount(query, null);
return foregroundTotalRowCount;
+ } finally {
+ lock.unlock();
}
}
@@ -123,11 +129,9 @@ public class LimitOffsetPagedList implements PagedList {
@Override
public String getDisplayXtoYofZ(String to, String of) {
-
int first = firstRow + 1;
int last = firstRow + getList().size();
int total = getTotalCount();
-
return first + to + last + of + total;
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
index bc82a9841..21fb58d63 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultOrmQuery.java
@@ -71,6 +71,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -88,6 +89,8 @@ public class DefaultOrmQuery implements SpiQuery {
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
+ private final ReentrantLock lock = new ReentrantLock(false);
+
private final Class beanType;
private final ExpressionFactory expressionFactory;
@@ -1992,8 +1995,11 @@ public class DefaultOrmQuery implements SpiQuery {
@Override
public void setCancelableQuery(CancelableQuery cancelableQuery) {
- synchronized (this) {
+ lock.lock();
+ try {
this.cancelableQuery = cancelableQuery;
+ } finally {
+ lock.unlock();
}
}
@@ -2026,18 +2032,24 @@ public class DefaultOrmQuery implements SpiQuery {
@Override
public void cancel() {
- synchronized (this) {
+ lock.lock();
+ try {
cancelled = true;
if (cancelableQuery != null) {
cancelableQuery.cancel();
}
+ } finally {
+ lock.unlock();
}
}
@Override
public boolean isCancelled() {
- synchronized (this) {
+ lock.lock();
+ try {
return cancelled;
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java
index bdbb22ea0..85733cd5b 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultPersistenceContext.java
@@ -1,12 +1,12 @@
package io.ebeaninternal.server.transaction;
import io.ebean.bean.PersistenceContext;
-import io.ebeaninternal.api.Monitor;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Default implementation of PersistenceContext.
@@ -32,7 +32,7 @@ public final class DefaultPersistenceContext implements PersistenceContext {
*/
private final HashMap, ClassContext> typeCache = new HashMap<>();
- private final Monitor monitor = new Monitor();
+ private final ReentrantLock lock = new ReentrantLock(false);
private int putCount;
@@ -68,7 +68,8 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
public boolean resetLimit() {
- synchronized (monitor) {
+ lock.lock();
+ try {
if (putCount < 100) {
return false;
}
@@ -80,6 +81,8 @@ public final class DefaultPersistenceContext implements PersistenceContext {
}
// checking after another 100 puts
return false;
+ } finally {
+ lock.unlock();
}
}
@@ -88,17 +91,23 @@ public final class DefaultPersistenceContext implements PersistenceContext {
*/
@Override
public void put(Class> rootType, Object id, Object bean) {
- synchronized (monitor) {
+ lock.lock();
+ try {
putCount++;
getClassContext(rootType).put(id, bean);
+ } finally {
+ lock.unlock();
}
}
@Override
public Object putIfAbsent(Class> rootType, Object id, Object bean) {
- synchronized (monitor) {
+ lock.lock();
+ try {
putCount++;
return getClassContext(rootType).putIfAbsent(id, bean);
+ } finally {
+ lock.unlock();
}
}
@@ -107,15 +116,21 @@ public final class DefaultPersistenceContext implements PersistenceContext {
*/
@Override
public Object get(Class> rootType, Object id) {
- synchronized (monitor) {
+ lock.lock();
+ try {
return getClassContext(rootType).get(id);
+ } finally {
+ lock.unlock();
}
}
@Override
public WithOption getWithOption(Class> rootType, Object id) {
- synchronized (monitor) {
+ lock.lock();
+ try {
return getClassContext(rootType).getWithOption(id);
+ } finally {
+ lock.unlock();
}
}
@@ -124,9 +139,12 @@ public final class DefaultPersistenceContext implements PersistenceContext {
*/
@Override
public int size(Class> rootType) {
- synchronized (monitor) {
+ lock.lock();
+ try {
ClassContext classMap = typeCache.get(rootType);
return classMap == null ? 0 : classMap.size();
+ } finally {
+ lock.unlock();
}
}
@@ -135,45 +153,60 @@ public final class DefaultPersistenceContext implements PersistenceContext {
*/
@Override
public void clear() {
- synchronized (monitor) {
+ lock.lock();
+ try {
typeCache.clear();
+ } finally {
+ lock.unlock();
}
}
@Override
public void clear(Class> rootType) {
- synchronized (monitor) {
+ lock.lock();
+ try {
ClassContext classMap = typeCache.get(rootType);
if (classMap != null) {
classMap.clear();
}
+ } finally {
+ lock.unlock();
}
}
@Override
public void deleted(Class> rootType, Object id) {
- synchronized (monitor) {
+ lock.lock();
+ try {
ClassContext classMap = typeCache.get(rootType);
if (classMap != null && id != null) {
classMap.deleted(id);
}
+ } finally {
+ lock.unlock();
}
}
@Override
public void clear(Class> rootType, Object id) {
- synchronized (monitor) {
+ lock.lock();
+ try {
ClassContext classMap = typeCache.get(rootType);
if (classMap != null && id != null) {
classMap.remove(id);
}
+ } finally {
+ lock.unlock();
}
}
@Override
public String toString() {
- synchronized (monitor) {
+ lock.lock();
+ try {
return typeCache.toString();
+ } finally {
+ lock.unlock();
}
}
diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java
index 12cfd436f..6d6dbb42e 100644
--- a/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java
+++ b/ebean-core/src/main/java/io/ebeaninternal/server/transaction/DefaultProfileHandler.java
@@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
import static java.time.temporal.ChronoField.DAY_OF_MONTH;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
@@ -65,6 +66,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
private final ExecutorService executor;
+ private final ReentrantLock lock = new ReentrantLock(false);
+
private final File dir;
private final long minMicros;
@@ -117,7 +120,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
}
private void flushCurrentFile() {
- synchronized (this) {
+ lock.lock();
+ try {
if (out != null) {
try {
out.close();
@@ -126,6 +130,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
log.error("Failed to flush and close transaction profiling file ", e);
}
}
+ } finally {
+ lock.unlock();
}
}
@@ -133,7 +139,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
* Move to the next file to write to.
*/
private void incrementFile() {
- synchronized (this) {
+ lock.lock();
+ try {
flushCurrentFile();
try {
String now = DTF.format(LocalDateTime.now());
@@ -142,6 +149,8 @@ public class DefaultProfileHandler implements SpiProfileHandler, Plugin {
} catch (IOException e) {
log.error("Not expected", e);
}
+ } finally {
+ lock.unlock();
}
}