Skip to content
Closed
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
92 changes: 92 additions & 0 deletions .github/unsafe/armeria-remove-JCTools.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
From f371066409daaf55739eb60e1ef0d9f42b21ac2a Mon Sep 17 00:00:00 2001
From: Trask Stalnaker <trask.stalnaker@gmail.com>
Date: Sat, 20 Sep 2025 15:36:51 -0700
Subject: [PATCH] Remove JCTools

---
.../java/com/linecorp/armeria/common/ExceptionSampler.java | 5 ++---
.../linecorp/armeria/common/stream/DefaultStreamMessage.java | 4 ++--
core/src/main/java/com/linecorp/armeria/server/Server.java | 4 ++--
3 files changed, 6 insertions(+), 7 deletions(-)

diff --git a/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java b/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
index 87afd2074..b5c1c2470 100644
--- a/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
+++ b/core/src/main/java/com/linecorp/armeria/common/ExceptionSampler.java
@@ -18,10 +18,9 @@ package com.linecorp.armeria.common;
import static java.util.Objects.requireNonNull;

import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

-import org.jctools.maps.NonBlockingHashMap;
-
import com.google.common.base.MoreObjects;

import com.linecorp.armeria.common.util.Sampler;
@@ -29,7 +28,7 @@ import com.linecorp.armeria.common.util.Sampler;
final class ExceptionSampler implements Sampler<Class<? extends Throwable>> {

private final Map<Class<? extends Throwable>, Sampler<Class<? extends Throwable>>> samplers =
- new NonBlockingHashMap<>();
+ new ConcurrentHashMap<>();
private final Function<? super Class<? extends Throwable>,
? extends Sampler<Class<? extends Throwable>>> samplerFactory;
private final String spec;
diff --git a/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java b/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
index e9328f03e..12173e999 100644
--- a/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
+++ b/core/src/main/java/com/linecorp/armeria/common/stream/DefaultStreamMessage.java
@@ -22,9 +22,9 @@ import static java.util.Objects.requireNonNull;

import java.util.Queue;
import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

-import org.jctools.queues.MpscChunkedArrayQueue;
import org.reactivestreams.Subscriber;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -109,7 +109,7 @@ public class DefaultStreamMessage<T> extends AbstractStreamWriter<T> {
*/
@Deprecated
public DefaultStreamMessage() {
- queue = new MpscChunkedArrayQueue<>(INITIAL_CAPACITY, 1 << 30);
+ queue = new ConcurrentLinkedQueue<>();
}

@Override
diff --git a/core/src/main/java/com/linecorp/armeria/server/Server.java b/core/src/main/java/com/linecorp/armeria/server/Server.java
index 6b8b0b557..0c3eed942 100644
--- a/core/src/main/java/com/linecorp/armeria/server/Server.java
+++ b/core/src/main/java/com/linecorp/armeria/server/Server.java
@@ -37,6 +37,7 @@ import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -51,7 +52,6 @@ import java.util.stream.Collectors;

import javax.net.ssl.SSLSession;

-import org.jctools.maps.NonBlockingHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@@ -119,7 +119,7 @@ public final class Server implements ListenableAsyncCloseable {

private final UpdatableServerConfig config;
private final StartStopSupport<Void, Void, Void, ServerListener> startStop;
- private final Set<ServerChannel> serverChannels = new NonBlockingHashSet<>();
+ private final Set<ServerChannel> serverChannels = ConcurrentHashMap.newKeySet();
private final ReentrantLock lock = new ReentrantShortLock();
@GuardedBy("lock")
private final Map<InetSocketAddress, ServerPort> activePorts = new LinkedHashMap<>();
--
2.51.0.windows.1

117 changes: 117 additions & 0 deletions .github/unsafe/armeria-update-Caffeine.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
From d6276724f7f432af4693e9d786ecfcaddb73e505 Mon Sep 17 00:00:00 2001
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO trask to open armeria issue

From: Trask Stalnaker <trask.stalnaker@gmail.com>
Date: Sat, 20 Sep 2025 21:48:43 -0700
Subject: [PATCH] Update Caffeine

---
.../src/main/java/com/linecorp/armeria/common/Flags.java | 2 +-
.../armeria/internal/common/util/CertificateUtil.java | 9 ++++++---
.../linecorp/armeria/server/file/FileServiceConfig.java | 2 +-
dependencies.toml | 5 ++---
gradle.properties | 4 ++--
5 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/core/src/main/java/com/linecorp/armeria/common/Flags.java b/core/src/main/java/com/linecorp/armeria/common/Flags.java
index 57671a686..e1dd6eb3b 100644
--- a/core/src/main/java/com/linecorp/armeria/common/Flags.java
+++ b/core/src/main/java/com/linecorp/armeria/common/Flags.java
@@ -1722,7 +1722,7 @@ public final class Flags {
if ("off".equals(value)) {
return allowOff;
}
- CaffeineSpec.parse(value);
+ var unused = CaffeineSpec.parse(value);
return true;
} catch (Exception e) {
return false;
diff --git a/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java b/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
index a343428a3..48698e3ea 100644
--- a/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
+++ b/core/src/main/java/com/linecorp/armeria/internal/common/util/CertificateUtil.java
@@ -57,6 +57,8 @@ public final class CertificateUtil {

private static final Logger logger = LoggerFactory.getLogger(CertificateUtil.class);

+ private static final String NO_HOSTNAME_FOUND = "<NO_HOSTNAME_FOUND>";
+
private static final LoadingCache<X509Certificate, String> hostnameCache =
Caffeine.newBuilder()
.weakKeys()
@@ -73,11 +75,11 @@ public final class CertificateUtil {

logger.warn("No common name or subject alternative name found " +
"in certificate: {}", cert);
- return null;
+ return NO_HOSTNAME_FOUND;
} catch (Exception e) {
logger.warn("Failed to get the common name or subject alternative name name " +
"from a certificate: {}", cert, e);
- return null;
+ return NO_HOSTNAME_FOUND;
}
});

@@ -136,7 +138,8 @@ public final class CertificateUtil {
if (!(certificate instanceof X509Certificate)) {
return null;
}
- return hostnameCache.get((X509Certificate) certificate);
+ final String hostname = hostnameCache.get((X509Certificate) certificate);
+ return NO_HOSTNAME_FOUND.equals(hostname) ? null : hostname;
}

public static List<X509Certificate> toX509Certificates(File file) throws CertificateException {
diff --git a/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java b/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
index 8766acd95..b6b8a1b62 100644
--- a/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
+++ b/core/src/main/java/com/linecorp/armeria/server/file/FileServiceConfig.java
@@ -72,7 +72,7 @@ public final class FileServiceConfig {
return null;
}
try {
- CaffeineSpec.parse(entryCacheSpec);
+ var unused = CaffeineSpec.parse(entryCacheSpec);
} catch (Exception e) {
throw new IllegalArgumentException("invalid cache spec: " + entryCacheSpec, e);
}
diff --git a/dependencies.toml b/dependencies.toml
index 22c366f47..bfd54bcce 100644
--- a/dependencies.toml
+++ b/dependencies.toml
@@ -15,8 +15,7 @@ brave6 = "6.3.0"
brotli4j = "1.18.0"
# Don"t upgrade bucket4j to 7.6.1 or 8.x that requires Java 11. The module name also has been changed to "com.bucket4j"
bucket4j = "7.6.0"
-# Don"t upgrade Caffeine to 3.x that requires Java 11.
-caffeine = "2.9.3"
+caffeine = "3.2.2"
cglib = "3.3.0"
checkerframework = "2.5.6"
checkstyle = "10.3.2"
@@ -325,7 +324,7 @@ javadocs = "https://javadoc.io/doc/com.github.vladimir-bukhtoyarov/bucket4j-core
module = "com.github.ben-manes.caffeine:caffeine"
version.ref = "caffeine"
exclusions = "com.google.errorprone:error_prone_annotations"
-javadocs = "https://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/2.9.3/"
+javadocs = "https://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine/3.2.2/"
relocations = { from = "com.github.benmanes.caffeine", to = "com.linecorp.armeria.internal.shaded.caffeine" }

[libraries.cglib]
diff --git a/gradle.properties b/gradle.properties
index de5b05013..5ab06b436 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -12,8 +12,8 @@ licenseUrl=https://www.apache.org/license/LICENSE-2.0.txt
scmUrl=https://github.com/line/armeria
scmConnection=scm:git:https://github.com/line/armeria.git
scmDeveloperConnection=scm:git:ssh://git@github.com/line/armeria.git
-javaSourceCompatibility=1.8
-javaTargetCompatibility=1.8
+javaSourceCompatibility=11
+javaTargetCompatibility=11
publishUrlForRelease=https://ossrh-staging-api.central.sonatype.com/service/local/staging/deploy/maven2/
publishUrlForSnapshot=https://central.sonatype.com/repository/maven-snapshots/
publishUsernameProperty=ossrhUsername
--
2.51.0.windows.1

27 changes: 27 additions & 0 deletions .github/unsafe/build-custom-armeria.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash
set -e

VERSION="1.33.3"
CURR_DIR="$(pwd)"

cd "$(mktemp -d)"

# Clone Armeria repository
git clone --depth 1 --branch "armeria-${VERSION}" https://github.com/line/armeria.git

cd armeria

# Apply patch to remove Unsafe usage
git apply "${CURR_DIR}/.github/unsafe/armeria-remove-JCTools.patch"
git apply "${CURR_DIR}/.github/unsafe/armeria-update-Caffeine.patch"

# Build the core module (shaded JAR includes all dependencies)
./gradlew :core:shadedJar -x javadoc -x :docs-client:nodeSetup -x :docs-client:npmSetup -x :docs-client:npmInstall -x :docs-client:eslint -x :docs-client:lint -x :docs-client:buildWeb -x :docs-client:copyWeb

# Download the original POM file
curl -sL -o "armeria-${VERSION}.pom" "https://repo1.maven.org/maven2/com/linecorp/armeria/armeria/${VERSION}/armeria-${VERSION}.pom"

# Install core JAR to Maven local repository with POM
mvn install:install-file -q \
-Dfile="core/build/libs/armeria-untrimmed-${VERSION}.jar" \
-DpomFile="armeria-${VERSION}.pom"
35 changes: 35 additions & 0 deletions .github/unsafe/build-custom-protobuf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash
set -e

VERSION="4.32.1"

cd "$(mktemp -d)"

# Download original artifact and extract
curl -sL -o "protobuf-java-${VERSION}.jar" "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/${VERSION}/protobuf-java-${VERSION}.jar"

# Extract JAR
mkdir classes
cd classes
jar -xf "../protobuf-java-${VERSION}.jar"
cd ..

# Clone protobuf repository
git clone --depth 1 --branch "v32.1" https://github.com/protocolbuffers/protobuf.git

# Apply patch to remove Unsafe usage
sed -i 's/private static final sun\.misc\.Unsafe UNSAFE = getUnsafe();/private static final sun.misc.Unsafe UNSAFE = null;/' protobuf/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

# Compile modified classes
javac -cp protobuf-java-${VERSION}.jar -d classes protobuf/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java

# Create new JAR with modified classes
jar -cf "protobuf-java-${VERSION}.jar" -C classes .

# Download the original POM file
curl -sL -o "protobuf-java-${VERSION}.pom" "https://repo1.maven.org/maven2/com/google/protobuf/protobuf-java/${VERSION}/protobuf-java-${VERSION}.pom"

# Install to Maven local repository with POM
mvn install:install-file -q \
-Dfile="protobuf-java-${VERSION}.jar" \
-DpomFile="protobuf-java-${VERSION}.pom"
10 changes: 10 additions & 0 deletions .github/unsafe/prioritize-maven-local.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e

# Move mavenLocal() before mavenCentral() in the repositories block
sed -i '/repositories {/,/}/ {
/mavenCentral()/d
/mavenLocal()/d
/repositories {/a\ mavenLocal()
/repositories {/a\ mavenCentral()
}' "settings.gradle.kts"
30 changes: 30 additions & 0 deletions .github/unsafe/update-lmax-disruptor.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/bash
set -e

# Add Java 11 compile target and disruptor version update to opencensus-shim build file
cat >> opencensus-shim/build.gradle.kts << 'EOF'

tasks.withType<JavaCompile>().configureEach {
options.release.set(11)
}

configurations.all {
resolutionStrategy.force("com.lmax:disruptor:4.0.0")
}
EOF

# Add targeted disruptor fix to exporters/otlp/all for JdkHttpSender tests
if ! grep -q "resolutionStrategy.force.*disruptor.*4.0.0" exporters/otlp/all/build.gradle.kts; then
# Replace the existing afterEvaluate block with the complete version
sed -i '/afterEvaluate {/,/^}$/c\
afterEvaluate {\
tasks.named<JavaCompile>("compileTestJdkHttpSenderJava") {\
options.release.set(11)\
}\
\
// Force disruptor 4.0.0 for JdkHttpSender tests to prevent conflicts with mockserver\
configurations.named("testJdkHttpSenderRuntimeClasspath") {\
resolutionStrategy.force("com.lmax:disruptor:4.0.0")\
}\
}' exporters/otlp/all/build.gradle.kts
fi
60 changes: 60 additions & 0 deletions .github/workflows/unsafe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Unsafe disabled test

on:
push:
branches:
- main
- release/*
pull_request:
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true

permissions:
contents: read

jobs:
unsafe-disabled-test:
name: Unsafe disabled test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- id: setup-java-test
name: Set up Java 24 for tests
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: temurin
java-version: 24

- id: setup-java
name: Set up Java for build
uses: actions/setup-java@dded0888837ed1f317902acf8a20df0ad188d165 # v5.0.0
with:
distribution: temurin
java-version: 17

- name: Set up gradle
uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4.4.3

- name: Build custom protobuf-java that doesn't require Unsafe
run: ./.github/unsafe/build-custom-protobuf.sh

- name: Build custom armeria that doesn't require Unsafe
run: ./.github/unsafe/build-custom-armeria.sh

- name: Prioritize Maven local repository to pick up custom builds
run: ./.github/unsafe/prioritize-maven-local.sh

- name: Update to LMAX Disruptor version that doesn't require Unsafe
run: ./.github/unsafe/update-lmax-disruptor.sh

- name: Build and test
run: >
./gradlew build
-PdisableUnsafe=true
-PtestJavaVersion=24
"-Porg.gradle.java.installations.paths=${{ steps.setup-java-test.outputs.path }}"
"-Porg.gradle.java.installations.auto-download=false"
5 changes: 5 additions & 0 deletions buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ dependencyCheck {
}

val testJavaVersion = gradle.startParameter.projectProperties.get("testJavaVersion")?.let(JavaVersion::toVersion)
val disableUnsafe = gradle.startParameter.projectProperties.get("disableUnsafe")?.toBoolean() ?: false

tasks {
withType<JavaCompile>().configureEach {
Expand Down Expand Up @@ -114,6 +115,10 @@ tasks {
)
}

if (disableUnsafe) {
jvmArgs("--sun-misc-unsafe-memory-access=deny")
}

val defaultMaxRetries = if (System.getenv().containsKey("CI")) 2 else 0
val maxTestRetries = gradle.startParameter.projectProperties["maxTestRetries"]?.toInt() ?: defaultMaxRetries

Expand Down
Loading
Loading