Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/jetty-12.1.x' into fix/12.1.x/dy…
Browse files Browse the repository at this point in the history
…namic-compression-handler
  • Loading branch information
joakime committed Sep 26, 2024
2 parents b46d075 + 32156ca commit 1575b0a
Show file tree
Hide file tree
Showing 48 changed files with 895 additions and 937 deletions.
4 changes: 2 additions & 2 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ def mavenBuild(jdk, cmdline, mvnName) {
buildCache = useBuildCache()
if (buildCache) {
echo "Using build cache"
extraArgs = " -Dmaven.build.cache.restoreGeneratedSources=false -Dmaven.build.cache.remote.url=http://nginx-cache-service.jenkins.svc.cluster.local:80 -Dmaven.build.cache.remote.enabled=true -Dmaven.build.cache.remote.save.enabled=true -Dmaven.build.cache.remote.server.id=remote-build-cache-server -Daether.connector.http.supportWebDav=true "
extraArgs = " -Dmaven.build.cache.restoreGeneratedSources=false -Dmaven.build.cache.remote.url=http://nexus-service.nexus.svc.cluster.local:8081/repository/maven-build-cache -Dmaven.build.cache.remote.enabled=true -Dmaven.build.cache.remote.save.enabled=true -Dmaven.build.cache.remote.server.id=nexus-cred "
} else {
// when not using cache
echo "Not using build cache"
extraArgs = " -Dmaven.test.failure.ignore=true -Dmaven.build.cache.skipCache=true -Dmaven.build.cache.remote.url=http://nginx-cache-service.jenkins.svc.cluster.local:80 -Dmaven.build.cache.remote.enabled=true -Dmaven.build.cache.remote.save.enabled=true -Dmaven.build.cache.remote.server.id=remote-build-cache-server -Daether.connector.http.supportWebDav=true "
extraArgs = " -Dmaven.test.failure.ignore=true -Dmaven.build.cache.skipCache=true -Dmaven.build.cache.remote.url=http://nexus-service.nexus.svc.cluster.local:8081/repository/maven-build-cache -Dmaven.build.cache.remote.enabled=true -Dmaven.build.cache.remote.save.enabled=true -Dmaven.build.cache.remote.server.id=nexus-cred "
}
if (env.BRANCH_NAME ==~ /PR-\d+/) {
if (pullRequest.labels.contains("build-all-tests")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

import java.util.concurrent.Executors;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.VirtualThreadPool;
Expand All @@ -26,9 +29,26 @@ public void queuedVirtualThreads()
{
// tag::queuedVirtual[]
QueuedThreadPool threadPool = new QueuedThreadPool();

// Simple, unlimited, virtual thread Executor.
threadPool.setVirtualThreadsExecutor(Executors.newVirtualThreadPerTaskExecutor());

// Configurable, bounded, virtual thread executor (preferred).
VirtualThreadPool virtualExecutor = new VirtualThreadPool();
virtualExecutor.setMaxThreads(128);
threadPool.setVirtualThreadsExecutor(virtualExecutor);

// For server-side usage.
Server server = new Server(threadPool);

// Simple client-side usage.
HttpClient client = new HttpClient();
client.setExecutor(threadPool);

// Client-side usage with explicit HttpClientTransport.
ClientConnector clientConnector = new ClientConnector();
clientConnector.setExecutor(threadPool);
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
// end::queuedVirtual[]
}

Expand All @@ -38,8 +58,21 @@ public void virtualVirtualThreads()
VirtualThreadPool threadPool = new VirtualThreadPool();
// Limit the max number of current virtual threads.
threadPool.setMaxThreads(200);
// Track, with details, virtual threads usage.
threadPool.setTracking(true);
threadPool.setDetailedDump(true);

// For server-side usage.
Server server = new Server(threadPool);

// Simple client-side usage.
HttpClient client = new HttpClient();
client.setExecutor(threadPool);

// Client-side usage with explicit HttpClientTransport.
ClientConnector clientConnector = new ClientConnector();
clientConnector.setExecutor(threadPool);
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
// end::virtualVirtual[]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -714,7 +714,6 @@ See also the xref:server/index.adoc#threadpool[section about configuring the thr
The `threadpool-all-virtual` module allows you to configure the server-wide thread pool, similarly to what you can do with the <<threadpool,`threadpool`>> Jetty module, so that all threads are virtual threads, introduced as an official feature since Java 21.

CAUTION: Only use this module if you are using Java 21 or later.
If you are using Java 19 or Java 20, use the <<threadpool-virtual-preview,`threadpool-virtual-preview`>> Jetty module instead.

The module properties to configure the thread pool are:

Expand All @@ -724,17 +723,7 @@ include::{jetty-home}/modules/threadpool-all-virtual.mod[tags=documentation]

The property `jetty.threadpool.maxThreads` limits, using a `Semaphore`, the number of current virtual threads in use.

Limiting the number of current virtual threads helps to limit resource usage in applications, especially in case of load spikes.
When an unlimited number of virtual threads is allowed, the server might be brought down due to resource (typically memory) exhaustion.

[CAUTION]
====
Even when using virtual threads, Jetty uses non-blocking I/O, and dedicates a thread to each `java.nio.channels.Selector` to perform the `Selector.select()` operation.
Currently (up to Java 22), calling `Selector.select()` from a virtual thread pins the carrier thread.
When using the `threadpool-all-virtual` Jetty module, if you have `N` selectors, then `N` carrier threads will be pinned by the virtual threads calling `Selector.select()`, possibly making your system less efficient, and at worst locking up the entire system if there are no carrier threads available to run virtual threads.
====
Please refer to the xref:programming-guide:arch/threads.adoc#thread-pool-virtual-threads[virtual threads section] of the Jetty Threading Architecture for more information about virtual threads and their pitfalls.

[[threadpool-virtual]]
== Module `threadpool-virtual`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,35 @@ Defaulting the number of reserved threads to zero ensures that the <<execution-s
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java[tags=virtualVirtual]
----

Despite the name, `VirtualThreadPool` does not pool virtual threads, but allows you to impose a limit on the maximum number of current virtual threads, in order to limit resource consumption.
Despite the name, `VirtualThreadPool` does not pool virtual threads, but allows you to impose a limit on the maximum number of current virtual threads, using a `Semaphore`.

Furthermore, you can configure it to track virtual threads so that a xref:troubleshooting/component-dump.adoc[Jetty component dump] will show all virtual threads, including those that are unmounted.
Limiting the number of current virtual threads helps to limit resource usage in applications, especially in case of load spikes.
When an unlimited number of virtual threads is allowed, the server might be brought down due to resource (typically memory) exhaustion.

Furthermore, you can configure it to track virtual threads so that a xref:troubleshooting/component-dump.adoc[Jetty component dump] will show all virtual threads currently in use, including those that are unmounted.

[[thread-pool-virtual-threads-pinning]]
==== Virtual Threads Pinning

Even when using virtual threads, Jetty uses non-blocking I/O, and dedicates a thread to each `java.nio.channels.Selector` to perform the `Selector.select()` operation.

Currently (up to Java 22), calling `Selector.select()` from a virtual thread *pins* the carrier thread.

If you configure a server-side `Connector`, or Jetty's `HttpClient` with `N` selectors, then `N` carrier threads will be pinned by the virtual threads calling `Selector.select()`.

If you have less than `N` CPU cores in your system, then by default all carriers will be pinned in the `Selector.select()` call, leaving no carrier to execute virtual threads, and therefore completely locking up your system, which will become completely unresponsive.

If you have more than `N` CPU cores in your system, then by default your system may be less efficient, since the carrier threads may be pinned in the `Selector.select()` call, and therefore not available to run virtual threads.

[WARNING]
====
The number of CPU cores of your system determines, by default, the number of carrier threads.
The number of carrier threads may be explicitly configured by setting the system property `-Djdk.virtualThreadScheduler.parallelism=N`, where `N` is your desired number of carrier threads.
Selector threads used by Jetty pin carrier threads.
Choose the number of selectors wisely when using virtual threads: the number of selectors must always be less than the number of carrier threads, to leave some of the carrier threads free to run virtual threads.
As an extreme example, if your system only has `1` CPU core, then `1` selector is enough to pin the only carrier thread, and your system will eventually lock up.
In this case, you must explicitly configure the number of carrier threads by setting the system property `-Djdk.virtualThreadScheduler.parallelism=2` (or to a larger value).
====
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
* <p>Content must be provided by writing to the {@link #getOutputStream() output stream}
* that must be {@link OutputStream#close() closed} when all content has been provided.</p>
* <p>Example usage:</p>
* <pre>
* <pre>{@code
* HttpClient httpClient = ...;
*
* // Use try-with-resources to autoclose the output stream.
Expand All @@ -37,7 +37,7 @@
* .body(content)
* .send(new Response.CompleteListener()
* {
* &#64;Override
* @Override
* public void onComplete(Result result)
* {
* // Your logic here
Expand All @@ -50,7 +50,7 @@
* // Even later...
* output.write("more content".getBytes());
* } // Implicit call to output.close().
* </pre>
* }</pre>
*/
public class OutputStreamRequestContent extends OutputStreamContentSource implements Request.Content
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.slf4j.Logger;
Expand All @@ -42,7 +41,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran

public HttpClientTransportOverHTTP()
{
this(Math.max(1, ProcessorUtils.availableProcessors() / 2));
this(1);
}

public HttpClientTransportOverHTTP(int selectors)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,11 @@ public State getState()
return _state;
}

public boolean hasContent()
{
return _endOfContent != EndOfContent.NO_CONTENT;
}

public boolean inContentState()
{
return _state.ordinal() >= State.CONTENT.ordinal() && _state.ordinal() < State.END.ordinal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,8 @@ default boolean isSecure()
interface SslSessionData
{
/**
* The name at which an {@code SslSessionData} instance may be found as a request
* {@link org.eclipse.jetty.util.Attributes Attribute} or from {@link SSLSession#getValue(String)}.
* The name at which an {@code SslSessionData} instance may be found
* as a request {@link org.eclipse.jetty.util.Attributes attribute}.
*/
String ATTRIBUTE = "org.eclipse.jetty.io.Endpoint.SslSessionData";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@
import org.eclipse.jetty.util.IO;

/**
* <p>
* A {@link Content.Source} backed by an {@link OutputStream}.
* Any bytes written to the {@link OutputStream} returned by {@link #getOutputStream()}
* is converted to a {@link Content.Chunk} and returned from {@link #read()}. If
* necessary, any {@link Runnable} passed to {@link #demand(Runnable)} is invoked.
* </p>
* <p>A {@link Content.Source} that provides content asynchronously through an {@link OutputStream}.</p>
* <p>Bytes written to the {@link OutputStream} returned by {@link #getOutputStream()}
* are converted to a {@link Content.Chunk} and returned from {@link #read()}.</p>
* <p>The {@code OutputStream} must be closed to signal that all the content has been written.</p>
*
* @see AsyncContent
*/
public class OutputStreamContentSource implements Content.Source, Closeable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ public class SslEndPoint extends AbstractEndPoint implements EndPoint.Wrapper

private final Callback _incompleteWriteCallback = new IncompleteWriteCallback();
private Throwable _failure;
private SslSessionData _sslSessionData;

public SslEndPoint()
{
Expand Down Expand Up @@ -1572,6 +1573,28 @@ private Throwable handleException(Throwable x, String context)
}
}

@Override
public SslSessionData getSslSessionData()
{
SSLSession sslSession = _sslEngine.getSession();
SslSessionData sslSessionData = _sslSessionData;
if (sslSessionData == null)
{
String cipherSuite = sslSession.getCipherSuite();

X509Certificate[] peerCertificates = _sslContextFactory != null
? _sslContextFactory.getX509CertChain(sslSession)
: SslContextFactory.getCertChain(sslSession);

byte[] bytes = sslSession.getId();
String idStr = StringUtil.toHexString(bytes);

sslSessionData = SslSessionData.from(sslSession, idStr, cipherSuite, peerCertificates);
_sslSessionData = sslSessionData;
}
return sslSessionData;
}

@Override
public String toString()
{
Expand Down Expand Up @@ -1644,28 +1667,6 @@ public String toString()
return String.format("SSL@%h.DEP.writeCallback", SslConnection.this);
}
}

@Override
public SslSessionData getSslSessionData()
{
SSLSession sslSession = _sslEngine.getSession();
SslSessionData sslSessionData = (SslSessionData)sslSession.getValue(SslSessionData.ATTRIBUTE);
if (sslSessionData == null)
{
String cipherSuite = sslSession.getCipherSuite();

X509Certificate[] peerCertificates = _sslContextFactory != null
? _sslContextFactory.getX509CertChain(sslSession)
: SslContextFactory.getCertChain(sslSession);

byte[] bytes = sslSession.getId();
String idStr = StringUtil.toHexString(bytes);

sslSessionData = SslSessionData.from(sslSession, idStr, cipherSuite, peerCertificates);
sslSession.putValue(SslSessionData.ATTRIBUTE, sslSessionData);
}
return sslSessionData;
}
}

private abstract class RunnableTask implements Invocable.Task
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import java.util.List;
import java.util.Map;

import org.eclipse.jetty.maven.MavenServerConnector;
import org.eclipse.jetty.maven.PluginLog;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
Expand Down Expand Up @@ -65,7 +63,15 @@ public static void configureHandlers(Server server, List<ContextHandler> context
if (contexts == null)
{
contexts = new ContextHandlerCollection();
server.setHandler(contexts);
if (server.getHandler() != null)
{
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(server.getHandler());
handlers.addHandler(contexts);
server.setHandler(handlers);
}
else
server.setHandler(contexts);
}

if (contextHandlers != null)
Expand Down
Loading

0 comments on commit 1575b0a

Please sign in to comment.