Issue #354 (Spin loop in case of exception thrown during accept()).

Fixed by introducing an overridable method that performs an arbitrary
sleep to avoid the spin loop. Subclasses may customize.
This commit is contained in:
Simone Bordet 2016-02-23 11:36:39 +01:00
parent ef6d0194b9
commit 76689dd303
2 changed files with 64 additions and 4 deletions

View File

@ -528,6 +528,34 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
return getConnectionFactory(_defaultProtocol);
}
protected boolean handleAcceptFailure(Throwable previous, Throwable current)
{
if (isAccepting())
{
if (previous == null)
LOG.warn(current);
else
LOG.debug(current);
}
else
{
LOG.ignore(current);
}
try
{
// Arbitrary sleep to avoid spin looping.
// Subclasses may decide for a different
// sleep policy or closing the connector.
Thread.sleep(1000);
return true;
}
catch (Throwable x)
{
return false;
}
}
private class Acceptor implements Runnable
{
private final int _id;
@ -557,18 +585,20 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
try
{
Throwable exception = null;
while (isAccepting())
{
try
{
accept(_id);
exception = null;
}
catch (Throwable e)
catch (Throwable x)
{
if (isAccepting())
LOG.warn(e);
if (handleAcceptFailure(exception, x))
exception = x;
else
LOG.ignore(e);
break;
}
}
}

View File

@ -28,6 +28,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.concurrent.atomic.AtomicLong;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -40,6 +41,7 @@ import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.IO;
import org.hamcrest.Matchers;
import org.junit.Test;
import static org.hamcrest.Matchers.anyOf;
@ -235,4 +237,32 @@ public class ServerConnectorTest
assertEquals(2, connector.getBeans(ConnectionFactory.class).size());
assertEquals(proxy.getProtocol(), connector.getDefaultProtocol());
}
@Test
public void testExceptionWhileAccepting() throws Exception
{
Server server = new Server();
AtomicLong spins = new AtomicLong();
ServerConnector connector = new ServerConnector(server)
{
@Override
public void accept(int acceptorID) throws IOException
{
spins.incrementAndGet();
throw new IOException("explicitly_thrown_by_test");
}
};
server.addConnector(connector);
server.start();
try
{
Thread.sleep(1000);
assertThat(spins.get(), Matchers.lessThan(5L));
}
finally
{
server.stop();
}
}
}