handle OutOfMemoryError, use field replace getter&setter.

This commit is contained in:
wenshao
2017-10-20 11:20:36 +08:00
parent 8793542fcd
commit 3751b29df1
4 changed files with 133 additions and 93 deletions
@@ -124,9 +124,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
protected volatile String validationQuery = DEFAULT_VALIDATION_QUERY;
protected volatile int validationQueryTimeout = -1;
private volatile boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
private volatile boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
private volatile boolean testWhileIdle = DEFAULT_WHILE_IDLE;
protected volatile boolean testOnBorrow = DEFAULT_TEST_ON_BORROW;
protected volatile boolean testOnReturn = DEFAULT_TEST_ON_RETURN;
protected volatile boolean testWhileIdle = DEFAULT_WHILE_IDLE;
protected volatile boolean poolPreparedStatements = false;
protected volatile boolean sharePreparedStatements = false;
protected volatile int maxPoolPreparedStatementPerConnectionSize = 10;
@@ -1444,7 +1444,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
}
void initStatement(DruidPooledConnection conn, Statement stmt) throws SQLException {
boolean transaction = !conn.getConnectionHolder().isUnderlyingAutoCommit();
boolean transaction = !conn.getConnectionHolder().underlyingAutoCommit;
int queryTimeout = transaction ? getTransactionQueryTimeout() : getQueryTimeout();
@@ -1600,9 +1600,9 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements
conn.setAutoCommit(defaultAutoCommit);
}
if (getDefaultReadOnly() != null) {
if (conn.isReadOnly() != getDefaultReadOnly()) {
conn.setReadOnly(getDefaultReadOnly());
if (defaultReadOnly != null) {
if (conn.isReadOnly() != defaultReadOnly) {
conn.setReadOnly(defaultReadOnly);
}
}
@@ -41,43 +41,33 @@ import com.alibaba.druid.util.Utils;
* @author wenshao [szujobs@hotmail.com]
*/
public final class DruidConnectionHolder {
private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class);
private final static Log LOG = LogFactory.getLog(DruidConnectionHolder.class);
public static boolean holdabilityUnsupported = false;
protected final DruidAbstractDataSource dataSource;
private final long connectionId;
private final Connection conn;
private final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
private final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
protected final long connectTimeMillis;
protected volatile long lastActiveTimeMillis;
private long useCount = 0;
private long keepAliveCheckCount = 0;
private long lastNotEmptyWaitNanos;
private final long createNanoSpan;
private PreparedStatementPool statementPool;
protected final List<Statement> statementTrace = new ArrayList<Statement>(2);
private final boolean defaultReadOnly;
private final int defaultHoldability;
private final int defaultTransactionIsolation;
private final boolean defaultAutoCommit;
private boolean underlyingReadOnly;
private int underlyingHoldability;
private int underlyingTransactionIsolation;
private boolean underlyingAutoCommit;
private boolean discard = false;
protected final Map<String, Object> variables;
protected final Map<String, Object> globleVariables;
public static boolean holdabilityUnsupported = false;
protected final long connectionId;
protected final Connection conn;
protected final List<ConnectionEventListener> connectionEventListeners = new CopyOnWriteArrayList<ConnectionEventListener>();
protected final List<StatementEventListener> statementEventListeners = new CopyOnWriteArrayList<StatementEventListener>();
protected final long connectTimeMillis;
protected volatile long lastActiveTimeMillis;
private long useCount = 0;
private long keepAliveCheckCount = 0;
private long lastNotEmptyWaitNanos;
private final long createNanoSpan;
protected PreparedStatementPool statementPool;
protected final List<Statement> statementTrace = new ArrayList<Statement>(2);
protected final boolean defaultReadOnly;
protected final int defaultHoldability;
protected final int defaultTransactionIsolation;
protected final boolean defaultAutoCommit;
protected boolean underlyingReadOnly;
protected int underlyingHoldability;
protected int underlyingTransactionIsolation;
protected boolean underlyingAutoCommit;
protected boolean discard = false;
protected final Map<String, Object> variables;
protected final Map<String, Object> globleVariables;
public DruidConnectionHolder(DruidAbstractDataSource dataSource, PhysicalConnectionInfo pyConnectInfo)
throws SQLException{
@@ -250,6 +250,12 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
this.setUseGlobalDataSourceStat(value);
}
}
{
Boolean value = getBoolean(properties, "druid.asyncInit"); // compatible for early versions
if (value != null) {
this.setAsyncInit(value);
}
}
{
String property = properties.getProperty("druid.filters");
@@ -308,6 +314,17 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
}
{
String property = properties.getProperty("druid.timeBetweenEvictionRunsMillis");
if (property != null && property.length() > 0) {
try {
long value = Long.parseLong(property);
this.setTimeBetweenEvictionRunsMillis(value);
} catch (NumberFormatException e) {
LOG.error("illegal property 'druid.timeBetweenEvictionRunsMillis'", e);
}
}
}
{
String property = properties.getProperty("druid.maxWaitThreadCount");
if (property != null && property.length() > 0) {
@@ -1232,35 +1249,35 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
throw ex;
}
if (isTestOnBorrow()) {
boolean validate = testConnectionInternal(poolableConnection.getConnection());
if (testOnBorrow) {
boolean validate = testConnectionInternal(poolableConnection.conn);
if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
}
Connection realConnection = poolableConnection.getConnection();
Connection realConnection = poolableConnection.conn;
discardConnection(realConnection);
continue;
}
} else {
Connection realConnection = poolableConnection.getConnection();
if (realConnection.isClosed()) {
Connection realConnection = poolableConnection.conn;
if (poolableConnection.conn.isClosed()) {
discardConnection(null); // 传入null,避免重复关闭
continue;
}
if (isTestWhileIdle()) {
if (testWhileIdle) {
final long currentTimeMillis = System.currentTimeMillis();
final long lastActiveTimeMillis = poolableConnection.getConnectionHolder().getLastActiveTimeMillis();
final long lastActiveTimeMillis = poolableConnection.holder.lastActiveTimeMillis;
final long idleMillis = currentTimeMillis - lastActiveTimeMillis;
long timeBetweenEvictionRunsMillis = this.getTimeBetweenEvictionRunsMillis();
long timeBetweenEvictionRunsMillis = this.timeBetweenEvictionRunsMillis;
if (timeBetweenEvictionRunsMillis <= 0) {
timeBetweenEvictionRunsMillis = DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
}
if (idleMillis >= timeBetweenEvictionRunsMillis) {
boolean validate = testConnectionInternal(poolableConnection.getConnection());
boolean validate = testConnectionInternal(poolableConnection.conn);
if (!validate) {
if (LOG.isDebugEnabled()) {
LOG.debug("skip not validate connection.");
@@ -1273,11 +1290,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
if (isRemoveAbandoned()) {
if (removeAbandoned) {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
poolableConnection.setConnectStackTrace(stackTrace);
poolableConnection.connectStackTrace = stackTrace;
poolableConnection.setConnectedTimeNano();
poolableConnection.setTraceEnable(true);
poolableConnection.traceEnable = true;
activeConnectionLock.lock();
try {
@@ -1287,7 +1304,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
if (!this.isDefaultAutoCommit()) {
if (!this.defaultAutoCommit) {
poolableConnection.setAutoCommit(false);
}
@@ -1328,7 +1345,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
final long nanos = TimeUnit.MILLISECONDS.toNanos(maxWait);
final int maxWaitThreadCount = getMaxWaitThreadCount();
final int maxWaitThreadCount = this.maxWaitThreadCount;
DruidConnectionHolder holder;
try {
@@ -1478,7 +1495,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
* 回收连接
*/
protected void recycle(DruidPooledConnection pooledConnection) throws SQLException {
final DruidConnectionHolder holder = pooledConnection.getConnectionHolder();
final DruidConnectionHolder holder = pooledConnection.holder;
if (holder == null) {
LOG.warn("connectionHolder is null");
@@ -1487,20 +1504,20 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
if (logDifferentThread //
&& (!isAsyncCloseConnectionEnable()) //
&& pooledConnection.getOwnerThread() != Thread.currentThread()//
&& pooledConnection.ownerThread != Thread.currentThread()//
) {
LOG.warn("get/close not same thread");
}
final Connection physicalConnection = holder.getConnection();
final Connection physicalConnection = holder.conn;
if (pooledConnection.isTraceEnable()) {
if (pooledConnection.traceEnable) {
Object oldInfo = null;
activeConnectionLock.lock();
try {
if (pooledConnection.isTraceEnable()) {
if (pooledConnection.traceEnable) {
oldInfo = activeConnections.remove(pooledConnection);
pooledConnection.setTraceEnable(false);
pooledConnection.traceEnable = false;
}
} finally {
activeConnectionLock.unlock();
@@ -1512,9 +1529,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
final boolean isAutoCommit = holder.isUnderlyingAutoCommit();
final boolean isReadOnly = holder.isUnderlyingReadOnly();
final boolean testOnReturn = this.isTestOnReturn();
final boolean isAutoCommit = holder.underlyingAutoCommit;
final boolean isReadOnly = holder.underlyingReadOnly;
final boolean testOnReturn = this.testOnReturn;
try {
// check need to rollback?
@@ -1523,7 +1540,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
// reset holder, restore default settings, clear warnings
boolean isSameThread = pooledConnection.getOwnerThread() == Thread.currentThread();
boolean isSameThread = pooledConnection.ownerThread == Thread.currentThread();
if (!isSameThread) {
final ReentrantLock lock = pooledConnection.lock;
lock.lock();
@@ -1536,7 +1553,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
holder.reset();
}
if (holder.isDiscard()) {
if (holder.discard) {
return;
}
@@ -1559,7 +1576,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
if (!enable) {
discardConnection(holder.getConnection());
discardConnection(holder.conn);
return;
}
@@ -1585,15 +1602,15 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
if (!result) {
JdbcUtils.close(holder.getConnection());
JdbcUtils.close(holder.conn);
LOG.info("connection recyle failed.");
}
} catch (Throwable e) {
holder.clearStatementCache();
if (!holder.isDiscard()) {
if (!holder.discard) {
this.discardConnection(physicalConnection);
holder.setDiscard(true);
holder.discard = true;
}
LOG.error("recyle error", e);
@@ -1610,7 +1627,10 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
try {
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder conn = connections[i];
conn.getStatementPool().clear();
if (conn.statementPool != null) {
conn.statementPool.clear();
}
}
} finally {
lock.unlock();
@@ -1731,7 +1751,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
return false;
}
e.setLastActiveTimeMillis(lastActiveTimeMillis);
e.lastActiveTimeMillis = lastActiveTimeMillis;
connections[poolingCount] = e;
incrementPoolingCount();
@@ -2148,9 +2168,38 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
try {
physicalConnection = createPhysicalConnection();
setFailContinuous(false);
} catch (OutOfMemoryError e) {
LOG.error("create connection OutOfMemoryError, out memory. ", e);
errorCount++;
if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
// fail over retry attempts
setFailContinuous(true);
if (failFast) {
lock.lock();
try {
notEmpty.signalAll();
} finally {
lock.unlock();
}
}
if (breakAfterAcquireFailure) {
lock.lock();
try {
createTaskCount--;
} finally {
lock.unlock();
}
return;
}
this.errorCount = 0; // reset errorCount
createSchedulerFuture = createScheduler.schedule(this, timeBetweenConnectErrorMillis, TimeUnit.MILLISECONDS);
return;
}
} catch (SQLException e) {
LOG.error("create connection error, url: " + jdbcUrl, e);
System.out.println();
LOG.error("create connection SQLException, url: " + jdbcUrl, e);
errorCount++;
if (errorCount > connectionErrorRetryAttempts && timeBetweenConnectErrorMillis > 0) {
@@ -2180,7 +2229,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
return;
}
} catch (RuntimeException e) {
LOG.error("create connection error", e);
LOG.error("create connection RuntimeException", e);
// unknow fatal exception
setFailContinuous(true);
continue;
@@ -2191,7 +2240,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
} finally {
lock.unlock();
}
LOG.error("create connection error", e);
LOG.error("create connection Error", e);
// unknow fatal exception
setFailContinuous(true);
break;
@@ -2266,6 +2315,9 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
} catch (InterruptedException e) {
lastCreateError = e;
lastErrorTimeMillis = System.currentTimeMillis();
LOG.error("create connection Thread Interrupted, url: " + jdbcUrl, e);
break;
} finally {
lock.unlock();
@@ -2277,7 +2329,7 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
connection = createPhysicalConnection();
setFailContinuous(false);
} catch (SQLException e) {
LOG.error("create connection error, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
LOG.error("create connection SQLException, url: " + jdbcUrl + ", errorCode " + e.getErrorCode()
+ ", state " + e.getSQLState(), e);
errorCount++;
@@ -2304,11 +2356,11 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
}
}
} catch (RuntimeException e) {
LOG.error("create connection error", e);
LOG.error("create connection RuntimeException", e);
setFailContinuous(true);
continue;
} catch (Error e) {
LOG.error("create connection error", e);
LOG.error("create connection Error", e);
setFailContinuous(true);
break;
}
@@ -2809,13 +2861,13 @@ public class DruidDataSource extends DruidAbstractDataSource implements DruidDat
map.put("id", System.identityHashCode(conn));
map.put("connectionId", connHolder.getConnectionId());
map.put("useCount", connHolder.getUseCount());
if (connHolder.getLastActiveTimeMillis() > 0) {
map.put("lastActiveTime", new Date(connHolder.getLastActiveTimeMillis()));
if (connHolder.lastActiveTimeMillis > 0) {
map.put("lastActiveTime", new Date(connHolder.lastActiveTimeMillis));
}
map.put("connectTime", new Date(connHolder.getTimeMillis()));
map.put("holdability", connHolder.getUnderlyingHoldability());
map.put("transactionIsolation", connHolder.getUnderlyingTransactionIsolation());
map.put("autoCommit", connHolder.isUnderlyingAutoCommit());
map.put("autoCommit", connHolder.underlyingAutoCommit);
map.put("readoOnly", connHolder.isUnderlyingReadOnly());
if (connHolder.isPoolPreparedStatements()) {
@@ -63,19 +63,17 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
protected volatile DruidConnectionHolder holder;
protected TransactionInfo transactionInfo;
private final boolean dupCloseLogEnable;
private volatile boolean traceEnable = false;
protected volatile boolean traceEnable = false;
private boolean disable = false;
private boolean closed = false;
private final Thread ownerThread;
protected final Thread ownerThread;
private long connectedTimeMillis;
private long connectedTimeNano;
private volatile boolean running = false;
private volatile boolean abandoned = false;
private StackTraceElement[] connectStackTrace;
private Throwable disableError = null;
protected StackTraceElement[] connectStackTrace;
protected Throwable disableError = null;
public ReentrantLock lock = new ReentrantLock();
@@ -205,7 +203,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
@Override
public Connection getConnection() {
if (!holder.isUnderlyingAutoCommit()) {
if (!holder.underlyingAutoCommit) {
createTransactionInfo();
}
@@ -706,7 +704,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState();
if (useLocalSessionState) {
if (autoCommit == holder.isUnderlyingAutoCommit()) {
if (autoCommit == holder.underlyingAutoCommit) {
return;
}
}
@@ -871,7 +869,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
public DatabaseMetaData getMetaData() throws SQLException {
checkState();
if (!holder.isUnderlyingAutoCommit()) {
if (!holder.underlyingAutoCommit) {
createTransactionInfo();
}
@@ -999,7 +997,7 @@ public class DruidPooledConnection extends PoolableWrapper implements javax.sql.
public int getHoldability() throws SQLException {
checkState();
if (!holder.isUnderlyingAutoCommit()) {
if (!holder.underlyingAutoCommit) {
createTransactionInfo();
}