Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,16 @@ 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.') ||
startsWith(github.base_ref, 'jetty-12.')
}}
with:
distribution: temurin
java-version: 17
java-version: 23

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
Expand Down
13 changes: 7 additions & 6 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ pipeline {
}
}

stage("Build / Test - JDK17 Javadoc") {
stage("Build / Test - JDK22 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 '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'),
Expand Down Expand Up @@ -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 "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')]) {
Expand All @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/**
* <p>A pool for {@link RetainableByteBuffer} instances.</p>
* <p>{@link RetainableByteBuffer} that are {@link #acquire(int, boolean) acquired}
* <b>must</b> be released by calling {@link RetainableByteBuffer#release()}
* otherwise the memory they hold will be leaked.</p>
*
* <p><b>API NOTE</b></p>
* <p>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
* <em>is-a</em> {@link Retainable}.</p>
* <p>Imagine this (hypothetical) code sequence:</p>
* <pre>{@code
* RetainableByteBuffer buffer = pool.acquire(size, direct);
* buffer.retain();
* pool.release(buffer);
* }</pre>
* <p>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.</p>
* <p>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}</p>
*/
public interface ByteBufferPool
{
ByteBufferPool NON_POOLING = new NonPooling();
Sized SIZED_NON_POOLING = new Sized(ByteBufferPool.NON_POOLING);

/**
* <p>Acquires a {@link RetainableByteBuffer} from this pool.</p>
*
* @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);

/**
* <p>Removes all {@link RetainableByteBuffer#isRetained() non-retained}
* pooled instances from this pool.</p>
*/
void clear();

/**
* <p>A wrapper for {@link ByteBufferPool} instances.</p>
*/
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);
}
}

/**
* <p>A {@link ByteBufferPool} that does not pool its
* {@link RetainableByteBuffer}s.</p>
* <p>The returned {@code RetainableByteBuffer}s are reference
* counted.</p>
* <p>{@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()}.</p>
*
* @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()
{
}
}

/**
* <p>Accumulates a sequence of {@link RetainableByteBuffer} that
* are typically created during the generation of protocol bytes.</p>
* <p>{@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.</p>
* @deprecated use {@link RetainableByteBuffer.DynamicCapacity}
*/
@Deprecated (forRemoval = true, since = "12.1.0")
class Accumulator
{
private final List<RetainableByteBuffer> buffers = new ArrayList<>();
private final List<ByteBuffer> 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<ByteBuffer> 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();
}
}
}
67 changes: 66 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2042,7 +2042,7 @@
<message>[ERROR] OLD MAVEN [${maven.version}] in use, Jetty ${project.version} requires Maven 3.9.2 or newer</message>
</requireMavenVersion>
<requireJavaVersion>
<version>[17,)</version>
<version>[22,)</version>
<message>[ERROR] OLD JDK [${java.version}] in use. Jetty ${project.version} requires JDK 17 or newer</message>
</requireJavaVersion>
<versionTxtRule implementation="org.eclipse.jetty.toolchain.enforcer.rules.VersionTxtRule"></versionTxtRule>
Expand Down Expand Up @@ -2140,6 +2140,7 @@
<configuration>
<excludes>
<!-- build tools -->
<exclude>**/META-INF/**</exclude>
<exclude>**/org/eclipse/jetty/ant/**</exclude>
<exclude>*/org/eclipse/jetty/maven/its/**</exclude>
<!-- example code / documentation -->
Expand Down Expand Up @@ -2211,6 +2212,70 @@
</build>

<profiles>
<profile>
<id>mr-jar-21</id>
<activation>
<file>
<exists>${project.basedir}/src/main/java21</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>java21</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
<configuration>
<release>21</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java21</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>mr-jar-22</id>
<activation>
<file>
<exists>${project.basedir}/src/main/java22</exists>
</file>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>java22</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
<configuration>
<release>22</release>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java22</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>unix-domain-windows</id>
<activation>
Expand Down