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:
Vladimir Bukhtoyarov 2016-10-20 13:11:23 +03:00 committed by Simone Bordet
parent 0162140e09
commit bbce9df664
2 changed files with 107 additions and 10 deletions

View File

@ -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();

View File

@ -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();
}
}