Merge branch `jetty-9.4.x` into `jetty-10.0.x`

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>

# Conflicts:
#	VERSION.txt
#	aggregates/jetty-all-compact3/pom.xml
#	aggregates/jetty-all/pom.xml
#	apache-jsp/pom.xml
#	apache-jstl/pom.xml
#	examples/async-rest/async-rest-jar/pom.xml
#	examples/async-rest/async-rest-webapp/pom.xml
#	examples/async-rest/pom.xml
#	examples/embedded/pom.xml
#	examples/pom.xml
#	jetty-alpn/jetty-alpn-client/pom.xml
#	jetty-alpn/jetty-alpn-conscrypt-client/pom.xml
#	jetty-alpn/jetty-alpn-conscrypt-server/pom.xml
#	jetty-alpn/jetty-alpn-java-client/pom.xml
#	jetty-alpn/jetty-alpn-java-server/pom.xml
#	jetty-alpn/jetty-alpn-openjdk8-client/pom.xml
#	jetty-alpn/jetty-alpn-openjdk8-server/pom.xml
#	jetty-alpn/jetty-alpn-server/pom.xml
#	jetty-alpn/pom.xml
#	jetty-annotations/pom.xml
#	jetty-ant/pom.xml
#	jetty-bom/pom.xml
#	jetty-cdi/cdi-2/pom.xml
#	jetty-cdi/cdi-core/pom.xml
#	jetty-cdi/cdi-full-servlet/pom.xml
#	jetty-cdi/cdi-servlet/pom.xml
#	jetty-cdi/cdi-websocket/pom.xml
#	jetty-cdi/pom.xml
#	jetty-cdi/test-cdi-webapp/pom.xml
#	jetty-client/pom.xml
#	jetty-continuation/pom.xml
#	jetty-deploy/pom.xml
#	jetty-distribution/pom.xml
#	jetty-documentation/pom.xml
#	jetty-fcgi/fcgi-client/pom.xml
#	jetty-fcgi/fcgi-server/pom.xml
#	jetty-fcgi/pom.xml
#	jetty-gcloud/jetty-gcloud-session-manager/pom.xml
#	jetty-gcloud/pom.xml
#	jetty-hazelcast/pom.xml
#	jetty-home/pom.xml
#	jetty-http-spi/pom.xml
#	jetty-http/pom.xml
#	jetty-http2/http2-alpn-tests/pom.xml
#	jetty-http2/http2-client/pom.xml
#	jetty-http2/http2-common/pom.xml
#	jetty-http2/http2-hpack/pom.xml
#	jetty-http2/http2-http-client-transport/pom.xml
#	jetty-http2/http2-server/pom.xml
#	jetty-http2/pom.xml
#	jetty-infinispan/pom.xml
#	jetty-io/pom.xml
#	jetty-jaas/pom.xml
#	jetty-jaspi/pom.xml
#	jetty-jmh/pom.xml
#	jetty-jmh/src/main/java/org/eclipse/jetty/http/jmh/MultiPartBenchmark.java
#	jetty-jmx/pom.xml
#	jetty-jndi/pom.xml
#	jetty-jspc-maven-plugin/pom.xml
#	jetty-maven-plugin/pom.xml
#	jetty-memcached/jetty-memcached-sessions/pom.xml
#	jetty-memcached/pom.xml
#	jetty-nosql/pom.xml
#	jetty-osgi/jetty-osgi-alpn/pom.xml
#	jetty-osgi/jetty-osgi-boot-jsp/pom.xml
#	jetty-osgi/jetty-osgi-boot-warurl/pom.xml
#	jetty-osgi/jetty-osgi-boot/pom.xml
#	jetty-osgi/jetty-osgi-httpservice/pom.xml
#	jetty-osgi/pom.xml
#	jetty-osgi/test-jetty-osgi-context/pom.xml
#	jetty-osgi/test-jetty-osgi-fragment/pom.xml
#	jetty-osgi/test-jetty-osgi-server/pom.xml
#	jetty-osgi/test-jetty-osgi-webapp/pom.xml
#	jetty-osgi/test-jetty-osgi/pom.xml
#	jetty-plus/pom.xml
#	jetty-proxy/pom.xml
#	jetty-quickstart/pom.xml
#	jetty-rewrite/pom.xml
#	jetty-runner/pom.xml
#	jetty-security/pom.xml
#	jetty-server/pom.xml
#	jetty-servlet/pom.xml
#	jetty-servlets/pom.xml
#	jetty-spring/pom.xml
#	jetty-start/pom.xml
#	jetty-unixsocket/pom.xml
#	jetty-util-ajax/pom.xml
#	jetty-util/pom.xml
#	jetty-webapp/pom.xml
#	jetty-websocket/javax-websocket-client-impl/pom.xml
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/AbstractJsrRemote.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/ClientContainer.java
#	jetty-websocket/javax-websocket-client-impl/src/main/java/org/eclipse/jetty/websocket/jsr356/annotations/JsrCallable.java
#	jetty-websocket/javax-websocket-server-impl/pom.xml
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/OnPartialTest.java
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/SessionTrackingTest.java
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/ConfiguredEchoSocket.java
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoAnnotatedSocket.java
#	jetty-websocket/javax-websocket-server-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/server/samples/echo/LargeEchoConfiguredSocket.java
#	jetty-websocket/jetty-websocket-tests/pom.xml
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/CloseTrackingEndpoint.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/BadNetworkTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientCloseTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientOpenSessionTracker.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientSessionsTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/ClientWriteThread.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/client/SlowClientTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ContainerEndpoint.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ServerCloseCreator.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/ServerCloseTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/java/org/eclipse/jetty/websocket/tests/server/SlowServerTest.java
#	jetty-websocket/jetty-websocket-tests/src/test/resources/jetty-logging.properties
#	jetty-websocket/pom.xml
#	jetty-websocket/websocket-api/pom.xml
#	jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/StatusCode.java
#	jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/WriteCallback.java
#	jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/IncomingFrames.java
#	jetty-websocket/websocket-client/pom.xml
#	jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketClient.java
#	jetty-websocket/websocket-client/src/main/java/org/eclipse/jetty/websocket/client/WebSocketUpgradeRequest.java
#	jetty-websocket/websocket-client/src/test/resources/jetty-logging.properties
#	jetty-websocket/websocket-common/pom.xml
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/LogicalConnection.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpoint.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/AbstractEventDriver.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/JettyAnnotatedEventDriver.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/AbstractExtension.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/identity/IdentityExtension.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FrameFlusher.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/FramePipes.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/DelegatedContainerScope.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/SimpleContainerScope.java
#	jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/scopes/WebSocketContainerScope.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ClosePayloadParserTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/GeneratorParserRoundtripTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ParserTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/PingPayloadParserTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/RFC6455ExamplesParserTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/TextPayloadParserTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/WebSocketRemoteEndpointTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_1.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase1_2.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase2.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/ab/TestABCase7_3.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/events/EventDriverTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/DummyIncomingFrames.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/DeflateFrameExtensionTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/FrameFlusherTest.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/io/LocalWebSocketConnection.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadConnection.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/DummyConnection.java
#	jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/IncomingFramesCapture.java
#	jetty-websocket/websocket-server/pom.xml
#	jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/WebSocketServerFactory.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdleTimeoutTest.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/SimpleServletServer.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketProtocolTest.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/ab/ABSocket.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/examples/echo/BigEchoSocket.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/SessionSocket.java
#	jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/misbehaving/MisbehavingClassTest.java
#	jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
#	jetty-websocket/websocket-servlet/pom.xml
#	jetty-xml/pom.xml
#	pom.xml
#	tests/pom.xml
#	tests/test-continuation/pom.xml
#	tests/test-distribution/pom.xml
#	tests/test-http-client-transport/pom.xml
#	tests/test-integration/pom.xml
#	tests/test-jmx/jmx-webapp-it/pom.xml
#	tests/test-jmx/jmx-webapp/pom.xml
#	tests/test-jmx/pom.xml
#	tests/test-loginservice/pom.xml
#	tests/test-quickstart/pom.xml
#	tests/test-sessions/pom.xml
#	tests/test-sessions/test-file-sessions/pom.xml
#	tests/test-sessions/test-gcloud-sessions/pom.xml
#	tests/test-sessions/test-hazelcast-sessions/pom.xml
#	tests/test-sessions/test-infinispan-sessions/pom.xml
#	tests/test-sessions/test-infinispan-sessions/src/test/java/org/eclipse/jetty/server/session/ClusteredSessionScavengingTest.java
#	tests/test-sessions/test-jdbc-sessions/pom.xml
#	tests/test-sessions/test-memcached-sessions/pom.xml
#	tests/test-sessions/test-mongodb-sessions/pom.xml
#	tests/test-sessions/test-sessions-common/pom.xml
#	tests/test-webapps/pom.xml
#	tests/test-webapps/test-http2-webapp/pom.xml
#	tests/test-webapps/test-jaas-webapp/pom.xml
#	tests/test-webapps/test-jetty-webapp/pom.xml
#	tests/test-webapps/test-jndi-webapp/pom.xml
#	tests/test-webapps/test-mock-resources/pom.xml
#	tests/test-webapps/test-proxy-webapp/pom.xml
#	tests/test-webapps/test-servlet-spec/pom.xml
#	tests/test-webapps/test-servlet-spec/test-container-initializer/pom.xml
#	tests/test-webapps/test-servlet-spec/test-spec-webapp/pom.xml
#	tests/test-webapps/test-servlet-spec/test-web-fragment/pom.xml
#	tests/test-webapps/test-simple-webapp/pom.xml
#	tests/test-webapps/test-webapp-rfc2616/pom.xml
This commit is contained in:
Joakim Erdfelt 2019-02-28 08:26:58 -05:00
commit ddc904f1f6
17 changed files with 771 additions and 372 deletions

