Enhancement for detection of insufficient threads (#1010)
* Issue #586 Enhancement for detection of insufficient threads Do not count acceptors and selectors at server level if connector uses own dedicated thread pool Signed-off-by: vladimir.bukhtoyarov <jsecoder@mail.ru>
This commit is contained in:
parent
0162140e09
commit
bbce9df664
|
@ -29,6 +29,7 @@ import java.util.Date;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -350,29 +351,39 @@ public class Server extends HandlerWrapper implements Attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpGenerator.setJettyVersion(HttpConfiguration.SERVER_VERSION);
|
HttpGenerator.setJettyVersion(HttpConfiguration.SERVER_VERSION);
|
||||||
MultiException mex=new MultiException();
|
|
||||||
|
|
||||||
// check size of thread pool
|
// check size of thread pool
|
||||||
SizedThreadPool pool = getBean(SizedThreadPool.class);
|
SizedThreadPool pool = getBean(SizedThreadPool.class);
|
||||||
int max=pool==null?-1:pool.getMaxThreads();
|
int max=pool==null?-1:pool.getMaxThreads();
|
||||||
int selectors=0;
|
int selectors=0;
|
||||||
int acceptors=0;
|
int acceptors=0;
|
||||||
if (mex.size()==0)
|
|
||||||
{
|
|
||||||
for (Connector connector : _connectors)
|
for (Connector connector : _connectors)
|
||||||
{
|
{
|
||||||
if (connector instanceof AbstractConnector)
|
if (!(connector instanceof AbstractConnector))
|
||||||
acceptors+=((AbstractConnector)connector).getAcceptors();
|
continue;
|
||||||
|
|
||||||
|
AbstractConnector abstractConnector = (AbstractConnector) connector;
|
||||||
|
Executor connectorExecutor = connector.getExecutor();
|
||||||
|
|
||||||
|
if (connectorExecutor != pool)
|
||||||
|
// Do not count the selectors and acceptors from this connector at server level, because connector uses dedicated executor.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
acceptors += abstractConnector.getAcceptors();
|
||||||
|
|
||||||
if (connector instanceof ServerConnector)
|
if (connector instanceof ServerConnector)
|
||||||
selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
|
selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int needed=1+selectors+acceptors;
|
int needed=1+selectors+acceptors;
|
||||||
if (max>0 && needed>max)
|
if (max>0 && needed>max)
|
||||||
throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
|
throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
|
||||||
|
|
||||||
|
MultiException mex=new MultiException();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
super.doStart();
|
super.doStart();
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2016 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.server;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||||
|
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class InsufficientThreadsDetectionTest {
|
||||||
|
|
||||||
|
private Server _server;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void dispose() throws Exception
|
||||||
|
{
|
||||||
|
_server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testConnectorUsesServerExecutorWithNotEnoughThreads() throws Exception
|
||||||
|
{
|
||||||
|
// server has 3 threads in the executor
|
||||||
|
_server = new Server(new QueuedThreadPool(3));
|
||||||
|
|
||||||
|
// connector will use executor from server because connectorPool is null
|
||||||
|
ThreadPool connectorPool = null;
|
||||||
|
// connector requires 7 threads(2 + 4 + 1)
|
||||||
|
ServerConnector connector = new ServerConnector(_server, connectorPool, null, null, 2, 4, new HttpConnectionFactory());
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
|
||||||
|
// should throw IllegalStateException because there are no required threads in server pool
|
||||||
|
_server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectorWithDedicatedExecutor() throws Exception
|
||||||
|
{
|
||||||
|
// server has 3 threads in the executor
|
||||||
|
_server = new Server(new QueuedThreadPool(3));
|
||||||
|
|
||||||
|
// connector pool has 100 threads
|
||||||
|
ThreadPool connectorPool = new QueuedThreadPool(100);
|
||||||
|
// connector requires 7 threads(2 + 4 + 1)
|
||||||
|
ServerConnector connector = new ServerConnector(_server, connectorPool, null, null, 2, 4, new HttpConnectionFactory());
|
||||||
|
connector.setPort(0);
|
||||||
|
_server.addConnector(connector);
|
||||||
|
|
||||||
|
// should not throw exception because connector uses own executor, so its threads should not be counted
|
||||||
|
_server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // Github issue #586
|
||||||
|
public void testCaseForMultipleConnectors() throws Exception {
|
||||||
|
// server has 3 threads in the executor
|
||||||
|
_server = new Server(new QueuedThreadPool(3));
|
||||||
|
|
||||||
|
// first connector consumes all 3 threads from server pool
|
||||||
|
_server.addConnector(new ServerConnector(_server, null, null, null, 1, 1, new HttpConnectionFactory()));
|
||||||
|
|
||||||
|
// second connect also require 3 threads but uses own executor, so its threads should not be counted
|
||||||
|
final QueuedThreadPool connectorPool = new QueuedThreadPool(3, 3);
|
||||||
|
_server.addConnector(new ServerConnector(_server, connectorPool, null, null, 1, 1, new HttpConnectionFactory()));
|
||||||
|
|
||||||
|
// should not throw exception because limit was not overflown
|
||||||
|
_server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue