Skip to content

Commit

Permalink
add idleTimeoutDecay param to QTP
Browse files Browse the repository at this point in the history
  • Loading branch information
magibney committed Feb 14, 2023
1 parent beee5ff commit dfab46b
Showing 1 changed file with 62 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ public class QueuedThreadPool extends ContainerLifeCycle implements ThreadFactor
private final ThreadFactory _threadFactory;
private String _name = "qtp" + hashCode();
private int _idleTimeout;
private int _idleTimeoutDecay = 1;
private long _shrinkInterval = -1;
private int _maxThreads;
private int _minThreads;
private int _reservedThreads = -1;
Expand Down Expand Up @@ -364,11 +366,53 @@ public int getIdleTimeout()
public void setIdleTimeout(int idleTimeout)
{
_idleTimeout = idleTimeout;
if (_idleTimeoutDecay > 1) {
// if non-default idleTimeoutDecay is configured, we must recompute _shrinkInterval
_shrinkInterval = computeShrinkIntervalNanos(idleTimeout, _idleTimeoutDecay);
}
ReservedThreadExecutor reserved = getBean(ReservedThreadExecutor.class);
if (reserved != null)
reserved.setIdleTimeout(idleTimeout, TimeUnit.MILLISECONDS);
}

/**
* @return the number of idle threads that are allowed to expire
* per idleTimeout interval.
*/
@ManagedAttribute("number of idle threads allowed to die per idleTimeout interval")
public float getIdleTimeoutDecay()

This comment has been minimized.

Copy link
@gregw

gregw Feb 14, 2023

why is this a float when the setter is an int?

This comment has been minimized.

Copy link
@magibney

magibney Feb 15, 2023

Author Owner

an oversight from a previous iteration of the design!

{
return _idleTimeoutDecay;
}

/**
* <p>Set the number of idle threads that will be allowed to expire per idleTimeout
* interval</p>
*
* @param expireCount the number of idle threads that may be allowed to die for
* every idleTimeout interval.
*/
public void setIdleTimeoutDecay(int expireCount)
{
if (expireCount < 1) {
throw new IllegalArgumentException("idleTimeoutDecay expireCount must be >= 1; found: " + expireCount);
}
_idleTimeoutDecay = expireCount;
_shrinkInterval = computeShrinkIntervalNanos(_idleTimeout, expireCount);
// TODO: do we need to pass idleTimeoutDecay along to reserved pool?
// ReservedThreadExecutor reserved = getBean(ReservedThreadExecutor.class);
// if (reserved != null)
// reserved.setIdleTimeoutDecay(expireCount);
}

private long getShrinkInterval() {
return _shrinkInterval < 0 ? TimeUnit.MILLISECONDS.toNanos(_idleTimeout) : _shrinkInterval;
}

static long computeShrinkIntervalNanos(int idleTimeout, int idleTimeoutDecay) {
return TimeUnit.MILLISECONDS.toNanos(idleTimeout) / idleTimeoutDecay;
}

/**
* @return the maximum number of threads
*/
Expand Down Expand Up @@ -1006,6 +1050,16 @@ public String toString()
_tryExecutor);
}

private boolean doShrink(long last, final long now, final long itNanos, final long siNanos) {
final long baseline = now - itNanos;
boolean ret;
while (!(ret = _lastShrink.compareAndSet(last, Math.max(last, baseline) + siNanos)) &&
(now - (last = _lastShrink.get())) > siNanos) {
// keep trying to update.
}
return ret;
}

private class Runner implements Runnable
{
private Runnable idleJobPoll(long idleTimeout) throws InterruptedException
Expand All @@ -1025,6 +1079,7 @@ public void run()
try
{
Runnable job = null;
long idleBaseline = NanoTime.now();
while (true)
{
// If we had a job,
Expand All @@ -1051,9 +1106,13 @@ else if (_counts.getHi() == Integer.MIN_VALUE)
long idleTimeout = getIdleTimeout();
if (idleTimeout > 0 && getThreads() > _minThreads)
{
long last = _lastShrink.get();
long last;
long now = NanoTime.now();
if (NanoTime.millisElapsed(last, now) > idleTimeout && _lastShrink.compareAndSet(last, now))
long itNanos = TimeUnit.MILLISECONDS.toNanos(idleTimeout);

This comment has been minimized.

Copy link
@gregw

gregw Feb 15, 2023

why isn't this just:

    long last = _lastShrink.get();
    long now = NanoTime.now();
    if (NanoTime.nanosElapsed(last, now) > getShrinkInterval() && _lastShrink.compareAndSet(last, now))
long siNanos;
if (now - idleBaseline > itNanos &&
(now - (last = _lastShrink.get())) > (siNanos = getShrinkInterval()) &&
doShrink(last, now, itNanos, siNanos))
{
if (LOG.isDebugEnabled())
LOG.debug("shrinking {}", QueuedThreadPool.this);
Expand All @@ -1076,6 +1135,7 @@ else if (_counts.getHi() == Integer.MIN_VALUE)
if (LOG.isDebugEnabled())
LOG.debug("run {} in {}", job, QueuedThreadPool.this);
runJob(job);
idleBaseline = NanoTime.now();
if (LOG.isDebugEnabled())
LOG.debug("ran {} in {}", job, QueuedThreadPool.this);
}
Expand Down

0 comments on commit dfab46b

Please sign in to comment.