10
Jenkinsfile vendored
View File

@ -50,6 +50,16 @@ pipeline {
} }
} }
stage("Build / Test - JDK12") {
agent { node { label 'linux' } }
options { timeout(time: 120, unit: 'MINUTES') }
steps {
mavenBuild("jdk12", "-Pmongodb install", "maven3", false)
warnings consoleParsers: [[parserName: 'Maven'], [parserName: 'Java']]
maven_invoker reportsFilenamePattern: "**/target/invoker-reports/BUILD*.xml", invokerBuildDir: "**/target/it"
}
}
stage("Build Javadoc") { stage("Build Javadoc") {
agent { node { label 'linux' } } agent { node { label 'linux' } }
options { timeout(time: 30, unit: 'MINUTES') } options { timeout(time: 30, unit: 'MINUTES') }

View File

@ -30,7 +30,6 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocket;
@ -50,7 +49,7 @@ import org.eclipse.jetty.util.thread.ExecutorThreadPool;
import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.condition.JRE;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
@ -139,12 +138,10 @@ public class HttpClientTLSTest
}); });
assertThrows(ExecutionException.class, () -> assertThrows(ExecutionException.class, () ->
{ client.newRequest("localhost", connector.getLocalPort())
client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString())
.scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS)
.timeout(5, TimeUnit.SECONDS) .send());
.send();
});
assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(serverLatch.await(1, TimeUnit.SECONDS));
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
@ -182,12 +179,10 @@ public class HttpClientTLSTest
}); });
assertThrows(ExecutionException.class, () -> assertThrows(ExecutionException.class, () ->
{ client.newRequest("localhost", connector.getLocalPort())
client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString())
.scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS)
.timeout(5, TimeUnit.SECONDS) .send());
.send();
});
assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(serverLatch.await(1, TimeUnit.SECONDS));
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
@ -226,24 +221,21 @@ public class HttpClientTLSTest
}); });
assertThrows(ExecutionException.class, () -> assertThrows(ExecutionException.class, () ->
{ client.newRequest("localhost", connector.getLocalPort())
client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString())
.scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS)
.timeout(5, TimeUnit.SECONDS) .send());
.send();
});
assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(serverLatch.await(1, TimeUnit.SECONDS));
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
} }
// In JDK 11, a mismatch on the client does not generate any bytes towards // In JDK 11+, a mismatch on the client does not generate any bytes towards
// the server, while in TLS 1.2 the client sends to the server the close_notify. // the server, while in previous JDKs the client sends to the server the close_notify.
@DisabledOnJre(JRE.JAVA_11) @EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10})
@Test @Test
public void testMismatchBetweenTLSProtocolAndTLSCiphersOnClient() throws Exception public void testMismatchBetweenTLSProtocolAndTLSCiphersOnClient() throws Exception
{ {
SslContextFactory serverTLSFactory = createSslContextFactory(); SslContextFactory serverTLSFactory = createSslContextFactory();
startServer(serverTLSFactory, new EmptyServerHandler()); startServer(serverTLSFactory, new EmptyServerHandler());
@ -274,12 +266,10 @@ public class HttpClientTLSTest
}); });
assertThrows(ExecutionException.class, () -> assertThrows(ExecutionException.class, () ->
{ client.newRequest("localhost", connector.getLocalPort())
client.newRequest("localhost", connector.getLocalPort()) .scheme(HttpScheme.HTTPS.asString())
.scheme(HttpScheme.HTTPS.asString()) .timeout(5, TimeUnit.SECONDS)
.timeout(5, TimeUnit.SECONDS) .send());
.send();
});
assertTrue(serverLatch.await(1, TimeUnit.SECONDS)); assertTrue(serverLatch.await(1, TimeUnit.SECONDS));
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
@ -321,8 +311,9 @@ public class HttpClientTLSTest
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
} }
// Excluded because of a bug in JDK 11+27 where session resumption does not work. // Excluded in JDK 11+ because resumed sessions cannot be compared
@DisabledOnJre(JRE.JAVA_11) // using their session IDs even though they are resumed correctly.
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10})
@Test @Test
public void testHandshakeSucceededWithSessionResumption() throws Exception public void testHandshakeSucceededWithSessionResumption() throws Exception
{ {
@ -400,8 +391,9 @@ public class HttpClientTLSTest
assertTrue(clientLatch.await(1, TimeUnit.SECONDS)); assertTrue(clientLatch.await(1, TimeUnit.SECONDS));
} }
// Excluded because of a bug in JDK 11+27 where session resumption does not work. // Excluded in JDK 11+ because resumed sessions cannot be compared
@DisabledOnJre(JRE.JAVA_11) // using their session IDs even though they are resumed correctly.
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10})
@Test @Test
public void testClientRawCloseDoesNotInvalidateSession() throws Exception public void testClientRawCloseDoesNotInvalidateSession() throws Exception
{ {

View File

@ -20,6 +20,7 @@
=== Managing Jetty Base and Jetty Home === Managing Jetty Base and Jetty Home
Instead of managing multiple Jetty implementations out of several different distribution locations, it is possible to maintain a separation between the binary installation of the standalone Jetty (known as `${jetty.home}`), and the customizations for your specific environment(s) (known as `${jetty.base}`). Instead of managing multiple Jetty implementations out of several different distribution locations, it is possible to maintain a separation between the binary installation of the standalone Jetty (known as `${jetty.home}`), and the customizations for your specific environment(s) (known as `${jetty.base}`).
In addition to easy management of multiple server instances, is allows for quick, drop-in upgrades of Jetty.
There should always only be *one* Jetty Home (per version of Jetty), but there can be multiple Jetty Base directories that reference it. There should always only be *one* Jetty Home (per version of Jetty), but there can be multiple Jetty Base directories that reference it.
Jetty Base:: Jetty Base::

View File

@ -44,7 +44,7 @@ In either case the syntax of the XML file is the same:
==== For All Apps on a Server ==== For All Apps on a Server
Set an attribute on the Server instance for which you want to modify the maximum form content size: Set an attribute in `jetty.xml` on the Server instance for which you want to modify the maximum form content size:
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
---- ----
@ -56,7 +56,32 @@ Set an attribute on the Server instance for which you want to modify the maximum
</Configure> </Configure>
---- ----
____
[IMPORTANT]
It is important to remember that you should *not* modify the XML files in your `$JETTY_HOME`.
If you do for some reason feel you want to change the way an XML file operates, it is best to make a copy of it in your `$JETTY_BASE` in an `/etc` directory.
Jetty will always look first to the `$JETTY_BASE` for configuration.
____
==== For All Apps in the JVM ==== For All Apps in the JVM
Use the system property `org.eclipse.jetty.server.Request.maxFormContentSize`. Use the system property `org.eclipse.jetty.server.Request.maxFormContentSize`.
This can be set on the command line or in the `start.ini` or `start.d\server.ini` file. This can be set on the command line or in the `$JETTY_BASE\start.ini` or any `$JETTY_BASE\start.d\*.ini` link:#startup-modules[module ini file.]
Using `$JETTY_BASE\start.d\server.ini` as an example:
[source, console, subs="{sub-order}"]
----
# ---------------------------------------
# Module: server
# Enables the core Jetty server on the classpath.
# ---------------------------------------
--module=server
### Common HTTP configuration
## Scheme to use to build URIs for secure redirects
# jetty.httpConfig.secureScheme=https
...
-Dorg.eclipse.jetty.server.Request.maxFormContentSize=200000
----

View File

@ -0,0 +1,108 @@
//
// ========================================================================
// Copyright (c) 1995-2019 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.io;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
@ManagedObject
abstract class AbstractByteBufferPool implements ByteBufferPool
{
private final int _factor;
private final int _maxQueueLength;
private final long _maxHeapMemory;
private final AtomicLong _heapMemory = new AtomicLong();
private final long _maxDirectMemory;
private final AtomicLong _directMemory = new AtomicLong();
protected AbstractByteBufferPool(int factor, int maxQueueLength, long maxHeapMemory, long maxDirectMemory)
{
_factor = factor <= 0 ? 1024 : factor;
_maxQueueLength = maxQueueLength;
_maxHeapMemory = maxHeapMemory;
_maxDirectMemory = maxDirectMemory;
}
protected int getCapacityFactor()
{
return _factor;
}
protected int getMaxQueueLength()
{
return _maxQueueLength;
}
protected void decrementMemory(ByteBuffer buffer)
{
updateMemory(buffer, false);
}
protected void incrementMemory(ByteBuffer buffer)
{
updateMemory(buffer, true);
}
private void updateMemory(ByteBuffer buffer, boolean addOrSub)
{
AtomicLong memory = buffer.isDirect() ? _directMemory : _heapMemory;
int capacity = buffer.capacity();
memory.addAndGet(addOrSub ? capacity : -capacity);
}
protected void releaseExcessMemory(boolean direct, Consumer<Boolean> clearFn)
{
long maxMemory = direct ? _maxDirectMemory : _maxHeapMemory;
if (maxMemory > 0)
{
while (getMemory(direct) > maxMemory)
clearFn.accept(direct);
}
}
@ManagedAttribute("The bytes retained by direct ByteBuffers")
public long getDirectMemory()
{
return getMemory(true);
}
@ManagedAttribute("The bytes retained by heap ByteBuffers")
public long getHeapMemory()
{
return getMemory(false);
}
public long getMemory(boolean direct)
{
AtomicLong memory = direct ? _directMemory : _heapMemory;
return memory.get();
}
@ManagedOperation(value = "Clears this ByteBufferPool", impact = "ACTION")
public void clear()
{
_heapMemory.set(0);
_directMemory.set(0);
}
}

View File

@ -19,96 +19,205 @@
package org.eclipse.jetty.io; package org.eclipse.jetty.io;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.IntFunction;
public class ArrayByteBufferPool implements ByteBufferPool import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
/**
* <p>A ByteBuffer pool where ByteBuffers are held in queues that are held in array elements.</p>
* <p>Given a capacity {@code factor} of 1024, the first array element holds a queue of ByteBuffers
* each of capacity 1024, the second array element holds a queue of ByteBuffers each of capacity
* 2048, and so on.</p>
*/
@ManagedObject
public class ArrayByteBufferPool extends AbstractByteBufferPool
{ {
private final int _min; private final int _minCapacity;
private final int _maxQueue;
private final ByteBufferPool.Bucket[] _direct; private final ByteBufferPool.Bucket[] _direct;
private final ByteBufferPool.Bucket[] _indirect; private final ByteBufferPool.Bucket[] _indirect;
private final int _inc;
/**
* Creates a new ArrayByteBufferPool with a default configuration.
*/
public ArrayByteBufferPool() public ArrayByteBufferPool()
{ {
this(-1,-1,-1,-1); this(-1, -1, -1);
} }
public ArrayByteBufferPool(int minSize, int increment, int maxSize) /**
* Creates a new ArrayByteBufferPool with the given configuration.
*
* @param minCapacity the minimum ByteBuffer capacity
* @param factor the capacity factor
* @param maxCapacity the maximum ByteBuffer capacity
*/
public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity)
{ {
this(minSize,increment,maxSize,-1); this(minCapacity, factor, maxCapacity, -1, -1, -1);
} }
public ArrayByteBufferPool(int minSize, int increment, int maxSize, int maxQueue) /**
* Creates a new ArrayByteBufferPool with the given configuration.
*
* @param minCapacity the minimum ByteBuffer capacity
* @param factor the capacity factor
* @param maxCapacity the maximum ByteBuffer capacity
* @param maxQueueLength the maximum ByteBuffer queue length
*/
public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength)
{ {
if (minSize<=0) this(minCapacity, factor, maxCapacity, maxQueueLength, -1, -1);
minSize=0; }
if (increment<=0)
increment=1024;
if (maxSize<=0)
maxSize=64*1024;
if (minSize>=increment)
throw new IllegalArgumentException("minSize >= increment");
if ((maxSize%increment)!=0 || increment>=maxSize)
throw new IllegalArgumentException("increment must be a divisor of maxSize");
_min=minSize;
_inc=increment;
_direct=new ByteBufferPool.Bucket[maxSize/increment]; /**
_indirect=new ByteBufferPool.Bucket[maxSize/increment]; * Creates a new ArrayByteBufferPool with the given configuration.
_maxQueue=maxQueue; *
* @param minCapacity the minimum ByteBuffer capacity
* @param factor the capacity factor
* @param maxCapacity the maximum ByteBuffer capacity
* @param maxQueueLength the maximum ByteBuffer queue length
* @param maxHeapMemory the max heap memory in bytes
* @param maxDirectMemory the max direct memory in bytes
*/
public ArrayByteBufferPool(int minCapacity, int factor, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory)
{
super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory);
int size=0; factor = getCapacityFactor();
for (int i=0;i<_direct.length;i++) if (minCapacity <= 0)
{ minCapacity = 0;
size+=_inc; if (maxCapacity <= 0)
_direct[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); maxCapacity = 64 * 1024;
_indirect[i]=new ByteBufferPool.Bucket(this,size,_maxQueue); if ((maxCapacity % factor) != 0 || factor >= maxCapacity)
} throw new IllegalArgumentException("The capacity factor must be a divisor of maxCapacity");
_minCapacity = minCapacity;
int length = maxCapacity / factor;
_direct = new ByteBufferPool.Bucket[length];
_indirect = new ByteBufferPool.Bucket[length];
} }
@Override @Override
public ByteBuffer acquire(int size, boolean direct) public ByteBuffer acquire(int size, boolean direct)
{ {
ByteBufferPool.Bucket bucket = bucketFor(size,direct); int capacity = size < _minCapacity ? size : (bucketFor(size) + 1) * getCapacityFactor();
if (bucket==null) ByteBufferPool.Bucket bucket = bucketFor(size, direct, null);
return newByteBuffer(size,direct); if (bucket == null)
return newByteBuffer(capacity, direct);
return bucket.acquire(direct); ByteBuffer buffer = bucket.acquire();
if (buffer == null)
return newByteBuffer(capacity, direct);
decrementMemory(buffer);
return buffer;
} }
@Override @Override
public void release(ByteBuffer buffer) public void release(ByteBuffer buffer)
{ {
if (buffer!=null) if (buffer == null)
return;
boolean direct = buffer.isDirect();
ByteBufferPool.Bucket bucket = bucketFor(buffer.capacity(), direct, this::newBucket);
if (bucket != null)
{ {
ByteBufferPool.Bucket bucket = bucketFor(buffer.capacity(),buffer.isDirect()); bucket.release(buffer);
if (bucket!=null) incrementMemory(buffer);
bucket.release(buffer); releaseExcessMemory(direct, this::clearOldestBucket);
} }
} }
private Bucket newBucket(int key)
{
return new Bucket(this, key * getCapacityFactor(), getMaxQueueLength());
}
@Override
public void clear() public void clear()
{ {
for (int i=0;i<_direct.length;i++) super.clear();
for (int i = 0; i < _direct.length; ++i)
{ {
_direct[i].clear(); Bucket bucket = _direct[i];
_indirect[i].clear(); if (bucket != null)
bucket.clear();
_direct[i] = null;
bucket = _indirect[i];
if (bucket != null)
bucket.clear();
_indirect[i] = null;
} }
} }
private ByteBufferPool.Bucket bucketFor(int size,boolean direct) private void clearOldestBucket(boolean direct)
{ {
if (size<=_min) long oldest = Long.MAX_VALUE;
return null; int index = -1;
int b=(size-1)/_inc; Bucket[] buckets = bucketsFor(direct);
if (b>=_direct.length) for (int i = 0; i < buckets.length; ++i)
return null; {
ByteBufferPool.Bucket bucket = direct?_direct[b]:_indirect[b]; Bucket bucket = buckets[i];
if (bucket == null)
continue;
long lastUpdate = bucket.getLastUpdate();
if (lastUpdate < oldest)
{
oldest = lastUpdate;
index = i;
}
}
if (index >= 0)
{
Bucket bucket = buckets[index];
buckets[index] = null;
// The same bucket may be concurrently
// removed, so we need this null guard.
if (bucket != null)
bucket.clear(this::decrementMemory);
}
}
private int bucketFor(int capacity)
{
return (capacity - 1) / getCapacityFactor();
}
private ByteBufferPool.Bucket bucketFor(int capacity, boolean direct, IntFunction<Bucket> newBucket)
{
if (capacity < _minCapacity)
return null;
int b = bucketFor(capacity);
if (b >= _direct.length)
return null;
Bucket[] buckets = bucketsFor(direct);
Bucket bucket = buckets[b];
if (bucket == null && newBucket != null)
buckets[b] = bucket = newBucket.apply(b + 1);
return bucket; return bucket;
} }
@ManagedAttribute("The number of pooled direct ByteBuffers")
public long getDirectByteBufferCount()
{
return getByteBufferCount(true);
}
@ManagedAttribute("The number of pooled heap ByteBuffers")
public long getHeapByteBufferCount()
{
return getByteBufferCount(false);
}
private long getByteBufferCount(boolean direct)
{
return Arrays.stream(bucketsFor(direct))
.filter(Objects::nonNull)
.mapToLong(Bucket::size)
.sum();
}
// Package local for testing // Package local for testing
ByteBufferPool.Bucket[] bucketsFor(boolean direct) ByteBufferPool.Bucket[] bucketsFor(boolean direct)
{ {

View File

@ -24,6 +24,7 @@ import java.util.Deque;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
@ -56,6 +57,13 @@ public interface ByteBufferPool
*/ */
public void release(ByteBuffer buffer); public void release(ByteBuffer buffer);
/**
* <p>Creates a new ByteBuffer of the given capacity and the given directness.</p>
*
* @param capacity the ByteBuffer capacity
* @param direct the ByteBuffer directness
* @return a newly allocated ByteBuffer
*/
default ByteBuffer newByteBuffer(int capacity, boolean direct) default ByteBuffer newByteBuffer(int capacity, boolean direct)
{ {
return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity); return direct ? BufferUtil.allocateDirect(capacity) : BufferUtil.allocate(capacity);
@ -124,54 +132,80 @@ public interface ByteBufferPool
} }
} }
class Bucket public static class Bucket
{ {
private final Deque<ByteBuffer> _queue = new ConcurrentLinkedDeque<>(); private final Deque<ByteBuffer> _queue = new ConcurrentLinkedDeque<>();
private final ByteBufferPool _pool; private final ByteBufferPool _pool;
private final int _capacity; private final int _capacity;
private final AtomicInteger _space; private final int _maxSize;
private final AtomicInteger _size;
private long _lastUpdate = System.nanoTime();
public Bucket(ByteBufferPool pool, int bufferSize, int maxSize) public Bucket(ByteBufferPool pool, int capacity, int maxSize)
{ {
_pool = pool; _pool = pool;
_capacity = bufferSize; _capacity = capacity;
_space = maxSize > 0 ? new AtomicInteger(maxSize) : null; _maxSize = maxSize;
_size = maxSize > 0 ? new AtomicInteger() : null;
} }
public ByteBuffer acquire()
{
ByteBuffer buffer = queuePoll();
if (buffer == null)
return null;
if (_size != null)
_size.decrementAndGet();
return buffer;
}
/**
* @param direct whether to create a direct buffer when none is available
* @return a ByteBuffer
* @deprecated use {@link #acquire()} instead
*/
@Deprecated
public ByteBuffer acquire(boolean direct) public ByteBuffer acquire(boolean direct)
{ {
ByteBuffer buffer = queuePoll(); ByteBuffer buffer = queuePoll();
if (buffer == null) if (buffer == null)
return _pool.newByteBuffer(_capacity, direct); return _pool.newByteBuffer(_capacity, direct);
if (_space != null) if (_size != null)
_space.incrementAndGet(); _size.decrementAndGet();
return buffer; return buffer;
} }
public void release(ByteBuffer buffer) public void release(ByteBuffer buffer)
{ {
_lastUpdate = System.nanoTime();
BufferUtil.clear(buffer); BufferUtil.clear(buffer);
if (_space == null) if (_size == null)
queueOffer(buffer); queueOffer(buffer);
else if (_space.decrementAndGet() >= 0) else if (_size.incrementAndGet() <= _maxSize)
queueOffer(buffer); queueOffer(buffer);
else else
_space.incrementAndGet(); _size.decrementAndGet();
} }
public void clear() public void clear()
{ {
if (_space == null) clear(null);
}
void clear(Consumer<ByteBuffer> memoryFn)
{
int size = _size == null ? 0 : _size.get() - 1;
while (size >= 0)
{ {
queueClear(); ByteBuffer buffer = queuePoll();
} if (buffer == null)
else break;
{ if (memoryFn != null)
int s = _space.getAndSet(0); memoryFn.accept(buffer);
while (s-- > 0) if (_size != null)
{ {
if (queuePoll() == null) _size.decrementAndGet();
_space.incrementAndGet(); --size;
} }
} }
} }
@ -186,11 +220,6 @@ public interface ByteBufferPool
return _queue.poll(); return _queue.poll();
} }
private void queueClear()
{
_queue.clear();
}
boolean isEmpty() boolean isEmpty()
{ {
return _queue.isEmpty(); return _queue.isEmpty();
@ -201,10 +230,15 @@ public interface ByteBufferPool
return _queue.size(); return _queue.size();
} }
long getLastUpdate()
{
return _lastUpdate;
}
@Override @Override
public String toString() public String toString()
{ {
return String.format("Bucket@%x{%d/%d}", hashCode(), size(), _capacity); return String.format("%s@%x{%d/%d@%d}", getClass().getSimpleName(), hashCode(), size(), _maxSize, _capacity);
} }
} }
} }

View File

@ -19,51 +19,104 @@
package org.eclipse.jetty.io; package org.eclipse.jetty.io;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function; import java.util.function.Function;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
public class MappedByteBufferPool implements ByteBufferPool /**
* <p>A ByteBuffer pool where ByteBuffers are held in queues that are held in a Map.</p>
* <p>Given a capacity {@code factor} of 1024, the Map entry with key {@code 1} holds a
* queue of ByteBuffers each of capacity 1024, the Map entry with key {@code 2} holds a
* queue of ByteBuffers each of capacity 2048, and so on.</p>
*/
@ManagedObject
public class MappedByteBufferPool extends AbstractByteBufferPool
{ {
private final ConcurrentMap<Integer, Bucket> directBuffers = new ConcurrentHashMap<>(); private final ConcurrentMap<Integer, Bucket> _directBuffers = new ConcurrentHashMap<>();
private final ConcurrentMap<Integer, Bucket> heapBuffers = new ConcurrentHashMap<>(); private final ConcurrentMap<Integer, Bucket> _heapBuffers = new ConcurrentHashMap<>();
private final int _factor;
private final Function<Integer, Bucket> _newBucket; private final Function<Integer, Bucket> _newBucket;
/**
* Creates a new MappedByteBufferPool with a default configuration.
*/
public MappedByteBufferPool() public MappedByteBufferPool()
{ {
this(-1); this(-1);
} }
/**
* Creates a new MappedByteBufferPool with the given capacity factor.
*
* @param factor the capacity factor
*/
public MappedByteBufferPool(int factor) public MappedByteBufferPool(int factor)
{ {
this(factor,-1,null); this(factor, -1);
} }
public MappedByteBufferPool(int factor,int maxQueue) /**
* Creates a new MappedByteBufferPool with the given configuration.
*
* @param factor the capacity factor
* @param maxQueueLength the maximum ByteBuffer queue length
*/
public MappedByteBufferPool(int factor, int maxQueueLength)
{ {
this(factor,maxQueue,null); this(factor, maxQueueLength, null);
} }
public MappedByteBufferPool(int factor,int maxQueue,Function<Integer, Bucket> newBucket) /**
* Creates a new MappedByteBufferPool with the given configuration.
*
* @param factor the capacity factor
* @param maxQueueLength the maximum ByteBuffer queue length
* @param newBucket the function that creates a Bucket
*/
public MappedByteBufferPool(int factor, int maxQueueLength, Function<Integer, Bucket> newBucket)
{ {
_factor = factor<=0?1024:factor; this(factor, maxQueueLength, newBucket, -1, -1);
_newBucket = newBucket!=null?newBucket:i->new Bucket(this,i*_factor,maxQueue); }
/**
* Creates a new MappedByteBufferPool with the given configuration.
*
* @param factor the capacity factor
* @param maxQueueLength the maximum ByteBuffer queue length
* @param newBucket the function that creates a Bucket
* @param maxHeapMemory the max heap memory in bytes
* @param maxDirectMemory the max direct memory in bytes
*/
public MappedByteBufferPool(int factor, int maxQueueLength, Function<Integer, Bucket> newBucket, long maxHeapMemory, long maxDirectMemory)
{
super(factor, maxQueueLength, maxHeapMemory, maxDirectMemory);
_newBucket = newBucket != null ? newBucket : this::newBucket;
}
private Bucket newBucket(int key)
{
return new Bucket(this, key * getCapacityFactor(), getMaxQueueLength());
} }
@Override @Override
public ByteBuffer acquire(int size, boolean direct) public ByteBuffer acquire(int size, boolean direct)
{ {
int b = bucketFor(size); int b = bucketFor(size);
int capacity = b * getCapacityFactor();
ConcurrentMap<Integer, Bucket> buffers = bucketsFor(direct); ConcurrentMap<Integer, Bucket> buffers = bucketsFor(direct);
Bucket bucket = buffers.get(b); Bucket bucket = buffers.get(b);
if (bucket==null) if (bucket == null)
return newByteBuffer(b*_factor, direct); return newByteBuffer(capacity, direct);
return bucket.acquire(direct); ByteBuffer buffer = bucket.acquire();
if (buffer == null)
return newByteBuffer(capacity, direct);
decrementMemory(buffer);
return buffer;
} }
@Override @Override
@ -72,36 +125,86 @@ public class MappedByteBufferPool implements ByteBufferPool
if (buffer == null) if (buffer == null)
return; // nothing to do return; // nothing to do
// validate that this buffer is from this pool int capacity = buffer.capacity();
assert((buffer.capacity() % _factor) == 0); // Validate that this buffer is from this pool.
assert ((capacity % getCapacityFactor()) == 0);
int b = bucketFor(buffer.capacity()); int b = bucketFor(capacity);
ConcurrentMap<Integer, Bucket> buckets = bucketsFor(buffer.isDirect()); boolean direct = buffer.isDirect();
ConcurrentMap<Integer, Bucket> buckets = bucketsFor(direct);
Bucket bucket = buckets.computeIfAbsent(b,_newBucket); Bucket bucket = buckets.computeIfAbsent(b, _newBucket);
bucket.release(buffer); bucket.release(buffer);
incrementMemory(buffer);
releaseExcessMemory(direct, this::clearOldestBucket);
} }
@Override
public void clear() public void clear()
{ {
directBuffers.values().forEach(Bucket::clear); super.clear();
directBuffers.clear(); _directBuffers.values().forEach(Bucket::clear);
heapBuffers.values().forEach(Bucket::clear); _directBuffers.clear();
heapBuffers.clear(); _heapBuffers.values().forEach(Bucket::clear);
_heapBuffers.clear();
}
private void clearOldestBucket(boolean direct)
{
long oldest = Long.MAX_VALUE;
int index = -1;
ConcurrentMap<Integer, Bucket> buckets = bucketsFor(direct);
for (Map.Entry<Integer, Bucket> entry : buckets.entrySet())
{
Bucket bucket = entry.getValue();
long lastUpdate = bucket.getLastUpdate();
if (lastUpdate < oldest)
{
oldest = lastUpdate;
index = entry.getKey();
}
}
if (index >= 0)
{
Bucket bucket = buckets.remove(index);
// The same bucket may be concurrently
// removed, so we need this null guard.
if (bucket != null)
bucket.clear(this::decrementMemory);
}
} }
private int bucketFor(int size) private int bucketFor(int size)
{ {
int bucket = size / _factor; int factor = getCapacityFactor();
if (size % _factor > 0) int bucket = size / factor;
if (bucket * factor != size)
++bucket; ++bucket;
return bucket; return bucket;
} }
@ManagedAttribute("The number of pooled direct ByteBuffers")
public long getDirectByteBufferCount()
{
return getByteBufferCount(true);
}
@ManagedAttribute("The number of pooled heap ByteBuffers")
public long getHeapByteBufferCount()
{
return getByteBufferCount(false);
}
private long getByteBufferCount(boolean direct)
{
return bucketsFor(direct).values().stream()
.mapToLong(Bucket::size)
.sum();
}
// Package local for testing // Package local for testing
ConcurrentMap<Integer, Bucket> bucketsFor(boolean direct) ConcurrentMap<Integer, Bucket> bucketsFor(boolean direct)
{ {
return direct ? directBuffers : heapBuffers; return direct ? _directBuffers : _heapBuffers;
} }
public static class Tagged extends MappedByteBufferPool public static class Tagged extends MappedByteBufferPool

