From 484280bac6956f9db0d98db60739f5368dec3691 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 14 Mar 2018 13:23:02 -0500 Subject: [PATCH] Issue #2218 - Windows Selector Bug Signed-off-by: Joakim Erdfelt --- .../eclipse/jetty/client/LivelockTest.java | 86 +++++++++++++------ .../test/resources/jetty-logging.properties | 4 +- .../org/eclipse/jetty/io/ManagedSelector.java | 7 +- 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java index 448dd426d16..aa359c69b80 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/LivelockTest.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.client; import java.nio.channels.Selector; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -30,14 +32,37 @@ import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.SocketAddressResolver; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class LivelockTest { + @Parameterized.Parameters(name = "server={0}, client={1}") + public static List data() + { + List data = new ArrayList<>(); + // Server-live-lock, Client-live-lock + data.add(new Object[] { true, true }); + data.add(new Object[] { true, false }); + data.add(new Object[] { false, true }); + data.add(new Object[] { false, false }); + return data; + } + + @Parameterized.Parameter(0) + public boolean serverLiveLock; + + @Parameterized.Parameter(1) + public boolean clientLiveLock; + private Server server; private ServerConnector connector; private HttpClient client; @@ -73,7 +98,7 @@ public class LivelockTest // ManagedSelectors that submit themselves in an attempt to cause a live lock // as there will always be an action available to run. - int count = 25; + int count = 5; HttpClientTransport transport = new HttpClientTransportOverHTTP(1); client = new HttpClient(transport, null); client.setMaxConnectionsPerDestination(2 * count); @@ -88,34 +113,21 @@ public class LivelockTest AtomicBoolean busy = new AtomicBoolean(true); - ManagedSelector clientSelector = client.getContainedBeans(ManagedSelector.class).stream().findAny().get(); - ManagedSelector.SelectorUpdate clientLivelock = new ManagedSelector.SelectorUpdate() + if (clientLiveLock) { - @Override - public void update(Selector selector) - { - sleep(10); - if (busy.get()) - clientSelector.submit(this); - } - }; - clientSelector.submit(clientLivelock); - - ManagedSelector serverSelector = connector.getContainedBeans(ManagedSelector.class).stream().findAny().get(); - ManagedSelector.SelectorUpdate serverLivelock = new ManagedSelector.SelectorUpdate() + ManagedSelector clientSelector = client.getContainedBeans(ManagedSelector.class).stream().findAny().get(); + busyLiveLock(busy, clientSelector); + } + + if (serverLiveLock) { - @Override - public void update(Selector selector) - { - sleep(10); - if (busy.get()) - serverSelector.submit(this); - } - }; - serverSelector.submit(serverLivelock); + ManagedSelector serverSelector = connector.getContainedBeans(ManagedSelector.class).stream().findAny().get(); + busyLiveLock(busy, serverSelector); + } int requestRate = 5; long pause = 1000 / requestRate; + Logger clientLog = Log.getLogger("TESTClient"); CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i < count; ++i) { @@ -125,6 +137,13 @@ public class LivelockTest { if (result.isSucceeded() && result.getResponse().getStatus() == HttpStatus.OK_200) latch.countDown(); + else + { + if(result.getRequestFailure() != null) + clientLog.warn(result.getRequestFailure()); + if(result.getResponseFailure() != null) + clientLog.warn(result.getResponseFailure()); + } }); sleep(pause); } @@ -134,11 +153,26 @@ public class LivelockTest busy.set(false); } - private void sleep(long time) + private void busyLiveLock(AtomicBoolean busy, ManagedSelector managedSelector) + { + ManagedSelector.SelectorUpdate liveLock = new ManagedSelector.SelectorUpdate() + { + @Override + public void update(Selector selector) + { + sleep(10); + if (busy.get()) + managedSelector.submit(this); + } + }; + managedSelector.submit(liveLock); + } + + private void sleep(long millis) { try { - Thread.sleep(time); + TimeUnit.MILLISECONDS.sleep(millis); } catch (InterruptedException x) { diff --git a/jetty-client/src/test/resources/jetty-logging.properties b/jetty-client/src/test/resources/jetty-logging.properties index a2296dfdf69..3f7f23333ae 100644 --- a/jetty-client/src/test/resources/jetty-logging.properties +++ b/jetty-client/src/test/resources/jetty-logging.properties @@ -1,5 +1,5 @@ -org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog -#org.eclipse.jetty.LEVEL=DEBUG +class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=INFO #org.eclipse.jetty.client.LEVEL=DEBUG #org.eclipse.jetty.io.ChannelEndPoint.LEVEL=DEBUG #org.eclipse.jetty.http.LEVEL=DEBUG diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java index 36900ba547f..5f9ad3ccedd 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ManagedSelector.java @@ -42,7 +42,6 @@ import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import org.eclipse.jetty.io.ManagedSelector.Connect; import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.DumpableCollection; @@ -322,7 +321,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable return task; processUpdates(); - + updateKeys(); if (!select()) @@ -372,7 +371,7 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable LOG.debug("updates {}",updates); if (selector != null) - selector.wakeup(); + selector.wakeup(); } private boolean select() @@ -385,6 +384,8 @@ public class ManagedSelector extends ContainerLifeCycle implements Dumpable if (LOG.isDebugEnabled()) LOG.debug("Selector {} waiting on select", selector); int selected = selector.select(); + if (selected == 0) + selected = selector.selectNow(); if (LOG.isDebugEnabled()) LOG.debug("Selector {} woken up from select, {}/{} selected", selector, selected, selector.keys().size());