From 60b7c386fb30444da228473b7d8aa502d19e40eb Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Tue, 10 Jun 2025 13:37:48 +1000 Subject: [PATCH 1/5] Setup profile for multi release jar Signed-off-by: Olivier Lamy --- .../org/eclipse/jetty/io/ByteBufferPool.java | 249 ++++++++++++++++++ pom.xml | 64 +++++ 2 files changed, 313 insertions(+) create mode 100644 jetty-core/jetty-io/src/main/java22/org/eclipse/jetty/io/ByteBufferPool.java diff --git a/jetty-core/jetty-io/src/main/java22/org/eclipse/jetty/io/ByteBufferPool.java b/jetty-core/jetty-io/src/main/java22/org/eclipse/jetty/io/ByteBufferPool.java new file mode 100644 index 000000000000..6a48575ef465 --- /dev/null +++ b/jetty-core/jetty-io/src/main/java22/org/eclipse/jetty/io/ByteBufferPool.java @@ -0,0 +1,249 @@ +// +// ======================================================================== +// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.io; + +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.IO; + +import java.lang.foreign.MemorySegment; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + *

A pool for {@link RetainableByteBuffer} instances.

+ *

{@link RetainableByteBuffer} that are {@link #acquire(int, boolean) acquired} + * must be released by calling {@link RetainableByteBuffer#release()} + * otherwise the memory they hold will be leaked.

+ * + *

API NOTE

+ *

This interface does not have a symmetric {@code release(RetainableByteBuffer)} + * method, because it will be confusing to use due to the fact that the acquired instance + * is-a {@link Retainable}.

+ *

Imagine this (hypothetical) code sequence:

+ *
{@code
+ * RetainableByteBuffer buffer = pool.acquire(size, direct);
+ * buffer.retain();
+ * pool.release(buffer);
+ * }
+ *

The hypothetical call to {@code release(RetainableByteBuffer)} would appear to + * release the buffer to the pool, but in fact the buffer is retained one more time + * (and therefore still in use) and not really released to the pool. + * For this reason there is no {@code release(RetainableByteBuffer)} method.

+ *

Therefore, in order to track acquire/release counts both the pool and the + * buffer returned by {@link #acquire(int, boolean)} must be wrapped, see + * {@link RetainableByteBuffer.Wrapper}

+ */ +public interface ByteBufferPool +{ + ByteBufferPool NON_POOLING = new NonPooling(); + Sized SIZED_NON_POOLING = new Sized(ByteBufferPool.NON_POOLING); + + /** + *

Acquires a {@link RetainableByteBuffer} from this pool.

+ * + * @param size The size of the buffer. The returned buffer will have at least this capacity. + * @param direct true if a direct memory buffer is needed, false otherwise. + * @return a {@link RetainableByteBuffer} with position and limit set to 0. + */ + RetainableByteBuffer.Mutable acquire(int size, boolean direct); + + /** + *

Removes all {@link RetainableByteBuffer#isRetained() non-retained} + * pooled instances from this pool.

+ */ + void clear(); + + /** + *

A wrapper for {@link ByteBufferPool} instances.

+ */ + class Wrapper implements ByteBufferPool + { + private final ByteBufferPool wrapped; + + public Wrapper(ByteBufferPool wrapped) + { + this.wrapped = wrapped; + } + + public ByteBufferPool getWrapped() + { + return wrapped; + } + + @Override + public RetainableByteBuffer.Mutable acquire(int size, boolean direct) + { + return getWrapped().acquire(size, direct); + } + + @Override + public void clear() + { + getWrapped().clear(); + } + } + + /** + * A ByteBufferPool with an additional no-args {@link #acquire()} method to obtain a buffer of a + * preconfigured specific size and type. + */ + class Sized extends Wrapper + { + private final boolean _direct; + private final int _size; + + /** + * Create a sized pool for non direct buffers of a default size from a wrapped pool. + * @param wrapped The actual {@link ByteBufferPool} + */ + public Sized(ByteBufferPool wrapped) + { + this(wrapped, false, -1); + } + + /** + * Create a sized pool for a give directness and size from a wrapped pool. + * @param wrapped The actual {@link ByteBufferPool} + * @param direct {@code true} for direct buffers. + * @param size The specified size in bytes of the buffer, any value less than 1 means use a default value. + */ + public Sized(ByteBufferPool wrapped, boolean direct, int size) + { + super(Objects.requireNonNullElse(wrapped, NON_POOLING)); + _direct = direct; + _size = size >= 0 ? size : IO.DEFAULT_BUFFER_SIZE; + } + + public boolean isDirect() + { + return _direct; + } + + public int getSize() + { + return _size; + } + + /** + * @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured size and type. + */ + public RetainableByteBuffer.Mutable acquire() + { + return getWrapped().acquire(_size, _direct); + } + + /** + * @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured type. + * @param size The specified size in bytes of the buffer + */ + public RetainableByteBuffer.Mutable acquire(int size) + { + return getWrapped().acquire(size, _direct); + } + + /** + * @return A {@link RetainableByteBuffer.Mutable} suitable for the specified preconfigured type. + * @param direct true for a direct byte buffer, false otherwise + */ + public RetainableByteBuffer.Mutable acquire(boolean direct) + { + return getWrapped().acquire(_size, direct); + } + } + + /** + *

A {@link ByteBufferPool} that does not pool its + * {@link RetainableByteBuffer}s.

+ *

The returned {@code RetainableByteBuffer}s are reference + * counted.

+ *

{@code RetainableByteBuffer}s returned by this class + * are suitable to be wrapped in other {@link Retainable} + * implementations that may delegate calls to + * {@link Retainable#retain()}.

+ * + * @see RetainableByteBuffer#wrap(ByteBuffer) + */ + class NonPooling implements ByteBufferPool + { + @Override + public RetainableByteBuffer.Mutable acquire(int size, boolean direct) + { + return RetainableByteBuffer.wrap(BufferUtil.allocate(size, direct)); + } + + @Override + public void clear() + { + } + } + + /** + *

Accumulates a sequence of {@link RetainableByteBuffer} that + * are typically created during the generation of protocol bytes.

+ *

{@code RetainableByteBuffer}s can be either + * {@link #append(RetainableByteBuffer) appended} to the sequence, + * or {@link #insert(int, RetainableByteBuffer) inserted} at a + * specific position in the sequence, and then + * {@link #release() released} when they are consumed.

+ * @deprecated use {@link RetainableByteBuffer.DynamicCapacity} + */ + @Deprecated (forRemoval = true, since = "12.1.0") + class Accumulator + { + private final List buffers = new ArrayList<>(); + private final List byteBuffers = new ArrayList<>(); + + public void append(RetainableByteBuffer buffer) + { + MemorySegment memorySegment; + buffers.add(buffer); + byteBuffers.add(buffer.getByteBuffer()); + } + + public void insert(int index, RetainableByteBuffer buffer) + { + buffers.add(index, buffer); + byteBuffers.add(index, buffer.getByteBuffer()); + } + + public List getByteBuffers() + { + return byteBuffers; + } + + public long getTotalLength() + { + long length = 0; + for (ByteBuffer buffer : byteBuffers) + { + length += buffer.remaining(); + } + return length; + } + + public int getSize() + { + return byteBuffers.size(); + } + + public void release() + { + buffers.forEach(RetainableByteBuffer::release); + buffers.clear(); + byteBuffers.clear(); + } + } +} diff --git a/pom.xml b/pom.xml index d79b8754edb5..1aae1b2e048e 100644 --- a/pom.xml +++ b/pom.xml @@ -2211,6 +2211,70 @@ + + mr-jar-21 + + + ${project.basedir}/src/main/java21 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + java21 + + compile + + compile + + 21 + + ${project.basedir}/src/main/java21 + + true + + + + + + + + + mr-jar-22 + + + ${project.basedir}/src/main/java22 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + java22 + + compile + + compile + + 22 + + ${project.basedir}/src/main/java22 + + true + + + + + + + unix-domain-windows From 9ebb1e0c2005bea4bfcc81307ca2b6d4420368fa Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Tue, 10 Jun 2025 13:53:59 +1000 Subject: [PATCH 2/5] need to always run/compile with minimum of 23 Signed-off-by: Olivier Lamy --- Jenkinsfile | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f3b16c842738..ce818b0fd041 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -39,13 +39,13 @@ pipeline { } } - stage("Build / Test - JDK17 Javadoc") { + stage("Build / Test - JDK24 Javadoc") { agent { node { label 'linux-light' } } steps { timeout( time: 180, unit: 'MINUTES' ) { checkout scm - withEnv(["JAVA_HOME=${ tool 'jdk17' }", - "PATH+MAVEN=${ tool 'jdk17' }/bin:${tool 'maven3'}/bin", + withEnv(["JAVA_HOME=${ tool 'jdk24' }", + "PATH+MAVEN=${ tool 'jdk24' }/bin:${tool 'maven3'}/bin", "MAVEN_OPTS=-Xms3072m -Xmx5120m -Djava.awt.headless=true -client -XX:+UnlockDiagnosticVMOptions -XX:GCLockerRetryAllocationCount=100"]) { configFileProvider( [configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS'), @@ -123,8 +123,9 @@ def slackNotif() { def mavenBuild(jdk, cmdline, mvnName) { script { try { - withEnv(["JAVA_HOME=${ tool "$jdk" }", - "PATH+MAVEN=${ tool "$jdk" }/bin:${tool "$mvnName"}/bin", + withEnv(["JDK_HOME=${ tool "$jdk" }", + "JAVA_HOME=${ tool "jdk23"}", + "PATH+MAVEN=${ tool "jdk23" }/bin:${tool "$mvnName"}/bin", "MAVEN_OPTS=-Xms3072m -Xmx5120m -Djava.awt.headless=true -client -XX:+UnlockDiagnosticVMOptions -XX:GCLockerRetryAllocationCount=100"]) { configFileProvider( [configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS')]) { @@ -148,7 +149,7 @@ def mavenBuild(jdk, cmdline, mvnName) { } sh "mkdir ~/.mimir" sh "cp jenkins-mimir-daemon.properties ~/.mimir/daemon.properties" - sh "mvn $extraArgs $dashProfile -s $GLOBAL_MVN_SETTINGS -DsettingsPath=$GLOBAL_MVN_SETTINGS -Dmaven.repo.uri=http://nexus-service.nexus.svc.cluster.local:8081/repository/maven-public/ -ntp -Dmaven.repo.local=.repository -Pci -V -B -e -U $cmdline" + sh "mvn $extraArgs -Djvm=$JDK_HOME/bin/java $dashProfile -s $GLOBAL_MVN_SETTINGS -DsettingsPath=$GLOBAL_MVN_SETTINGS -Dmaven.repo.uri=http://nexus-service.nexus.svc.cluster.local:8081/repository/maven-public/ -ntp -Dmaven.repo.local=.repository -Pci -V -B -e -U $cmdline" if(saveHome()) { archiveArtifacts artifacts: ".repository/org/eclipse/jetty/jetty-home/**/jetty-home-*", allowEmptyArchive: true, onlyIfSuccessful: false } From 914798924af790c534c60881c4d751b5e92ddd68 Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Tue, 10 Jun 2025 13:56:22 +1000 Subject: [PATCH 3/5] 22 as minimum Signed-off-by: Olivier Lamy --- Jenkinsfile | 10 +++++----- pom.xml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index ce818b0fd041..73696bf1b26f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -39,13 +39,13 @@ pipeline { } } - stage("Build / Test - JDK24 Javadoc") { + stage("Build / Test - JDK22 Javadoc") { agent { node { label 'linux-light' } } steps { timeout( time: 180, unit: 'MINUTES' ) { checkout scm - withEnv(["JAVA_HOME=${ tool 'jdk24' }", - "PATH+MAVEN=${ tool 'jdk24' }/bin:${tool 'maven3'}/bin", + withEnv(["JAVA_HOME=${ tool 'jdk22' }", + "PATH+MAVEN=${ tool 'jdk22' }/bin:${tool 'maven3'}/bin", "MAVEN_OPTS=-Xms3072m -Xmx5120m -Djava.awt.headless=true -client -XX:+UnlockDiagnosticVMOptions -XX:GCLockerRetryAllocationCount=100"]) { configFileProvider( [configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS'), @@ -124,8 +124,8 @@ def mavenBuild(jdk, cmdline, mvnName) { script { try { withEnv(["JDK_HOME=${ tool "$jdk" }", - "JAVA_HOME=${ tool "jdk23"}", - "PATH+MAVEN=${ tool "jdk23" }/bin:${tool "$mvnName"}/bin", + "JAVA_HOME=${ tool "jdk22"}", + "PATH+MAVEN=${ tool "jdk22" }/bin:${tool "$mvnName"}/bin", "MAVEN_OPTS=-Xms3072m -Xmx5120m -Djava.awt.headless=true -client -XX:+UnlockDiagnosticVMOptions -XX:GCLockerRetryAllocationCount=100"]) { configFileProvider( [configFile(fileId: 'oss-settings.xml', variable: 'GLOBAL_MVN_SETTINGS')]) { diff --git a/pom.xml b/pom.xml index 1aae1b2e048e..8389cfc148ae 100644 --- a/pom.xml +++ b/pom.xml @@ -2042,7 +2042,7 @@ [ERROR] OLD MAVEN [${maven.version}] in use, Jetty ${project.version} requires Maven 3.9.2 or newer - [17,) + [22,) [ERROR] OLD JDK [${java.version}] in use. Jetty ${project.version} requires JDK 17 or newer From f442459768b2494790cb956ded1caaff312afea6 Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Tue, 10 Jun 2025 16:58:29 +1000 Subject: [PATCH 4/5] jdk 23 for gha Signed-off-by: Olivier Lamy --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f890f52abf8a..dcc3a02835d8 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -46,8 +46,8 @@ jobs: distribution: temurin java-version: 11 - # Install and setup JDK 17 - - name: Setup JDK 17 + # Install and setup JDK 23 + - name: Setup JDK 23 uses: actions/setup-java@v4 if: ${{ startsWith(github.ref, 'refs/heads/jetty-12.') || @@ -55,7 +55,7 @@ jobs: }} with: distribution: temurin - java-version: 17 + java-version: 23 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL From 146488f2d954f88dcda15ea6d98e6c3b12a4623f Mon Sep 17 00:00:00 2001 From: Olivier Lamy Date: Wed, 11 Jun 2025 15:09:01 +1000 Subject: [PATCH 5/5] jacoco doesn't like much mrjar Signed-off-by: Olivier Lamy --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index 8389cfc148ae..cbb9474b157e 100644 --- a/pom.xml +++ b/pom.xml @@ -2140,6 +2140,7 @@ + **/META-INF/** **/org/eclipse/jetty/ant/** */org/eclipse/jetty/maven/its/**