alibaba / alibaba/druid

关闭空闲链接线程循环中第一个链接始终活跃不能触发超过设置最小空闲时间的就结束循环的问题

Open
#2,147 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
28.2k
Forks
8.6k
PR merge metrics
No merged PRs in 30d

Description

今天好好看了一下定时关闭连接的源码,发现一个地方有点### 问题:
循环的第一个链接如果始终活跃的话,就不可能触发空闲连接超过设置时间这个配置

public class DestroyTask implements Runnable {

@Override
public void run() {
shrink(true, keepAlive);这个关闭链接的线程执行这个方法

if (isRemoveAbandoned()) {
removeAbandoned();这个是关闭设置removeAbandonedTimeout的方法
}
}

}
public void shrink(boolean checkTime, boolean keepAlive) {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
return;
}

int evictCount = 0;
int keepAliveCount = 0;
try {
if (!inited) {
return;
}

final int checkCount = poolingCount - minIdle;
final long currentTimeMillis = System.currentTimeMillis();
for (int i = 0; i < poolingCount; ++i) {
DruidConnectionHolder connection = connections[i];

if (checkTime) {
if (phyTimeoutMillis > 0) {
long phyConnectTimeMillis = currentTimeMillis - connection.connectTimeMillis;
if (phyConnectTimeMillis > phyTimeoutMillis) {
evictConnections[evictCount++] = connection;
continue;
}
}

long idleMillis = currentTimeMillis - connection.lastActiveTimeMillis;

if (idleMillis < minEvictableIdleTimeMillis) {
break; 这个关闭连接的循环只要有存活连接小于超时时间就终止循环
}

if (checkTime && i < checkCount) {
evictConnections[evictCount++] = connection;
} else if (idleMillis > maxEvictableIdleTimeMillis) {
evictConnections[evictCount++] = connection;
} else if (keepAlive) {
keepAliveConnections[keepAliveCount++] = connection;
}
} else {
if (i < checkCount) {
evictConnections[evictCount++] = connection;
} else {
break;
}
}
}

int removeCount = evictCount + keepAliveCount;
if (removeCount > 0) {
System.arraycopy(connections, removeCount, connections, 0, poolingCount - removeCount);
Arrays.fill(connections, poolingCount - removeCount, poolingCount, null);
poolingCount -= removeCount;
}
keepAliveCheckCount += keepAliveCount;
} finally {
lock.unlock();
}

if (evictCount > 0) {
for (int i = 0; i < evictCount; ++i) {
DruidConnectionHolder item = evictConnections[i];
Connection connection = item.getConnection();
JdbcUtils.close(connection);
destroyCount.incrementAndGet();
}
Arrays.fill(evictConnections, null);
}

if (keepAliveCount > 0) {
this.getDataSourceStat().addKeepAliveCheckCount(keepAliveCount);
// keep order
for (int i = keepAliveCount - 1; i >= 0; --i) {
DruidConnectionHolder holer = keepAliveConnections[i];
Connection connection = holer.getConnection();
holer.incrementKeepAliveCheckCount();

boolean validate = false;
try {
this.validateConnection(connection);
validate = true;
} catch (Throwable error) {
if (LOG.isDebugEnabled()) {
LOG.debug("keepAliveErr", error);
}
// skip
}

if (validate) {
holer.setLastActiveTimeMillis(System.currentTimeMillis());
put(holer);
} else {
JdbcUtils.close(connection);
}
}
Arrays.fill(keepAliveConnections, null);
}
}

Contributor guide

Open the contributing guide

Research direction

Start with DestroyTask.run and the shrink(boolean checkTime, boolean keepAlive) path shown in the issue, then trace the ordering of connections and the minIdle, minEvictableIdleTimeMillis, and maxEvictableIdleTimeMillis checks. Reproduce a pool where the first connection remains active while later connections exceed the idle threshold; done means the configured idle connections are evaluated correctly and regression coverage verifies the behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
databases
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.