mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-11-04 00:26:20 +00:00
Refactor synchronized to ReentrantLock (#2081)
This commit is contained in:
1 parent
0faa6a8efd
commit
14181932ec
30 files changed
+368
-185
No files matched your search
+6
-5
@@ -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<String, ServerCache> allCaches = new ConcurrentHashMap<>();
|
||||
|
||||
private final ConcurrentHashMap<String, Set<String>> collectIdCaches = new ConcurrentHashMap<>();
|
||||
|
||||
private final ServerCacheFactory cacheFactory;
|
||||
|
||||
private final ServerCacheOptions beanDefault;
|
||||
private final ServerCacheOptions queryDefault;
|
||||
|
||||
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));
|
||||
|
||||
@@ -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<String, EbeanServer> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<Plugin> 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);
|
||||
|
||||
@@ -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<String, String> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
* </p>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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<EntityBeanIntercept> 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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T> 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<T> 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<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
throw new PersistenceException(msg, e);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,8 +332,8 @@ public class CQuery<T> 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<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
|
||||
// executeQuery
|
||||
return pstmt.executeQuery();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -524,8 +532,8 @@ public class CQuery<T> 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<T> implements DbReadContext, CancelableQuery, SpiProfileTran
|
||||
}
|
||||
hasNextCache = readNextBean();
|
||||
return hasNextCache;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <T> the entity bean type
|
||||
*/
|
||||
public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
private final transient SpiEbeanServer server;
|
||||
|
||||
private final transient ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final SpiQuery<T> query;
|
||||
|
||||
private final int firstRow;
|
||||
|
||||
private final int maxRows;
|
||||
|
||||
private final Monitor monitor = new Monitor();
|
||||
|
||||
private int foregroundTotalRowCount = -1;
|
||||
|
||||
private Future<Integer> futureRowCount;
|
||||
@@ -49,21 +47,27 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public Future<Integer> getFutureCount() {
|
||||
synchronized (monitor) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (futureRowCount == null) {
|
||||
futureRowCount = server.findFutureCount(query, null);
|
||||
}
|
||||
return futureRowCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> 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<T> implements PagedList<T> {
|
||||
|
||||
@Override
|
||||
public int getTotalPageCount() {
|
||||
|
||||
int rowCount = getTotalCount();
|
||||
if (rowCount == 0) {
|
||||
return 0;
|
||||
@@ -88,7 +91,8 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@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<T> implements PagedList<T> {
|
||||
// just using foreground thread
|
||||
foregroundTotalRowCount = server.findCount(query, null);
|
||||
return foregroundTotalRowCount;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +129,9 @@ public class LimitOffsetPagedList<T> implements PagedList<T> {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T> implements SpiQuery<T> {
|
||||
|
||||
private static final FetchConfig FETCH_LAZY = new FetchConfig().lazy();
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock(false);
|
||||
|
||||
private final Class<T> beanType;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
@@ -1992,8 +1995,11 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@Override
|
||||
public void setCancelableQuery(CancelableQuery cancelableQuery) {
|
||||
synchronized (this) {
|
||||
lock.lock();
|
||||
try {
|
||||
this.cancelableQuery = cancelableQuery;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2026,18 +2032,24 @@ public class DefaultOrmQuery<T> implements SpiQuery<T> {
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
-13
@@ -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<Class<?>, 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-2
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user