View File

@ -18,76 +18,60 @@
package org.eclipse.jetty.io; package org.eclipse.jetty.io;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.Objects;
import org.eclipse.jetty.io.ByteBufferPool.Bucket; import org.eclipse.jetty.io.ByteBufferPool.Bucket;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@SuppressWarnings("ReferenceEquality") import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ArrayByteBufferPoolTest public class ArrayByteBufferPoolTest
{ {
@Test @Test
public void testMinimumRelease() throws Exception public void testMinimumRelease()
{ {
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000);
ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true);
for (int size=1;size<=9;size++) for (int size = 1; size <= 9; size++)
{ {
ByteBuffer buffer = bufferPool.acquire(size, true); ByteBuffer buffer = bufferPool.acquire(size, true);
assertTrue(buffer.isDirect()); assertTrue(buffer.isDirect());
assertEquals(size,buffer.capacity()); assertEquals(size, buffer.capacity());
for (ByteBufferPool.Bucket bucket : buckets)
assertTrue(bucket.isEmpty());
bufferPool.release(buffer);
for (ByteBufferPool.Bucket bucket : buckets)
assertTrue(bucket.isEmpty());
}
}
@Test
public void testMaxRelease() throws Exception
{
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000);
ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true);
for (int size=999;size<=1001;size++)
{
bufferPool.clear();
ByteBuffer buffer = bufferPool.acquire(size, true);
assertTrue(buffer.isDirect());
assertThat(buffer.capacity(),greaterThanOrEqualTo(size));
for (ByteBufferPool.Bucket bucket : buckets)
assertTrue(bucket.isEmpty());
bufferPool.release(buffer);
int pooled=0;
for (ByteBufferPool.Bucket bucket : buckets) for (ByteBufferPool.Bucket bucket : buckets)
{ {
pooled+=bucket.size(); if (bucket != null)
assertTrue(bucket.isEmpty());
}
bufferPool.release(buffer);
for (ByteBufferPool.Bucket bucket : buckets)
{
if (bucket != null)
assertTrue(bucket.isEmpty());
} }
assertEquals(size<=1000,1==pooled);
} }
} }
@Test @Test
public void testAcquireRelease() throws Exception public void testMaxRelease()
{ {
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000);
ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true);
for (int size=390;size<=510;size++) for (int size = 999; size <= 1001; size++)
{ {
bufferPool.clear(); bufferPool.clear();
ByteBuffer buffer = bufferPool.acquire(size, true); ByteBuffer buffer = bufferPool.acquire(size, true);
@ -95,32 +79,57 @@ public class ArrayByteBufferPoolTest
assertTrue(buffer.isDirect()); assertTrue(buffer.isDirect());
assertThat(buffer.capacity(), greaterThanOrEqualTo(size)); assertThat(buffer.capacity(), greaterThanOrEqualTo(size));
for (ByteBufferPool.Bucket bucket : buckets) for (ByteBufferPool.Bucket bucket : buckets)
assertTrue(bucket.isEmpty()); {
if (bucket != null)
assertTrue(bucket.isEmpty());
}
bufferPool.release(buffer); bufferPool.release(buffer);
int pooled=0; int pooled = Arrays.stream(buckets)
for (ByteBufferPool.Bucket bucket : buckets) .filter(Objects::nonNull)
{ .mapToInt(Bucket::size)
if (!bucket.isEmpty()) .sum();
{ assertEquals(size <= 1000, 1 == pooled);
pooled+=bucket.size();
// TODO assertThat(bucket._bufferSize,greaterThanOrEqualTo(size));
// TODO assertThat(bucket._bufferSize,Matchers.lessThan(size+100));
}
}
assertEquals(1,pooled);
} }
} }
@Test @Test
@SuppressWarnings("ReferenceEquality") public void testAcquireRelease()
public void testAcquireReleaseAcquire() throws Exception
{ {
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10,100,1000); ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000);
ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true); ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true);
for (int size=390;size<=510;size++) for (int size = 390; size <= 510; size++)
{
bufferPool.clear();
ByteBuffer buffer = bufferPool.acquire(size, true);
assertTrue(buffer.isDirect());
assertThat(buffer.capacity(), greaterThanOrEqualTo(size));
for (ByteBufferPool.Bucket bucket : buckets)
{
if (bucket != null)
assertTrue(bucket.isEmpty());
}
bufferPool.release(buffer);
int pooled = Arrays.stream(buckets)
.filter(Objects::nonNull)
.mapToInt(Bucket::size)
.sum();
assertEquals(1, pooled);
}
}
@Test
public void testAcquireReleaseAcquire()
{
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(10, 100, 1000);
ByteBufferPool.Bucket[] buckets = bufferPool.bucketsFor(true);
for (int size = 390; size <= 510; size++)
{ {
bufferPool.clear(); bufferPool.clear();
ByteBuffer buffer1 = bufferPool.acquire(size, true); ByteBuffer buffer1 = bufferPool.acquire(size, true);
@ -130,38 +139,37 @@ public class ArrayByteBufferPoolTest
ByteBuffer buffer3 = bufferPool.acquire(size, false); ByteBuffer buffer3 = bufferPool.acquire(size, false);
bufferPool.release(buffer3); bufferPool.release(buffer3);
int pooled=0; int pooled = Arrays.stream(buckets)
for (ByteBufferPool.Bucket bucket : buckets) .filter(Objects::nonNull)
{ .mapToInt(Bucket::size)
if (!bucket.isEmpty()) .sum();
{ assertEquals(1, pooled);
pooled+=bucket.size();
// TODO assertThat(bucket._bufferSize,greaterThanOrEqualTo(size));
// TODO assertThat(bucket._bufferSize,Matchers.lessThan(size+100));
}
}
assertEquals(1,pooled);
assertTrue(buffer1==buffer2); assertSame(buffer1, buffer2);
assertTrue(buffer1!=buffer3); assertNotSame(buffer1, buffer3);
} }
} }
@Test @Test
public void testMaxQueue() throws Exception public void testMaxQueue()
{ {
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1,-1,-1,2); ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1, -1, -1, 2);
ByteBuffer buffer1 = bufferPool.acquire(512, false); ByteBuffer buffer1 = bufferPool.acquire(512, false);
ByteBuffer buffer2 = bufferPool.acquire(512, false); ByteBuffer buffer2 = bufferPool.acquire(512, false);
ByteBuffer buffer3 = bufferPool.acquire(512, false); ByteBuffer buffer3 = bufferPool.acquire(512, false);
Bucket[] buckets = bufferPool.bucketsFor(false); Bucket[] buckets = bufferPool.bucketsFor(false);
Arrays.asList(buckets).forEach(b->assertEquals(0,b.size())); Arrays.stream(buckets)
.filter(Objects::nonNull)
.forEach(b -> assertEquals(0, b.size()));
bufferPool.release(buffer1); bufferPool.release(buffer1);
Bucket bucket=Arrays.asList(buckets).stream().filter(b->b.size()>0).findFirst().get(); Bucket bucket = Arrays.stream(buckets)
.filter(Objects::nonNull)
.filter(b -> b.size() > 0)
.findFirst()
.orElseThrow(AssertionError::new);
assertEquals(1, bucket.size()); assertEquals(1, bucket.size());
bufferPool.release(buffer2); bufferPool.release(buffer2);
@ -171,4 +179,40 @@ public class ArrayByteBufferPoolTest
assertEquals(2, bucket.size()); assertEquals(2, bucket.size());
} }
@Test
public void testMaxMemory()
{
int factor = 1024;
int maxMemory = 11 * 1024;
ArrayByteBufferPool bufferPool = new ArrayByteBufferPool(-1, factor, -1, -1, -1, maxMemory);
Bucket[] buckets = bufferPool.bucketsFor(true);
// Create the buckets - the oldest is the larger.
// 1+2+3+4=10 / maxMemory=11.
for (int i = 4; i >= 1; --i)
{
int capacity = factor * i;
ByteBuffer buffer = bufferPool.acquire(capacity, true);
bufferPool.release(buffer);
}
// Create and release a buffer to exceed the max memory.
ByteBuffer buffer = bufferPool.newByteBuffer(2 * factor, true);
bufferPool.release(buffer);
// Now the oldest buffer should be gone and we have: 1+2x2+3=8
long memory = bufferPool.getMemory(true);
assertThat(memory, lessThan((long)maxMemory));
assertNull(buckets[3]);
// Create and release a large buffer.
// Max memory is exceeded and buckets 3 and 1 are cleared.
// We will have 2x2+7=11.
buffer = bufferPool.newByteBuffer(7 * factor, true);
bufferPool.release(buffer);
memory = bufferPool.getMemory(true);
assertThat(memory, lessThanOrEqualTo((long)maxMemory));
assertNull(buckets[0]);
assertNull(buckets[2]);
}
} }

