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.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -350,29 +351,39 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
}
|
||||
|
||||
HttpGenerator.setJettyVersion(HttpConfiguration.SERVER_VERSION);
|
||||
MultiException mex=new MultiException();
|
||||
|
||||
|
||||
// check size of thread pool
|
||||
SizedThreadPool pool = getBean(SizedThreadPool.class);
|
||||
int max=pool==null?-1:pool.getMaxThreads();
|
||||
int selectors=0;
|
||||
int acceptors=0;
|
||||
if (mex.size()==0)
|
||||
{
|
||||
|
||||
for (Connector connector : _connectors)
|
||||
{
|
||||
if (connector instanceof AbstractConnector)
|
||||
acceptors+=((AbstractConnector)connector).getAcceptors();
|
||||
if (!(connector instanceof AbstractConnector))
|
||||
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)
|
||||
selectors+=((ServerConnector)connector).getSelectorManager().getSelectorCount();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int needed=1+selectors+acceptors;
|
||||
if (max>0 && needed>max)
|
||||
throw new IllegalStateException(String.format("Insufficient threads: max=%d < needed(acceptors=%d + selectors=%d + request=1)",max,acceptors,selectors));
|
||||
|
||||
MultiException mex=new MultiException();
|
||||
try
|
||||
{
|
||||
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