Jetty 9.4.x 1803 proposal 0 - single ReservedThreadExecutor (#2119)
Issue #1803 - Review usage of scheduling strategies Use a single ReservedThreadExecutor built into the QueuedThreadPool via new interface TryExecutor. Signed-off-by: Greg Wilkins <gregw@webtide.com> Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
9a787b1e54
commit
ab5fc29cca
|
@ -39,7 +39,6 @@ import org.eclipse.jetty.io.EndPoint;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.Promise;
|
import org.eclipse.jetty.util.Promise;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
|
|
||||||
public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
|
@ -69,36 +68,19 @@ public class HTTP2ClientConnectionFactory implements ClientConnectionFactory
|
||||||
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
|
HTTP2ClientSession session = new HTTP2ClientSession(scheduler, endPoint, generator, listener, flowControl);
|
||||||
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
|
Parser parser = new Parser(byteBufferPool, session, 4096, 8192);
|
||||||
|
|
||||||
ReservedThreadExecutor reservedExecutor = provideReservedThreadExecutor(client, executor);
|
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, executor, endPoint,
|
||||||
|
|
||||||
HTTP2ClientConnection connection = new HTTP2ClientConnection(client, byteBufferPool, reservedExecutor, endPoint,
|
|
||||||
parser, session, client.getInputBufferSize(), promise, listener);
|
parser, session, client.getInputBufferSize(), promise, listener);
|
||||||
connection.addListener(connectionListener);
|
connection.addListener(connectionListener);
|
||||||
return customize(connection, context);
|
return customize(connection, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ReservedThreadExecutor provideReservedThreadExecutor(HTTP2Client client, Executor executor)
|
|
||||||
{
|
|
||||||
synchronized (this)
|
|
||||||
{
|
|
||||||
ReservedThreadExecutor reservedExecutor = client.getBean(ReservedThreadExecutor.class);
|
|
||||||
if (reservedExecutor == null)
|
|
||||||
{
|
|
||||||
// TODO: see HTTP2Connection.FillableCallback
|
|
||||||
reservedExecutor = new ReservedThreadExecutor(executor, 0);
|
|
||||||
client.addManaged(reservedExecutor);
|
|
||||||
}
|
|
||||||
return reservedExecutor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class HTTP2ClientConnection extends HTTP2Connection implements Callback
|
private class HTTP2ClientConnection extends HTTP2Connection implements Callback
|
||||||
{
|
{
|
||||||
private final HTTP2Client client;
|
private final HTTP2Client client;
|
||||||
private final Promise<Session> promise;
|
private final Promise<Session> promise;
|
||||||
private final Session.Listener listener;
|
private final Session.Listener listener;
|
||||||
|
|
||||||
private HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, ReservedThreadExecutor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener)
|
private HTTP2ClientConnection(HTTP2Client client, ByteBufferPool byteBufferPool, Executor executor, EndPoint endpoint, Parser parser, ISession session, int bufferSize, Promise<Session> promise, Session.Listener listener)
|
||||||
{
|
{
|
||||||
super(byteBufferPool, executor, endpoint, parser, session, bufferSize);
|
super(byteBufferPool, executor, endpoint, parser, session, bufferSize);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.eclipse.jetty.http2.parser.Parser;
|
import org.eclipse.jetty.http2.parser.Parser;
|
||||||
|
@ -35,7 +36,7 @@ import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
import org.eclipse.jetty.util.thread.TryExecutor;
|
||||||
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
||||||
|
|
||||||
public class HTTP2Connection extends AbstractConnection implements WriteFlusher.Listener
|
public class HTTP2Connection extends AbstractConnection implements WriteFlusher.Listener
|
||||||
|
@ -51,14 +52,15 @@ public class HTTP2Connection extends AbstractConnection implements WriteFlusher.
|
||||||
private final int bufferSize;
|
private final int bufferSize;
|
||||||
private final ExecutionStrategy strategy;
|
private final ExecutionStrategy strategy;
|
||||||
|
|
||||||
public HTTP2Connection(ByteBufferPool byteBufferPool, ReservedThreadExecutor executor, EndPoint endPoint, Parser parser, ISession session, int bufferSize)
|
public HTTP2Connection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, Parser parser, ISession session, int bufferSize)
|
||||||
{
|
{
|
||||||
super(endPoint, executor.getExecutor());
|
super(endPoint, executor);
|
||||||
this.byteBufferPool = byteBufferPool;
|
this.byteBufferPool = byteBufferPool;
|
||||||
this.parser = parser;
|
this.parser = parser;
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.bufferSize = bufferSize;
|
this.bufferSize = bufferSize;
|
||||||
this.strategy = new EatWhatYouKill(producer, executor.getExecutor(), executor);
|
// TODO HTTP2 cannot use EWYK without fix for #1803
|
||||||
|
this.strategy = new EatWhatYouKill(producer, new TryExecutor.NoTryExecutor(executor));
|
||||||
LifeCycle.start(strategy);
|
LifeCycle.start(strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
<Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="128"/></Set>
|
<Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="128"/></Set>
|
||||||
<Set name="initialStreamRecvWindow"><Property name="jetty.http2.initialStreamRecvWindow" default="524288"/></Set>
|
<Set name="initialStreamRecvWindow"><Property name="jetty.http2.initialStreamRecvWindow" default="524288"/></Set>
|
||||||
<Set name="initialSessionRecvWindow"><Property name="jetty.http2.initialSessionRecvWindow" default="1048576"/></Set>
|
<Set name="initialSessionRecvWindow"><Property name="jetty.http2.initialSessionRecvWindow" default="1048576"/></Set>
|
||||||
<Set name="reservedThreads"><Property name="jetty.http2.reservedThreads" default="-1"/></Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
|
@ -27,7 +27,3 @@ etc/jetty-http2.xml
|
||||||
|
|
||||||
## Initial session receive window (client to server)
|
## Initial session receive window (client to server)
|
||||||
# jetty.http2.initialSessionRecvWindow=1048576
|
# jetty.http2.initialSessionRecvWindow=1048576
|
||||||
|
|
||||||
## Reserve threads for high priority tasks (-1 use number of Selectors, 0 no reserved threads)
|
|
||||||
# jetty.http2.reservedThreads=-1
|
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,6 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.annotation.Name;
|
import org.eclipse.jetty.util.annotation.Name;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
|
||||||
|
|
||||||
@ManagedObject
|
@ManagedObject
|
||||||
public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
|
public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConnectionFactory
|
||||||
|
@ -49,7 +48,6 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
||||||
private int maxHeaderBlockFragment = 0;
|
private int maxHeaderBlockFragment = 0;
|
||||||
private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
|
private FlowControlStrategy.Factory flowControlStrategyFactory = () -> new BufferingFlowControlStrategy(0.5F);
|
||||||
private long streamIdleTimeout;
|
private long streamIdleTimeout;
|
||||||
private int reservedThreads;
|
|
||||||
|
|
||||||
public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
|
public AbstractHTTP2ServerConnectionFactory(@Name("config") HttpConfiguration httpConfiguration)
|
||||||
{
|
{
|
||||||
|
@ -143,20 +141,23 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ReservedThreadExecutor
|
* @return -1
|
||||||
* @return The number of reserved threads
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
@ManagedAttribute("The number of threads reserved for high priority tasks")
|
@Deprecated
|
||||||
public int getReservedThreads()
|
public int getReservedThreads()
|
||||||
{
|
{
|
||||||
return reservedThreads;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param threads ignored
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setReservedThreads(int threads)
|
public void setReservedThreads(int threads)
|
||||||
{
|
{
|
||||||
// TODO: see also HTTP2Connection.FillableCallback.
|
throw new UnsupportedOperationException();
|
||||||
// TODO: currently disabled since the only value that works is 0.
|
|
||||||
// this.reservedThreads = threads;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public HttpConfiguration getHttpConfiguration()
|
public HttpConfiguration getHttpConfiguration()
|
||||||
|
@ -183,30 +184,14 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
||||||
streamIdleTimeout = endPoint.getIdleTimeout();
|
streamIdleTimeout = endPoint.getIdleTimeout();
|
||||||
session.setStreamIdleTimeout(streamIdleTimeout);
|
session.setStreamIdleTimeout(streamIdleTimeout);
|
||||||
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
|
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
|
||||||
|
|
||||||
ReservedThreadExecutor executor = provideReservedThreadExecutor(connector);
|
|
||||||
|
|
||||||
ServerParser parser = newServerParser(connector, session);
|
ServerParser parser = newServerParser(connector, session);
|
||||||
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), executor,
|
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
|
||||||
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
|
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
|
||||||
connection.addListener(connectionListener);
|
connection.addListener(connectionListener);
|
||||||
return configure(connection, connector, endPoint);
|
return configure(connection, connector, endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ReservedThreadExecutor provideReservedThreadExecutor(Connector connector)
|
|
||||||
{
|
|
||||||
synchronized (this)
|
|
||||||
{
|
|
||||||
ReservedThreadExecutor executor = getBean(ReservedThreadExecutor.class);
|
|
||||||
if (executor == null)
|
|
||||||
{
|
|
||||||
executor = new ReservedThreadExecutor(connector.getExecutor(), getReservedThreads());
|
|
||||||
addManaged(executor);
|
|
||||||
}
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
|
protected abstract ServerSessionListener newSessionListener(Connector connector, EndPoint endPoint);
|
||||||
|
|
||||||
protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
|
protected ServerParser newServerParser(Connector connector, ServerParser.Listener listener)
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.BadMessageException;
|
import org.eclipse.jetty.http.BadMessageException;
|
||||||
|
@ -58,7 +59,6 @@ import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.Callback;
|
import org.eclipse.jetty.util.Callback;
|
||||||
import org.eclipse.jetty.util.CountingCallback;
|
import org.eclipse.jetty.util.CountingCallback;
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
|
||||||
|
|
||||||
public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo
|
public class HTTP2ServerConnection extends HTTP2Connection implements Connection.UpgradeTo
|
||||||
{
|
{
|
||||||
|
@ -94,7 +94,7 @@ public class HTTP2ServerConnection extends HTTP2Connection implements Connection
|
||||||
private final HttpConfiguration httpConfig;
|
private final HttpConfiguration httpConfig;
|
||||||
private boolean recycleHttpChannels;
|
private boolean recycleHttpChannels;
|
||||||
|
|
||||||
public HTTP2ServerConnection(ByteBufferPool byteBufferPool, ReservedThreadExecutor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener)
|
public HTTP2ServerConnection(ByteBufferPool byteBufferPool, Executor executor, EndPoint endPoint, HttpConfiguration httpConfig, ServerParser parser, ISession session, int inputBufferSize, ServerSessionListener listener)
|
||||||
{
|
{
|
||||||
super(byteBufferPool, executor, endPoint, parser, session, inputBufferSize);
|
super(byteBufferPool, executor, endPoint, parser, session, inputBufferSize);
|
||||||
this.listener = listener;
|
this.listener = listener;
|
||||||
|
|
|
@ -48,7 +48,6 @@ import org.eclipse.jetty.util.component.DumpableCollection;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
||||||
|
|
||||||
|
@ -77,7 +76,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
_id = id;
|
_id = id;
|
||||||
SelectorProducer producer = new SelectorProducer();
|
SelectorProducer producer = new SelectorProducer();
|
||||||
Executor executor = selectorManager.getExecutor();
|
Executor executor = selectorManager.getExecutor();
|
||||||
_strategy = new EatWhatYouKill(producer,executor,_selectorManager.getBean(ReservedThreadExecutor.class));
|
_strategy = new EatWhatYouKill(producer,executor);
|
||||||
addBean(_strategy,true);
|
addBean(_strategy,true);
|
||||||
setStopTimeout(5000);
|
setStopTimeout(5000);
|
||||||
}
|
}
|
||||||
|
@ -136,17 +135,17 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submit an {@link SelectorUpdate} to be acted on between calls to {@link Selector#select()}
|
* Submit an {@link SelectorUpdate} to be acted on between calls to {@link Selector#select()}
|
||||||
* @param action
|
* @param update The selector update to apply at next wakeup
|
||||||
*/
|
*/
|
||||||
public void submit(SelectorUpdate action)
|
public void submit(SelectorUpdate update)
|
||||||
{
|
{
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Queued change {} on {}", action, this);
|
LOG.debug("Queued change {} on {}", update, this);
|
||||||
|
|
||||||
Selector selector = null;
|
Selector selector = null;
|
||||||
synchronized(ManagedSelector.this)
|
synchronized(ManagedSelector.this)
|
||||||
{
|
{
|
||||||
_updates.offer(action);
|
_updates.offer(update);
|
||||||
|
|
||||||
if (_selecting)
|
if (_selecting)
|
||||||
{
|
{
|
||||||
|
@ -265,15 +264,15 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
{
|
{
|
||||||
Selector selector = _selector;
|
Selector selector = _selector;
|
||||||
List<String> keys = null;
|
List<String> keys = null;
|
||||||
List<SelectorUpdate> actions = null;
|
List<SelectorUpdate> updates = null;
|
||||||
if (selector != null && selector.isOpen())
|
if (selector != null && selector.isOpen())
|
||||||
{
|
{
|
||||||
DumpKeys dump = new DumpKeys();
|
DumpKeys dump = new DumpKeys();
|
||||||
String actionsAt;
|
String updatesAt;
|
||||||
synchronized(ManagedSelector.this)
|
synchronized(ManagedSelector.this)
|
||||||
{
|
{
|
||||||
actionsAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
updatesAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
||||||
actions = new ArrayList<>(_updates);
|
updates = new ArrayList<>(_updates);
|
||||||
_updates.addFirst(dump);
|
_updates.addFirst(dump);
|
||||||
_selecting = false;
|
_selecting = false;
|
||||||
}
|
}
|
||||||
|
@ -282,7 +281,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
String keysAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
String keysAt = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
|
||||||
if (keys==null)
|
if (keys==null)
|
||||||
keys = Collections.singletonList("No dump keys retrieved");
|
keys = Collections.singletonList("No dump keys retrieved");
|
||||||
dumpBeans(out, indent, Arrays.asList(new DumpableCollection("actions @ "+actionsAt, actions),
|
dumpBeans(out, indent, Arrays.asList(new DumpableCollection("updates @ "+updatesAt, updates),
|
||||||
new DumpableCollection("keys @ "+keysAt, keys)));
|
new DumpableCollection("keys @ "+keysAt, keys)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -295,7 +294,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
Selector selector = _selector;
|
Selector selector = _selector;
|
||||||
return String.format("%s id=%s keys=%d selected=%d actions=%d",
|
return String.format("%s id=%s keys=%d selected=%d updates=%d",
|
||||||
super.toString(),
|
super.toString(),
|
||||||
_id,
|
_id,
|
||||||
selector != null && selector.isOpen() ? selector.keys().size() : -1,
|
selector != null && selector.isOpen() ? selector.keys().size() : -1,
|
||||||
|
@ -377,16 +376,16 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
_updateable.clear();
|
_updateable.clear();
|
||||||
|
|
||||||
Selector selector;
|
Selector selector;
|
||||||
int actions;
|
int updates;
|
||||||
synchronized(ManagedSelector.this)
|
synchronized(ManagedSelector.this)
|
||||||
{
|
{
|
||||||
actions = _updates.size();
|
updates = _updates.size();
|
||||||
_selecting = actions==0;
|
_selecting = updates==0;
|
||||||
selector = _selecting?null:_selector;
|
selector = _selecting?null:_selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("actions {}",actions);
|
LOG.debug("updates {}",updates);
|
||||||
|
|
||||||
if (selector != null)
|
if (selector != null)
|
||||||
selector.wakeup();
|
selector.wakeup();
|
||||||
|
@ -405,18 +404,18 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Selector {} woken up from select, {}/{} selected", selector, selected, selector.keys().size());
|
LOG.debug("Selector {} woken up from select, {}/{} selected", selector, selected, selector.keys().size());
|
||||||
|
|
||||||
int actions;
|
int updates;
|
||||||
synchronized(ManagedSelector.this)
|
synchronized(ManagedSelector.this)
|
||||||
{
|
{
|
||||||
// finished selecting
|
// finished selecting
|
||||||
_selecting = false;
|
_selecting = false;
|
||||||
actions = _updates.size();
|
updates = _updates.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
_keys = selector.selectedKeys();
|
_keys = selector.selectedKeys();
|
||||||
_cursor = _keys.iterator();
|
_cursor = _keys.iterator();
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("Selector {} processing {} keys, {} actions", selector, _keys.size(), actions);
|
LOG.debug("Selector {} processing {} keys, {} updates", selector, _keys.size(), updates);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -489,7 +488,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable
|
||||||
{
|
{
|
||||||
// Do update keys for only previously selected keys.
|
// Do update keys for only previously selected keys.
|
||||||
// This will update only those keys whose selection did not cause an
|
// This will update only those keys whose selection did not cause an
|
||||||
// updateKeys action to be submitted.
|
// updateKeys update to be submitted.
|
||||||
for (SelectionKey key : _keys)
|
for (SelectionKey key : _keys)
|
||||||
updateKey(key);
|
updateKey(key);
|
||||||
_keys.clear();
|
_keys.clear();
|
||||||
|
|
|
@ -38,11 +38,9 @@ import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.component.Dumpable;
|
import org.eclipse.jetty.util.component.Dumpable;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
|
||||||
import org.eclipse.jetty.util.thread.Scheduler;
|
import org.eclipse.jetty.util.thread.Scheduler;
|
||||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||||
import org.eclipse.jetty.util.thread.ThreadPoolBudget;
|
import org.eclipse.jetty.util.thread.ThreadPoolBudget;
|
||||||
import org.eclipse.jetty.util.thread.strategy.EatWhatYouKill;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>{@link SelectorManager} manages a number of {@link ManagedSelector}s that
|
* <p>{@link SelectorManager} manages a number of {@link ManagedSelector}s that
|
||||||
|
@ -63,9 +61,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
private final AtomicInteger _selectorIndex = new AtomicInteger();
|
private final AtomicInteger _selectorIndex = new AtomicInteger();
|
||||||
private final IntUnaryOperator _selectorIndexUpdate;
|
private final IntUnaryOperator _selectorIndexUpdate;
|
||||||
private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
private long _connectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||||
private int _reservedThreads = -1;
|
|
||||||
private ThreadPoolBudget.Lease _lease;
|
private ThreadPoolBudget.Lease _lease;
|
||||||
private ReservedThreadExecutor _reservedThreadExecutor;
|
|
||||||
|
|
||||||
private static int defaultSelectors(Executor executor)
|
private static int defaultSelectors(Executor executor)
|
||||||
{
|
{
|
||||||
|
@ -133,34 +129,23 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of preallocated producing threads
|
* @return -1
|
||||||
* @see EatWhatYouKill
|
* @deprecated
|
||||||
* @see ReservedThreadExecutor
|
|
||||||
* @return The number of threads preallocated to producing (default -1).
|
|
||||||
*/
|
*/
|
||||||
@ManagedAttribute("The number of reserved producer threads")
|
@Deprecated
|
||||||
public int getReservedThreads()
|
public int getReservedThreads()
|
||||||
{
|
{
|
||||||
return _reservedThreads;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the number of reserved threads for high priority tasks.
|
* @param threads ignored
|
||||||
* <p>Reserved threads are used to take over producing duties, so that a
|
* @deprecated
|
||||||
* producer thread may immediately consume a task it has produced (EatWhatYouKill
|
|
||||||
* scheduling). If a reserved thread is not available, then produced tasks must
|
|
||||||
* be submitted to an executor to be executed by a different thread.
|
|
||||||
* @see EatWhatYouKill
|
|
||||||
* @see ReservedThreadExecutor
|
|
||||||
* @param threads The number of producing threads to preallocate. If
|
|
||||||
* less that 0 (the default), then a heuristic based on the number of CPUs and
|
|
||||||
* the thread pool size is used to select the number of threads. If 0, no
|
|
||||||
* threads are preallocated and the EatWhatYouKill scheduler will be
|
|
||||||
* disabled and all produced tasks will be executed in a separate thread.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public void setReservedThreads(int threads)
|
public void setReservedThreads(int threads)
|
||||||
{
|
{
|
||||||
_reservedThreads = threads;
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,7 +167,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
return _selectors.length;
|
return _selectors.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ManagedSelector chooseSelector(SelectableChannel channel)
|
private ManagedSelector chooseSelector()
|
||||||
{
|
{
|
||||||
return _selectors[_selectorIndex.updateAndGet(_selectorIndexUpdate)];
|
return _selectors[_selectorIndex.updateAndGet(_selectorIndexUpdate)];
|
||||||
}
|
}
|
||||||
|
@ -199,7 +184,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
*/
|
*/
|
||||||
public void connect(SelectableChannel channel, Object attachment)
|
public void connect(SelectableChannel channel, Object attachment)
|
||||||
{
|
{
|
||||||
ManagedSelector set = chooseSelector(channel);
|
ManagedSelector set = chooseSelector();
|
||||||
set.submit(set.new Connect(channel, attachment));
|
set.submit(set.new Connect(channel, attachment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +209,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
*/
|
*/
|
||||||
public void accept(SelectableChannel channel, Object attachment)
|
public void accept(SelectableChannel channel, Object attachment)
|
||||||
{
|
{
|
||||||
final ManagedSelector selector = chooseSelector(channel);
|
final ManagedSelector selector = chooseSelector();
|
||||||
selector.submit(selector.new Accept(channel, attachment));
|
selector.submit(selector.new Accept(channel, attachment));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +224,7 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
*/
|
*/
|
||||||
public Closeable acceptor(SelectableChannel server)
|
public Closeable acceptor(SelectableChannel server)
|
||||||
{
|
{
|
||||||
final ManagedSelector selector = chooseSelector(null);
|
final ManagedSelector selector = chooseSelector();
|
||||||
ManagedSelector.Acceptor acceptor = selector.new Acceptor(server);
|
ManagedSelector.Acceptor acceptor = selector.new Acceptor(server);
|
||||||
selector.submit(acceptor);
|
selector.submit(acceptor);
|
||||||
return acceptor;
|
return acceptor;
|
||||||
|
@ -262,8 +247,6 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
_reservedThreadExecutor = new ReservedThreadExecutor(getExecutor(),_reservedThreads,this);
|
|
||||||
addBean(_reservedThreadExecutor,true);
|
|
||||||
_lease = ThreadPoolBudget.leaseFrom(getExecutor(), this, _selectors.length);
|
_lease = ThreadPoolBudget.leaseFrom(getExecutor(), this, _selectors.length);
|
||||||
for (int i = 0; i < _selectors.length; i++)
|
for (int i = 0; i < _selectors.length; i++)
|
||||||
{
|
{
|
||||||
|
@ -301,9 +284,6 @@ public abstract class SelectorManager extends ContainerLifeCycle implements Dump
|
||||||
removeBean(selector);
|
removeBean(selector);
|
||||||
}
|
}
|
||||||
Arrays.fill(_selectors,null);
|
Arrays.fill(_selectors,null);
|
||||||
if (_reservedThreadExecutor!=null)
|
|
||||||
removeBean(_reservedThreadExecutor);
|
|
||||||
_reservedThreadExecutor = null;
|
|
||||||
if (_lease != null)
|
if (_lease != null)
|
||||||
_lease.close();
|
_lease.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
<Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="128"/></Set>
|
<Set name="maxConcurrentStreams"><Property name="jetty.http2.maxConcurrentStreams" deprecated="http2.maxConcurrentStreams" default="128"/></Set>
|
||||||
<Set name="initialStreamRecvWindow"><Property name="jetty.http2.initialStreamRecvWindow" default="524288"/></Set>
|
<Set name="initialStreamRecvWindow"><Property name="jetty.http2.initialStreamRecvWindow" default="524288"/></Set>
|
||||||
<Set name="initialSessionRecvWindow"><Property name="jetty.http2.initialSessionRecvWindow" default="1048576"/></Set>
|
<Set name="initialSessionRecvWindow"><Property name="jetty.http2.initialSessionRecvWindow" default="1048576"/></Set>
|
||||||
<Set name="reservedThreads"><Property name="jetty.http2.reservedThreads" default="-1"/></Set>
|
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
<Set name="acceptQueueSize"><Property name="jetty.http.acceptQueueSize" deprecated="http.acceptQueueSize" default="0"/></Set>
|
<Set name="acceptQueueSize"><Property name="jetty.http.acceptQueueSize" deprecated="http.acceptQueueSize" default="0"/></Set>
|
||||||
<Get name="SelectorManager">
|
<Get name="SelectorManager">
|
||||||
<Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
|
<Set name="connectTimeout"><Property name="jetty.http.connectTimeout" default="15000"/></Set>
|
||||||
<Set name="reservedThreads"><Property name="jetty.http.reservedThreads" default="-2"/></Set>
|
|
||||||
</Get>
|
</Get>
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
<Set name="acceptQueueSize"><Property name="jetty.ssl.acceptQueueSize" deprecated="ssl.acceptQueueSize" default="0"/></Set>
|
<Set name="acceptQueueSize"><Property name="jetty.ssl.acceptQueueSize" deprecated="ssl.acceptQueueSize" default="0"/></Set>
|
||||||
<Get name="SelectorManager">
|
<Get name="SelectorManager">
|
||||||
<Set name="connectTimeout"><Property name="jetty.ssl.connectTimeout" default="15000"/></Set>
|
<Set name="connectTimeout"><Property name="jetty.ssl.connectTimeout" default="15000"/></Set>
|
||||||
<Set name="reservedThreads"><Property name="jetty.ssl.reservedThreads" default="-2"/></Set>
|
|
||||||
</Get>
|
</Get>
|
||||||
</New>
|
</New>
|
||||||
</Arg>
|
</Arg>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<!-- =========================================================== -->
|
<!-- =========================================================== -->
|
||||||
<Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
|
<Set name="minThreads" type="int"><Property name="jetty.threadPool.minThreads" deprecated="threads.min" default="10"/></Set>
|
||||||
<Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
|
<Set name="maxThreads" type="int"><Property name="jetty.threadPool.maxThreads" deprecated="threads.max" default="200"/></Set>
|
||||||
|
<Set name="reservedThreads" type="int"><Property name="jetty.threadPool.reservedThreads" default="-1"/></Set>
|
||||||
<Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
|
<Set name="idleTimeout" type="int"><Property name="jetty.threadPool.idleTimeout" deprecated="threads.timeout" default="60000"/></Set>
|
||||||
<Set name="detailedDump" type="boolean"><Property name="jetty.threadPool.detailedDump" default="false"/></Set>
|
<Set name="detailedDump" type="boolean"><Property name="jetty.threadPool.detailedDump" default="false"/></Set>
|
||||||
</Configure>
|
</Configure>
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
<!-- configuration that may be set here. -->
|
<!-- configuration that may be set here. -->
|
||||||
<!-- =============================================================== -->
|
<!-- =============================================================== -->
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
|
||||||
<Arg name="threadpool"><Ref refid="threadPool"/></Arg>
|
<Arg name="threadpool"><Ref refid="threadPool"/></Arg>
|
||||||
|
|
||||||
<!-- =========================================================== -->
|
<!-- =========================================================== -->
|
||||||
|
|
|
@ -40,9 +40,6 @@ etc/jetty-http.xml
|
||||||
## Thread priority delta to give to acceptor threads
|
## Thread priority delta to give to acceptor threads
|
||||||
# jetty.http.acceptorPriorityDelta=0
|
# jetty.http.acceptorPriorityDelta=0
|
||||||
|
|
||||||
## Reserve threads for high priority tasks (-1 use a heuristic, 0 no reserved threads)
|
|
||||||
# jetty.http.reservedThreads=-1
|
|
||||||
|
|
||||||
## Connect Timeout in milliseconds
|
## Connect Timeout in milliseconds
|
||||||
# jetty.http.connectTimeout=15000
|
# jetty.http.connectTimeout=15000
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,6 @@ basehome:modules/ssl/keystore|etc/keystore
|
||||||
## Thread priority delta to give to acceptor threads
|
## Thread priority delta to give to acceptor threads
|
||||||
# jetty.ssl.acceptorPriorityDelta=0
|
# jetty.ssl.acceptorPriorityDelta=0
|
||||||
|
|
||||||
## Preallocated producer threads (0 disables EatWhatYouKill scheduling)
|
|
||||||
# jetty.ssl.reservedThreads=-1
|
|
||||||
|
|
||||||
## Connect Timeout in milliseconds
|
## Connect Timeout in milliseconds
|
||||||
# jetty.ssl.connectTimeout=15000
|
# jetty.ssl.connectTimeout=15000
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@ etc/jetty-threadpool.xml
|
||||||
## Maximum Number of Threads
|
## Maximum Number of Threads
|
||||||
#jetty.threadPool.maxThreads=200
|
#jetty.threadPool.maxThreads=200
|
||||||
|
|
||||||
|
## Number of reserved threads (-1 for heuristic)
|
||||||
|
# jetty.threadPool.reservedThreads=-1
|
||||||
|
|
||||||
## Thread Idle Timeout (in milliseconds)
|
## Thread Idle Timeout (in milliseconds)
|
||||||
#jetty.threadPool.idleTimeout=60000
|
#jetty.threadPool.idleTimeout=60000
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
import org.eclipse.jetty.util.annotation.ManagedOperation;
|
||||||
import org.eclipse.jetty.util.annotation.Name;
|
import org.eclipse.jetty.util.annotation.Name;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
|
||||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||||
import org.eclipse.jetty.util.component.Dumpable;
|
import org.eclipse.jetty.util.component.Dumpable;
|
||||||
import org.eclipse.jetty.util.component.DumpableCollection;
|
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||||
|
@ -46,7 +45,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool;
|
import org.eclipse.jetty.util.thread.ThreadPool.SizedThreadPool;
|
||||||
|
|
||||||
@ManagedObject("A thread pool")
|
@ManagedObject("A thread pool")
|
||||||
public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPool, Dumpable
|
public class QueuedThreadPool extends ContainerLifeCycle implements SizedThreadPool, Dumpable, TryExecutor
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(QueuedThreadPool.class);
|
private static final Logger LOG = Log.getLogger(QueuedThreadPool.class);
|
||||||
|
|
||||||
|
@ -61,6 +60,8 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
private int _idleTimeout;
|
private int _idleTimeout;
|
||||||
private int _maxThreads;
|
private int _maxThreads;
|
||||||
private int _minThreads;
|
private int _minThreads;
|
||||||
|
private int _reservedThreads = -1;
|
||||||
|
private TryExecutor _tryExecutor = TryExecutor.NO_TRY;
|
||||||
private int _priority = Thread.NORM_PRIORITY;
|
private int _priority = Thread.NORM_PRIORITY;
|
||||||
private boolean _daemon = false;
|
private boolean _daemon = false;
|
||||||
private boolean _detailedDump = false;
|
private boolean _detailedDump = false;
|
||||||
|
@ -93,12 +94,17 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
}
|
}
|
||||||
|
|
||||||
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
|
||||||
|
{
|
||||||
|
this(maxThreads, minThreads, idleTimeout, -1, queue, threadGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("reservedThreads") int reservedThreads, @Name("queue") BlockingQueue<Runnable> queue, @Name("threadGroup") ThreadGroup threadGroup)
|
||||||
{
|
{
|
||||||
setMinThreads(minThreads);
|
setMinThreads(minThreads);
|
||||||
setMaxThreads(maxThreads);
|
setMaxThreads(maxThreads);
|
||||||
setIdleTimeout(idleTimeout);
|
setIdleTimeout(idleTimeout);
|
||||||
setStopTimeout(5000);
|
setStopTimeout(5000);
|
||||||
|
setReservedThreads(reservedThreads);
|
||||||
if (queue==null)
|
if (queue==null)
|
||||||
{
|
{
|
||||||
int capacity=Math.max(_minThreads, 8);
|
int capacity=Math.max(_minThreads, 8);
|
||||||
|
@ -106,7 +112,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
}
|
}
|
||||||
_jobs=queue;
|
_jobs=queue;
|
||||||
_threadGroup=threadGroup;
|
_threadGroup=threadGroup;
|
||||||
_budget=new ThreadPoolBudget(this);
|
setThreadPoolBudget(new ThreadPoolBudget(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,15 +131,21 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
|
_tryExecutor = new ReservedThreadExecutor(this,_reservedThreads);
|
||||||
|
addBean(_tryExecutor);
|
||||||
|
|
||||||
super.doStart();
|
super.doStart();
|
||||||
_threadsStarted.set(0);
|
_threadsStarted.set(0);
|
||||||
|
|
||||||
startThreads(_minThreads);
|
startThreads(_minThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doStop() throws Exception
|
protected void doStop() throws Exception
|
||||||
{
|
{
|
||||||
|
removeBean(_tryExecutor);
|
||||||
|
_tryExecutor = TryExecutor.NO_TRY;
|
||||||
|
|
||||||
super.doStop();
|
super.doStop();
|
||||||
|
|
||||||
long timeout = getStopTimeout();
|
long timeout = getStopTimeout();
|
||||||
|
@ -222,7 +234,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
* Set the maximum thread idle time.
|
* Set the maximum thread idle time.
|
||||||
* Threads that are idle for longer than this period may be
|
* Threads that are idle for longer than this period may be
|
||||||
* stopped.
|
* stopped.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @param idleTimeout Max idle time in ms.
|
* @param idleTimeout Max idle time in ms.
|
||||||
* @see #getIdleTimeout
|
* @see #getIdleTimeout
|
||||||
|
@ -234,7 +245,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the maximum number of threads.
|
* Set the maximum number of threads.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @param maxThreads maximum number of threads.
|
* @param maxThreads maximum number of threads.
|
||||||
* @see #getMaxThreads
|
* @see #getMaxThreads
|
||||||
|
@ -249,7 +259,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the minimum number of threads.
|
* Set the minimum number of threads.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @param minThreads minimum number of threads
|
* @param minThreads minimum number of threads
|
||||||
* @see #getMinThreads
|
* @see #getMinThreads
|
||||||
|
@ -266,6 +275,19 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
if (isStarted() && threads < _minThreads)
|
if (isStarted() && threads < _minThreads)
|
||||||
startThreads(_minThreads - threads);
|
startThreads(_minThreads - threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the number of reserved threads.
|
||||||
|
*
|
||||||
|
* @param reservedThreads number of reserved threads or -1 for heuristically determined
|
||||||
|
* @see #getReservedThreads
|
||||||
|
*/
|
||||||
|
public void setReservedThreads(int reservedThreads)
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
throw new IllegalStateException(getState());
|
||||||
|
_reservedThreads = reservedThreads;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name Name of this thread pool to use when naming threads.
|
* @param name Name of this thread pool to use when naming threads.
|
||||||
|
@ -289,7 +311,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum thread idle time.
|
* Get the maximum thread idle time.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @return Max idle time in ms.
|
* @return Max idle time in ms.
|
||||||
* @see #setIdleTimeout
|
* @see #setIdleTimeout
|
||||||
|
@ -302,7 +323,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the maximum number of threads.
|
* Get the maximum number of threads.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @return maximum number of threads.
|
* @return maximum number of threads.
|
||||||
* @see #setMaxThreads
|
* @see #setMaxThreads
|
||||||
|
@ -316,7 +336,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the minimum number of threads.
|
* Get the minimum number of threads.
|
||||||
* Delegated to the named or anonymous Pool.
|
|
||||||
*
|
*
|
||||||
* @return minimum number of threads.
|
* @return minimum number of threads.
|
||||||
* @see #setMinThreads
|
* @see #setMinThreads
|
||||||
|
@ -328,6 +347,20 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
return _minThreads;
|
return _minThreads;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of reserved threads.
|
||||||
|
*
|
||||||
|
* @return number of reserved threads or or -1 for heuristically determined
|
||||||
|
* @see #setReservedThreads
|
||||||
|
*/
|
||||||
|
@ManagedAttribute("the number of reserved threads in the pool")
|
||||||
|
public int getReservedThreads()
|
||||||
|
{
|
||||||
|
if (isStarted())
|
||||||
|
return getBean(ReservedThreadExecutor.class).getCapacity();
|
||||||
|
return _reservedThreads;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The name of the this thread pool
|
* @return The name of the this thread pool
|
||||||
*/
|
*/
|
||||||
|
@ -409,6 +442,13 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryExecute(Runnable task)
|
||||||
|
{
|
||||||
|
TryExecutor tryExecutor = _tryExecutor;
|
||||||
|
return tryExecutor!=null && tryExecutor.tryExecute(task);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blocks until the thread pool is {@link LifeCycle#stop stopped}.
|
* Blocks until the thread pool is {@link LifeCycle#stop stopped}.
|
||||||
*/
|
*/
|
||||||
|
@ -509,13 +549,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
return new Thread(_threadGroup, runnable);
|
return new Thread(_threadGroup, runnable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@ManagedOperation("dumps thread pool state")
|
|
||||||
public String dump()
|
|
||||||
{
|
|
||||||
return ContainerLifeCycle.dump(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dump(Appendable out, String indent) throws IOException
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
{
|
{
|
||||||
|
@ -585,14 +618,21 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
|
||||||
if (isDetailedDump())
|
if (isDetailedDump())
|
||||||
jobs = new ArrayList<>(getQueue());
|
jobs = new ArrayList<>(getQueue());
|
||||||
|
|
||||||
ContainerLifeCycle.dumpObject(out, this);
|
dumpBeans(out, indent, threads, Collections.singletonList(new DumpableCollection("jobs", jobs)));
|
||||||
ContainerLifeCycle.dump(out, indent, threads, Collections.singletonList(new DumpableCollection("jobs",jobs)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return String.format("QueuedThreadPool@%s{%s,%d<=%d<=%d,i=%d,q=%d}", _name, getState(), getMinThreads(), getThreads(), getMaxThreads(), getIdleThreads(), (_jobs == null ? -1 : _jobs.size()));
|
return String.format("QueuedThreadPool@%s{%s,%d<=%d<=%d,i=%d,q=%d,r=%s}",
|
||||||
|
_name,
|
||||||
|
getState(),
|
||||||
|
getMinThreads(),
|
||||||
|
getThreads(),
|
||||||
|
getMaxThreads(),
|
||||||
|
getIdleThreads(),
|
||||||
|
_jobs.size(),
|
||||||
|
_tryExecutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable idleJobPoll() throws InterruptedException
|
private Runnable idleJobPoll() throws InterruptedException
|
||||||
|
|
|
@ -42,7 +42,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* whenever it has been idle for that period.
|
* whenever it has been idle for that period.
|
||||||
*/
|
*/
|
||||||
@ManagedObject("A pool for reserved threads")
|
@ManagedObject("A pool for reserved threads")
|
||||||
public class ReservedThreadExecutor extends AbstractLifeCycle implements Executor
|
public class ReservedThreadExecutor extends AbstractLifeCycle implements TryExecutor
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(ReservedThreadExecutor.class);
|
private static final Logger LOG = Log.getLogger(ReservedThreadExecutor.class);
|
||||||
private static final Runnable STOP = new Runnable()
|
private static final Runnable STOP = new Runnable()
|
||||||
|
@ -66,42 +66,24 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
||||||
private final AtomicInteger _pending = new AtomicInteger();
|
private final AtomicInteger _pending = new AtomicInteger();
|
||||||
|
|
||||||
private ThreadPoolBudget.Lease _lease;
|
private ThreadPoolBudget.Lease _lease;
|
||||||
private Object _owner;
|
|
||||||
private long _idleTime = 1L;
|
private long _idleTime = 1L;
|
||||||
private TimeUnit _idleTimeUnit = TimeUnit.MINUTES;
|
private TimeUnit _idleTimeUnit = TimeUnit.MINUTES;
|
||||||
|
|
||||||
public ReservedThreadExecutor(Executor executor)
|
|
||||||
{
|
|
||||||
this(executor,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param executor The executor to use to obtain threads
|
|
||||||
* @param capacity The number of threads to preallocate. If less than 0 then capacity
|
|
||||||
* is calculated based on a heuristic from the number of available processors and
|
|
||||||
* thread pool size.
|
|
||||||
*/
|
|
||||||
public ReservedThreadExecutor(Executor executor, int capacity)
|
|
||||||
{
|
|
||||||
this(executor,capacity,null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param executor The executor to use to obtain threads
|
* @param executor The executor to use to obtain threads
|
||||||
* @param capacity The number of threads to preallocate. If less than 0 then capacity
|
* @param capacity The number of threads to preallocate. If less than 0 then capacity
|
||||||
* is calculated based on a heuristic from the number of available processors and
|
* is calculated based on a heuristic from the number of available processors and
|
||||||
* thread pool size.
|
* thread pool size.
|
||||||
* @param owner the owner of the instance. Only used for debugging purpose withing the {@link #toString()} method
|
|
||||||
*/
|
*/
|
||||||
public ReservedThreadExecutor(Executor executor,int capacity, Object owner)
|
public ReservedThreadExecutor(Executor executor,int capacity)
|
||||||
{
|
{
|
||||||
_executor = executor;
|
_executor = executor;
|
||||||
_capacity = reservedThreads(executor,capacity);
|
_capacity = reservedThreads(executor,capacity);
|
||||||
_stack = new ConcurrentLinkedDeque<>();
|
_stack = new ConcurrentLinkedDeque<>();
|
||||||
_owner = owner;
|
|
||||||
|
|
||||||
LOG.debug("{}",this);
|
LOG.debug("{}",this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param executor The executor to use to obtain threads
|
* @param executor The executor to use to obtain threads
|
||||||
* @param capacity The number of threads to preallocate, If less than 0 then capacity
|
* @param capacity The number of threads to preallocate, If less than 0 then capacity
|
||||||
|
@ -110,7 +92,7 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
||||||
* @return the number of reserved threads that would be used by a ReservedThreadExecutor
|
* @return the number of reserved threads that would be used by a ReservedThreadExecutor
|
||||||
* constructed with these arguments.
|
* constructed with these arguments.
|
||||||
*/
|
*/
|
||||||
public static int reservedThreads(Executor executor,int capacity)
|
private static int reservedThreads(Executor executor,int capacity)
|
||||||
{
|
{
|
||||||
if (capacity>=0)
|
if (capacity>=0)
|
||||||
return capacity;
|
return capacity;
|
||||||
|
@ -118,7 +100,7 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
||||||
if (executor instanceof ThreadPool.SizedThreadPool)
|
if (executor instanceof ThreadPool.SizedThreadPool)
|
||||||
{
|
{
|
||||||
int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads();
|
int threads = ((ThreadPool.SizedThreadPool)executor).getMaxThreads();
|
||||||
return Math.max(1, Math.min(cpus, threads / 8));
|
return Math.max(1, Math.min(cpus, threads / 10));
|
||||||
}
|
}
|
||||||
return cpus;
|
return cpus;
|
||||||
}
|
}
|
||||||
|
@ -193,8 +175,7 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
||||||
@Override
|
@Override
|
||||||
public void execute(Runnable task) throws RejectedExecutionException
|
public void execute(Runnable task) throws RejectedExecutionException
|
||||||
{
|
{
|
||||||
if (!tryExecute(task))
|
_executor.execute(task);
|
||||||
throw new RejectedExecutionException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -255,13 +236,12 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements Executo
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return String.format("%s@%x{s=%d/%d,p=%d}@%s",
|
return String.format("%s@%x{s=%d/%d,p=%d}",
|
||||||
getClass().getSimpleName(),
|
getClass().getSimpleName(),
|
||||||
hashCode(),
|
hashCode(),
|
||||||
_size.get(),
|
_size.get(),
|
||||||
_capacity,
|
_capacity,
|
||||||
_pending.get(),
|
_pending.get());
|
||||||
_owner);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ReservedThread implements Runnable
|
private class ReservedThread implements Runnable
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.util.thread;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.RejectedExecutionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A variation of Executor that can confirm if a thread is available immediately
|
||||||
|
*/
|
||||||
|
public interface TryExecutor extends Executor
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Attempt to execute a task.
|
||||||
|
* @param task The task to be executed
|
||||||
|
* @return True IFF the task has been given directly to a thread to execute. The task cannot be queued pending the later availability of a Thread.
|
||||||
|
*/
|
||||||
|
boolean tryExecute(Runnable task);
|
||||||
|
|
||||||
|
default void execute(Runnable task)
|
||||||
|
{
|
||||||
|
if (!tryExecute(task))
|
||||||
|
throw new RejectedExecutionException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TryExecutor asTryExecutor(Executor executor)
|
||||||
|
{
|
||||||
|
if (executor instanceof TryExecutor)
|
||||||
|
return (TryExecutor)executor;
|
||||||
|
return new NoTryExecutor(executor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NoTryExecutor implements TryExecutor
|
||||||
|
{
|
||||||
|
private final Executor executor;
|
||||||
|
|
||||||
|
public NoTryExecutor(Executor executor)
|
||||||
|
{
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(Runnable task)
|
||||||
|
{
|
||||||
|
executor.execute(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tryExecute(Runnable task)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final TryExecutor NO_TRY = task -> false;
|
||||||
|
}
|
|
@ -34,7 +34,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
import org.eclipse.jetty.util.thread.ExecutionStrategy;
|
||||||
import org.eclipse.jetty.util.thread.Invocable;
|
import org.eclipse.jetty.util.thread.Invocable;
|
||||||
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
|
import org.eclipse.jetty.util.thread.Invocable.InvocationType;
|
||||||
import org.eclipse.jetty.util.thread.ReservedThreadExecutor;
|
import org.eclipse.jetty.util.thread.TryExecutor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>A strategy where the thread that produces will run the resulting task if it
|
* <p>A strategy where the thread that produces will run the resulting task if it
|
||||||
|
@ -73,25 +73,16 @@ public class EatWhatYouKill extends ContainerLifeCycle implements ExecutionStrat
|
||||||
private final LongAdder _executed = new LongAdder();
|
private final LongAdder _executed = new LongAdder();
|
||||||
private final Producer _producer;
|
private final Producer _producer;
|
||||||
private final Executor _executor;
|
private final Executor _executor;
|
||||||
private final ReservedThreadExecutor _producers;
|
private final TryExecutor _tryExecutor;
|
||||||
private State _state = State.IDLE;
|
private State _state = State.IDLE;
|
||||||
|
|
||||||
public EatWhatYouKill(Producer producer, Executor executor)
|
public EatWhatYouKill(Producer producer, Executor executor)
|
||||||
{
|
|
||||||
this(producer,executor,new ReservedThreadExecutor(executor,1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public EatWhatYouKill(Producer producer, Executor executor, int maxReserved)
|
|
||||||
{
|
|
||||||
this(producer,executor,new ReservedThreadExecutor(executor,maxReserved));
|
|
||||||
}
|
|
||||||
|
|
||||||
public EatWhatYouKill(Producer producer, Executor executor, ReservedThreadExecutor producers)
|
|
||||||
{
|
{
|
||||||
_producer = producer;
|
_producer = producer;
|
||||||
_executor = executor;
|
_executor = executor;
|
||||||
_producers = producers;
|
_tryExecutor = TryExecutor.asTryExecutor(executor);
|
||||||
addBean(_producer);
|
addBean(_producer);
|
||||||
|
addBean(_tryExecutor);
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("{} created", this);
|
LOG.debug("{} created", this);
|
||||||
}
|
}
|
||||||
|
@ -214,7 +205,7 @@ public class EatWhatYouKill extends ContainerLifeCycle implements ExecutionStrat
|
||||||
{
|
{
|
||||||
synchronized(this)
|
synchronized(this)
|
||||||
{
|
{
|
||||||
if (_producers.tryExecute(this))
|
if (_tryExecutor.tryExecute(this))
|
||||||
{
|
{
|
||||||
// EXECUTE PRODUCE CONSUME!
|
// EXECUTE PRODUCE CONSUME!
|
||||||
// We have executed a new Producer, so we can EWYK consume
|
// We have executed a new Producer, so we can EWYK consume
|
||||||
|
@ -334,7 +325,7 @@ public class EatWhatYouKill extends ContainerLifeCycle implements ExecutionStrat
|
||||||
{
|
{
|
||||||
builder.append(_state);
|
builder.append(_state);
|
||||||
builder.append('/');
|
builder.append('/');
|
||||||
builder.append(_producers);
|
builder.append(_tryExecutor);
|
||||||
builder.append("[nb=");
|
builder.append("[nb=");
|
||||||
builder.append(getNonBlockingTasksConsumed());
|
builder.append(getNonBlockingTasksConsumed());
|
||||||
builder.append(",c=");
|
builder.append(",c=");
|
||||||
|
|
Loading…
Reference in New Issue