View File

@ -26,21 +26,24 @@ import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.lessThan;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertSame;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
public class MappedByteBufferPoolTest public class MappedByteBufferPoolTest
{ {
@Test @Test
public void testAcquireRelease() throws Exception public void testAcquireRelease()
{ {
MappedByteBufferPool bufferPool = new MappedByteBufferPool(); MappedByteBufferPool bufferPool = new MappedByteBufferPool();
ConcurrentMap<Integer,Bucket> buckets = bufferPool.bucketsFor(true); ConcurrentMap<Integer, Bucket> buckets = bufferPool.bucketsFor(true);
int size = 512; int size = 512;
ByteBuffer buffer = bufferPool.acquire(size, true); ByteBuffer buffer = bufferPool.acquire(size, true);
@ -56,10 +59,10 @@ public class MappedByteBufferPoolTest
} }
@Test @Test
public void testAcquireReleaseAcquire() throws Exception public void testAcquireReleaseAcquire()
{ {
MappedByteBufferPool bufferPool = new MappedByteBufferPool(); MappedByteBufferPool bufferPool = new MappedByteBufferPool();
ConcurrentMap<Integer,Bucket> buckets = bufferPool.bucketsFor(false); ConcurrentMap<Integer, Bucket> buckets = bufferPool.bucketsFor(false);
ByteBuffer buffer1 = bufferPool.acquire(512, false); ByteBuffer buffer1 = bufferPool.acquire(512, false);
bufferPool.release(buffer1); bufferPool.release(buffer1);
@ -76,10 +79,10 @@ public class MappedByteBufferPoolTest
} }
@Test @Test
public void testAcquireReleaseClear() throws Exception public void testAcquireReleaseClear()
{ {
MappedByteBufferPool bufferPool = new MappedByteBufferPool(); MappedByteBufferPool bufferPool = new MappedByteBufferPool();
ConcurrentMap<Integer,Bucket> buckets = bufferPool.bucketsFor(true); ConcurrentMap<Integer, Bucket> buckets = bufferPool.bucketsFor(true);
ByteBuffer buffer = bufferPool.acquire(512, true); ByteBuffer buffer = bufferPool.acquire(512, true);
bufferPool.release(buffer); bufferPool.release(buffer);
@ -96,11 +99,9 @@ public class MappedByteBufferPoolTest
* In a scenario where MappedByteBufferPool is being used improperly, * In a scenario where MappedByteBufferPool is being used improperly,
* such as releasing a buffer that wasn't created/acquired by the * such as releasing a buffer that wasn't created/acquired by the
* MappedByteBufferPool, an assertion is tested for. * MappedByteBufferPool, an assertion is tested for.
*
* @throws Exception test failure
*/ */
@Test @Test
public void testReleaseAssertion() throws Exception public void testReleaseAssertion()
{ {
int factor = 1024; int factor = 1024;
MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor); MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor);
@ -129,18 +130,18 @@ public class MappedByteBufferPoolTest
{ {
MappedByteBufferPool pool = new MappedByteBufferPool.Tagged(); MappedByteBufferPool pool = new MappedByteBufferPool.Tagged();
ByteBuffer buffer = pool.acquire(1024,false); ByteBuffer buffer = pool.acquire(1024, false);
assertThat(BufferUtil.toDetailString(buffer),containsString("@T00000001")); assertThat(BufferUtil.toDetailString(buffer), containsString("@T00000001"));
buffer = pool.acquire(1024,false); buffer = pool.acquire(1024, false);
assertThat(BufferUtil.toDetailString(buffer),containsString("@T00000002")); assertThat(BufferUtil.toDetailString(buffer), containsString("@T00000002"));
} }
@Test @Test
public void testMaxQueue() throws Exception public void testMaxQueue()
{ {
MappedByteBufferPool bufferPool = new MappedByteBufferPool(-1,2); MappedByteBufferPool bufferPool = new MappedByteBufferPool(-1, 2);
ConcurrentMap<Integer,Bucket> buckets = bufferPool.bucketsFor(false); ConcurrentMap<Integer, Bucket> buckets = bufferPool.bucketsFor(false);
ByteBuffer buffer1 = bufferPool.acquire(512, false); ByteBuffer buffer1 = bufferPool.acquire(512, false);
ByteBuffer buffer2 = bufferPool.acquire(512, false); ByteBuffer buffer2 = bufferPool.acquire(512, false);
@ -149,7 +150,7 @@ public class MappedByteBufferPoolTest
bufferPool.release(buffer1); bufferPool.release(buffer1);
assertEquals(1, buckets.size()); assertEquals(1, buckets.size());
Bucket bucket=buckets.values().iterator().next(); Bucket bucket = buckets.values().iterator().next();
assertEquals(1, bucket.size()); assertEquals(1, bucket.size());
bufferPool.release(buffer2); bufferPool.release(buffer2);
@ -158,4 +159,41 @@ public class MappedByteBufferPoolTest
bufferPool.release(buffer3); bufferPool.release(buffer3);
assertEquals(2, bucket.size()); assertEquals(2, bucket.size());
} }
@Test
public void testMaxMemory()
{
int factor = 1024;
int maxMemory = 11 * 1024;
MappedByteBufferPool bufferPool = new MappedByteBufferPool(factor, -1, null, -1, maxMemory);
ConcurrentMap<Integer, Bucket> buckets = bufferPool.bucketsFor(true);
// Create the buckets - the oldest is the larger.
// 1+2+3+4=10 / maxMemory=11.
for (int i = 4; i >= 1; --i)
{
int capacity = factor * i;
ByteBuffer buffer = bufferPool.acquire(capacity, true);
bufferPool.release(buffer);
}
// Create and release a buffer to exceed the max memory.
ByteBuffer buffer = bufferPool.newByteBuffer(2 * factor, true);
bufferPool.release(buffer);
// Now the oldest buffer should be gone and we have: 1+2x2+3=8
long memory = bufferPool.getMemory(true);
assertThat(memory, lessThan((long)maxMemory));
assertNull(buckets.get(4));
// Create and release a large buffer.
// Max memory is exceeded and buckets 3 and 1 are cleared.
// We will have 2x2+7=11.
buffer = bufferPool.newByteBuffer(7 * factor, true);
bufferPool.release(buffer);
memory = bufferPool.getMemory(true);
assertThat(memory, lessThanOrEqualTo((long)maxMemory));
assertNull(buckets.get(1));
assertNull(buckets.get(3));
}
} }

View File

@ -0,0 +1,12 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure>
<New id="byteBufferPool" class="org.eclipse.jetty.io.ArrayByteBufferPool">
<Arg type="int"><Property name="jetty.byteBufferPool.minCapacity" default="0"/></Arg>
<Arg type="int"><Property name="jetty.byteBufferPool.factor" default="1024"/></Arg>
<Arg type="int"><Property name="jetty.byteBufferPool.maxCapacity" default="65536"/></Arg>
<Arg type="int"><Property name="jetty.byteBufferPool.maxQueueLength" default="-1"/></Arg>
<Arg type="long"><Property name="jetty.byteBufferPool.maxHeapMemory" default="-1"/></Arg>
<Arg type="long"><Property name="jetty.byteBufferPool.maxDirectMemory" default="-1"/></Arg>
</New>
</Configure>

View File

@ -26,6 +26,10 @@
<Configure id="Server" class="org.eclipse.jetty.server.Server"> <Configure id="Server" class="org.eclipse.jetty.server.Server">
<Arg name="threadpool"><Ref refid="threadPool"/></Arg> <Arg name="threadpool"><Ref refid="threadPool"/></Arg>
<Call name="addBean">
<Arg><Ref refid="byteBufferPool"/></Arg>
</Call>
<!-- =========================================================== --> <!-- =========================================================== -->
<!-- Add shared Scheduler instance --> <!-- Add shared Scheduler instance -->
<!-- =========================================================== --> <!-- =========================================================== -->

View File

@ -0,0 +1,27 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[description]
Configures the ByteBufferPool used by ServerConnectors.
[xml]
etc/jetty-bytebufferpool.xml
[ini-template]
### Server ByteBufferPool Configuration
## Minimum capacity to pool ByteBuffers
#jetty.byteBufferPool.minCapacity=0
## Maximum capacity to pool ByteBuffers
#jetty.byteBufferPool.maxCapacity=65536
## Capacity factor
#jetty.byteBufferPool.factor=1024
## Maximum queue length for each bucket (-1 for unbounded)
#jetty.byteBufferPool.maxQueueLength=-1
## Maximum heap memory retainable by the pool (-1 for unlimited)
#jetty.byteBufferPool.maxHeapMemory=-1
## Maximum direct memory retainable by the pool (-1 for unlimited)
#jetty.byteBufferPool.maxDirectMemory=-1

View File

@ -11,6 +11,7 @@ logging
[depend] [depend]
threadpool threadpool
bytebufferpool
[lib] [lib]
lib/jetty-servlet-api-4.0.*.jar lib/jetty-servlet-api-4.0.*.jar

View File

@ -18,14 +18,6 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -37,6 +29,14 @@ import java.util.ListIterator;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
/** /**
* Tests for LazyList utility class. * Tests for LazyList utility class.
*/ */
@ -152,19 +152,19 @@ public class LazyListTest
Object list=null; Object list=null;
list=LazyList.add(list, null); list=LazyList.add(list, null);
assertEquals(1,LazyList.size(list)); assertEquals(1,LazyList.size(list));
assertEquals(null,LazyList.get(list,0)); assertNull(LazyList.get(list,0));
list="a"; list="a";
list=LazyList.add(list, null); list=LazyList.add(list, null);
assertEquals(2,LazyList.size(list)); assertEquals(2,LazyList.size(list));
assertEquals(LazyList.get(list, 0), "a"); assertEquals(LazyList.get(list, 0), "a");
assertEquals(null,LazyList.get(list,1)); assertNull(LazyList.get(list,1));
list=LazyList.add(list, null); list=LazyList.add(list, null);
assertEquals(3,LazyList.size(list)); assertEquals(3,LazyList.size(list));
assertEquals(LazyList.get(list, 0), "a"); assertEquals(LazyList.get(list, 0), "a");
assertEquals(null,LazyList.get(list,1)); assertNull(LazyList.get(list,1));
assertEquals(null,LazyList.get(list,2)); assertNull(LazyList.get(list,2));
} }
/** /**
@ -254,7 +254,7 @@ public class LazyListTest
Object list = LazyList.add(input, 0, null); Object list = LazyList.add(input, 0, null);
assertNotNull(list); assertNotNull(list);
assertEquals(2,LazyList.size(list)); assertEquals(2,LazyList.size(list));
assertEquals(null, LazyList.get(list,0)); assertNull( LazyList.get(list,0));
assertEquals(LazyList.get(list, 1), "a"); assertEquals(LazyList.get(list, 1), "a");
} }

View File

@ -1,107 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2019 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.websocket.tests.client;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.BatchMode;
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
import org.eclipse.jetty.websocket.api.Session;
public class ClientWriteThread extends Thread
{
private static final Logger LOG = Log.getLogger(ClientWriteThread.class);
private final Session session;
private int slowness = -1;
private int messageCount = 100;
private String message = "Hello";
public ClientWriteThread(Session session)
{
this.session = session;
}
public String getMessage()
{
return message;
}
public int getMessageCount()
{
return messageCount;
}
public int getSlowness()
{
return slowness;
}
@Override
public void run()
{
final AtomicInteger m = new AtomicInteger();
try
{
LOG.debug("Writing {} messages to connection {}",messageCount);
LOG.debug("Artificial Slowness {} ms",slowness);
Future<Void> lastMessage = null;
RemoteEndpoint remote = session.getRemote();
while (m.get() < messageCount)
{
lastMessage = remote.sendStringByFuture(message + "/" + m.get() + "/");
m.incrementAndGet();
if (slowness > 0)
{
TimeUnit.MILLISECONDS.sleep(slowness);
}
}
if (remote.getBatchMode() == BatchMode.ON)
remote.flush();
// block on write of last message
if (lastMessage != null)
lastMessage.get(2,TimeUnit.MINUTES); // block on write
}
catch (Exception e)
{
LOG.warn(e);
}
}
public void setMessage(String message)
{
this.message = message;
}
public void setMessageCount(int messageCount)
{
this.messageCount = messageCount;
}
public void setSlowness(int slowness)
{
this.slowness = slowness;
}
}

View File

@ -18,17 +18,11 @@
package org.eclipse.jetty.server.session; package org.eclipse.jetty.server.session;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -44,6 +38,11 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* AbstractClusteredSessionScavengingTest * AbstractClusteredSessionScavengingTest
* *
@ -62,7 +61,6 @@ public abstract class AbstractClusteredSessionScavengingTest extends AbstractTes
@Test @Test
public void testClusteredScavenge() throws Exception public void testClusteredScavenge() throws Exception
{ {