mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
DruidDataSource onFatalErrorMaxActive support.
This commit is contained in:
@@ -255,6 +255,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
|
||||
protected boolean initVariants = false;
|
||||
protected boolean initGlobalVariants = false;
|
||||
protected volatile boolean onFatalError = false;
|
||||
protected volatile int onFatalErrorMaxActive = 0;
|
||||
|
||||
public DruidAbstractDataSource(boolean lockFair){
|
||||
lock = new ReentrantLock(lockFair);
|
||||
@@ -1955,6 +1957,18 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
|
||||
this.failFast = failFast;
|
||||
}
|
||||
|
||||
public int getOnFatalErrorMaxActive() {
|
||||
return onFatalErrorMaxActive;
|
||||
}
|
||||
|
||||
public void setOnFatalErrorMaxActive(int onFatalErrorMaxActive) {
|
||||
this.onFatalErrorMaxActive = onFatalErrorMaxActive;
|
||||
}
|
||||
|
||||
public boolean isOnFatalError() {
|
||||
return onFatalError;
|
||||
}
|
||||
|
||||
public static class PhysicalConnectionInfo {
|
||||
private Connection connection;
|
||||
private long connectStartNanos;
|
||||
|
||||
@@ -90,36 +90,30 @@ import com.alibaba.druid.wall.WallProviderStatValue;
|
||||
*/
|
||||
public class DruidDataSource extends DruidAbstractDataSource implements DruidDataSourceMBean, ManagedDataSource, Referenceable, Closeable, Cloneable, ConnectionPoolDataSource, MBeanRegistration {
|
||||
|
||||
private final static Log LOG = LogFactory.getLog(DruidDataSource.class);
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final static Log LOG = LogFactory.getLog(DruidDataSource.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
// stats
|
||||
private final AtomicLong recycleErrorCount = new AtomicLong();
|
||||
private long connectCount = 0L;
|
||||
private long closeCount = 0L;
|
||||
private final AtomicLong connectErrorCount = new AtomicLong();
|
||||
private long recycleCount = 0L;
|
||||
private long removeAbandonedCount = 0L;
|
||||
private long notEmptyWaitCount = 0L;
|
||||
private long notEmptySignalCount = 0L;
|
||||
private long notEmptyWaitNanos = 0L;
|
||||
|
||||
private int keepAliveCheckCount = 0;
|
||||
|
||||
private int activePeak = 0;
|
||||
private long activePeakTime = 0;
|
||||
private int poolingPeak = 0;
|
||||
private long poolingPeakTime = 0;
|
||||
|
||||
private final AtomicLong recycleErrorCount = new AtomicLong();
|
||||
private long connectCount = 0L;
|
||||
private long closeCount = 0L;
|
||||
private final AtomicLong connectErrorCount = new AtomicLong();
|
||||
private long recycleCount = 0L;
|
||||
private long removeAbandonedCount = 0L;
|
||||
private long notEmptyWaitCount = 0L;
|
||||
private long notEmptySignalCount = 0L;
|
||||
private long notEmptyWaitNanos = 0L;
|
||||
private int keepAliveCheckCount = 0;
|
||||
private int activePeak = 0;
|
||||
private long activePeakTime = 0;
|
||||
private int poolingPeak = 0;
|
||||
private long poolingPeakTime = 0;
|
||||
// store
|
||||
private volatile DruidConnectionHolder[] connections;
|
||||
private int poolingCount = 0;
|
||||
private int activeCount = 0;
|
||||
private long discardCount = 0;
|
||||
private int notEmptyWaitThreadCount = 0;
|
||||
private int notEmptyWaitThreadPeak = 0;
|
||||
|
||||
private int poolingCount = 0;
|
||||
private int activeCount = 0;
|
||||
private long discardCount = 0;
|
||||
private int notEmptyWaitThreadCount = 0;
|
||||
private int notEmptyWaitThreadPeak = 0;
|
||||
//
|
||||
private DruidConnectionHolder[] evictConnections;
|
||||
private DruidConnectionHolder[] keepAliveConnections;
|
||||
@@ -135,30 +129,27 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
private LogStatsThread logStatsThread;
|
||||
private int createTaskCount;
|
||||
|
||||
private final CountDownLatch initedLatch = new CountDownLatch(2);
|
||||
private final CountDownLatch initedLatch = new CountDownLatch(2);
|
||||
|
||||
private volatile boolean enable = true;
|
||||
private volatile boolean enable = true;
|
||||
|
||||
private boolean resetStatEnable = true;
|
||||
private final AtomicLong resetCount = new AtomicLong();
|
||||
private boolean resetStatEnable = true;
|
||||
private final AtomicLong resetCount = new AtomicLong();
|
||||
|
||||
private String initStackTrace;
|
||||
|
||||
private volatile boolean closing = false;
|
||||
private volatile boolean closed = false;
|
||||
private long closeTimeMillis = -1L;
|
||||
private volatile boolean closing = false;
|
||||
private volatile boolean closed = false;
|
||||
private long closeTimeMillis = -1L;
|
||||
|
||||
protected JdbcDataSourceStat dataSourceStat;
|
||||
|
||||
private boolean useGlobalDataSourceStat = false;
|
||||
|
||||
private boolean mbeanRegistered = false;
|
||||
|
||||
public static ThreadLocal<Long> waitNanosLocal = new ThreadLocal<Long>();
|
||||
private boolean logDifferentThread = true;
|
||||
private volatile boolean keepAlive = false;
|
||||
private boolean asyncInit = false;
|
||||
|
||||
private boolean useGlobalDataSourceStat = false;
|
||||
private boolean mbeanRegistered = false;
|
||||
public static ThreadLocal<Long> waitNanosLocal = new ThreadLocal<Long>();
|
||||
private boolean logDifferentThread = true;
|
||||
private volatile boolean keepAlive = false;
|
||||
private boolean asyncInit = false;
|
||||
protected boolean killWhenSocketReadTimeout = false;
|
||||
|
||||
public DruidDataSource(){
|
||||
@@ -1371,12 +1362,19 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
}
|
||||
|
||||
try {
|
||||
if (maxWaitThreadCount > 0) {
|
||||
if (notEmptyWaitThreadCount >= maxWaitThreadCount) {
|
||||
if (maxWaitThreadCount > 0
|
||||
&& notEmptyWaitThreadCount >= maxWaitThreadCount)
|
||||
{
|
||||
connectErrorCount.incrementAndGet();
|
||||
throw new SQLException("maxWaitThreadCount " + maxWaitThreadCount + ", current wait Thread count "
|
||||
+ lock.getQueueLength());
|
||||
}
|
||||
}
|
||||
|
||||
if (onFatalError
|
||||
&& onFatalErrorMaxActive > 0
|
||||
&& activeCount >= onFatalErrorMaxActive) {
|
||||
connectErrorCount.incrementAndGet();
|
||||
throw new SQLException("onFatalError, activeCount " + activeCount + ", onFatalErrorMaxActive " + onFatalErrorMaxActive);
|
||||
}
|
||||
|
||||
connectCount++;
|
||||
@@ -1482,6 +1480,8 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
|
||||
pooledConnection.disable(t);
|
||||
requireDiscard = true;
|
||||
}
|
||||
|
||||
onFatalError = true;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
|
||||
protected TransactionInfo transactionInfo;
|
||||
private final boolean dupCloseLogEnable;
|
||||
protected volatile boolean traceEnable = false;
|
||||
private boolean disable = false;
|
||||
private volatile boolean disable = false;
|
||||
private boolean closed = false;
|
||||
protected final Thread ownerThread;
|
||||
private long connectedTimeMillis;
|
||||
@@ -1208,9 +1208,13 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
|
||||
|
||||
final void afterExecute() {
|
||||
final DruidConnectionHolder holder = this.holder;
|
||||
if (holder != null && holder.dataSource.removeAbandoned) {
|
||||
running = false;
|
||||
holder.lastActiveTimeMillis = System.currentTimeMillis();
|
||||
if (holder != null) {
|
||||
DruidAbstractDataSource dataSource = holder.dataSource;
|
||||
if (dataSource.removeAbandoned) {
|
||||
running = false;
|
||||
holder.lastActiveTimeMillis = System.currentTimeMillis();
|
||||
}
|
||||
dataSource.onFatalError = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.alibaba.druid.bvt.pool;
|
||||
|
||||
import com.alibaba.druid.PoolTestCase;
|
||||
import com.alibaba.druid.pool.DruidAbstractDataSource;
|
||||
import com.alibaba.druid.pool.DruidDataSource;
|
||||
import com.alibaba.druid.util.JdbcUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
public class OnFatalErrorMaxActiveTest extends PoolTestCase {
|
||||
protected DruidDataSource dataSource;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
dataSource = new DruidDataSource();
|
||||
dataSource.setUrl("jdbc:mock:");
|
||||
dataSource.setOnFatalErrorMaxActive(1);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
JdbcUtils.close(dataSource);
|
||||
}
|
||||
|
||||
public void test_for_fatalError() throws Exception {
|
||||
Field field = DruidAbstractDataSource.class.getDeclaredField("onFatalError");
|
||||
field.setAccessible(true);
|
||||
|
||||
{
|
||||
Connection conn = dataSource.getConnection();
|
||||
conn.close();
|
||||
}
|
||||
|
||||
field.set(dataSource, true);
|
||||
|
||||
|
||||
Connection conn_0 = dataSource.getConnection();
|
||||
assertTrue(dataSource.isOnFatalError());
|
||||
|
||||
SQLException error = null;
|
||||
try {
|
||||
Connection conn_1 = dataSource.getConnection();
|
||||
} catch (SQLException ex) {
|
||||
error = ex;
|
||||
}
|
||||
assertNotNull(error);
|
||||
assertEquals("onFatalError, activeCount 1, onFatalErrorMaxActive 1", error.getMessage());
|
||||
|
||||
Statement stmt = conn_0.createStatement();
|
||||
ResultSet rs = stmt.executeQuery("select 1");
|
||||
assertFalse(dataSource.isOnFatalError());
|
||||
rs.close();
|
||||
stmt.close();
|
||||
conn_0.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user